Skip to content

Commit 3b7b31b

Browse files
authored
Merge pull request #2620 from hongwei1/develop
feature/OBPv6.0.0 added ETH payments endpoints ETH_SEND_RAW_TRANSACTION and ETH_SEND_TRANSACTION
2 parents 4a5e652 + 4b3bd24 commit 3b7b31b

File tree

21 files changed

+969
-20
lines changed

21 files changed

+969
-20
lines changed

build.sbt

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
ThisBuild / version := "1.10.1"
2+
ThisBuild / scalaVersion := "2.12.20"
3+
ThisBuild / organization := "com.tesobe"
4+
5+
// Java version compatibility
6+
ThisBuild / javacOptions ++= Seq("-source", "11", "-target", "11")
7+
ThisBuild / scalacOptions ++= Seq(
8+
"-unchecked",
9+
"-explaintypes",
10+
"-target:jvm-1.8",
11+
"-Yrangepos"
12+
)
13+
14+
// Enable SemanticDB for Metals
15+
ThisBuild / semanticdbEnabled := true
16+
ThisBuild / semanticdbVersion := "4.13.9"
17+
18+
// Fix dependency conflicts
19+
ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always
20+
21+
lazy val liftVersion = "3.5.0"
22+
lazy val akkaVersion = "2.5.32"
23+
lazy val jettyVersion = "9.4.50.v20221201"
24+
lazy val avroVersion = "1.8.2"
25+
26+
lazy val commonSettings = Seq(
27+
resolvers ++= Seq(
28+
"Sonatype OSS Releases" at "https://oss.sonatype.org/content/repositories/releases",
29+
"Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots",
30+
"Artima Maven Repository" at "https://repo.artima.com/releases",
31+
"OpenBankProject M2 Repository" at "https://raw.githubusercontent.com/OpenBankProject/OBP-M2-REPO/master",
32+
"jitpack.io" at "https://jitpack.io"
33+
)
34+
)
35+
36+
lazy val obpCommons = (project in file("obp-commons"))
37+
.settings(
38+
commonSettings,
39+
name := "obp-commons",
40+
libraryDependencies ++= Seq(
41+
"net.liftweb" %% "lift-common" % liftVersion,
42+
"net.liftweb" %% "lift-util" % liftVersion,
43+
"net.liftweb" %% "lift-mapper" % liftVersion,
44+
"org.scala-lang" % "scala-reflect" % "2.12.20",
45+
"org.scalatest" %% "scalatest" % "3.2.15" % Test,
46+
"org.scalactic" %% "scalactic" % "3.2.15",
47+
"net.liftweb" %% "lift-json" % liftVersion,
48+
"com.alibaba" % "transmittable-thread-local" % "2.11.5",
49+
"org.apache.commons" % "commons-lang3" % "3.12.0",
50+
"org.apache.commons" % "commons-text" % "1.10.0",
51+
"com.google.guava" % "guava" % "32.0.0-jre"
52+
)
53+
)
54+
55+
lazy val obpApi = (project in file("obp-api"))
56+
.dependsOn(obpCommons)
57+
.settings(
58+
commonSettings,
59+
name := "obp-api",
60+
libraryDependencies ++= Seq(
61+
// Core dependencies
62+
"net.liftweb" %% "lift-mapper" % liftVersion,
63+
"net.databinder.dispatch" %% "dispatch-lift-json" % "0.13.1",
64+
"ch.qos.logback" % "logback-classic" % "1.2.13",
65+
"org.slf4j" % "log4j-over-slf4j" % "1.7.26",
66+
"org.slf4j" % "slf4j-ext" % "1.7.26",
67+
68+
// Security
69+
"org.bouncycastle" % "bcpg-jdk15on" % "1.70",
70+
"org.bouncycastle" % "bcpkix-jdk15on" % "1.70",
71+
"com.nimbusds" % "nimbus-jose-jwt" % "9.37.2",
72+
"com.nimbusds" % "oauth2-oidc-sdk" % "9.27",
73+
74+
// Commons
75+
"org.apache.commons" % "commons-lang3" % "3.12.0",
76+
"org.apache.commons" % "commons-text" % "1.10.0",
77+
"org.apache.commons" % "commons-email" % "1.5",
78+
"org.apache.commons" % "commons-compress" % "1.26.0",
79+
"org.apache.commons" % "commons-pool2" % "2.11.1",
80+
81+
// Database
82+
"org.postgresql" % "postgresql" % "42.4.4",
83+
"com.h2database" % "h2" % "2.2.220" % Runtime,
84+
"mysql" % "mysql-connector-java" % "8.0.30",
85+
"com.microsoft.sqlserver" % "mssql-jdbc" % "11.2.0.jre11",
86+
87+
// Web
88+
"javax.servlet" % "javax.servlet-api" % "3.1.0" % Provided,
89+
"org.eclipse.jetty" % "jetty-server" % jettyVersion % Test,
90+
"org.eclipse.jetty" % "jetty-webapp" % jettyVersion % Test,
91+
"org.eclipse.jetty" % "jetty-util" % jettyVersion,
92+
93+
// Akka
94+
"com.typesafe.akka" %% "akka-actor" % akkaVersion,
95+
"com.typesafe.akka" %% "akka-remote" % akkaVersion,
96+
"com.typesafe.akka" %% "akka-slf4j" % akkaVersion,
97+
"com.typesafe.akka" %% "akka-http-core" % "10.1.6",
98+
99+
// Avro
100+
"com.sksamuel.avro4s" %% "avro4s-core" % avroVersion,
101+
102+
// Twitter
103+
"com.twitter" %% "chill-akka" % "0.9.1",
104+
"com.twitter" %% "chill-bijection" % "0.9.1",
105+
106+
// Cache
107+
"com.github.cb372" %% "scalacache-redis" % "0.9.3",
108+
"com.github.cb372" %% "scalacache-guava" % "0.9.3",
109+
110+
// Utilities
111+
"com.github.dwickern" %% "scala-nameof" % "1.0.3",
112+
"org.javassist" % "javassist" % "3.25.0-GA",
113+
"com.alibaba" % "transmittable-thread-local" % "2.14.2",
114+
"org.clapper" %% "classutil" % "1.4.0",
115+
"com.github.grumlimited" % "geocalc" % "0.5.7",
116+
"com.github.OpenBankProject" % "scala-macros" % "v1.0.0-alpha.3",
117+
"org.scalameta" %% "scalameta" % "3.7.4",
118+
119+
// Akka Adapter - exclude transitive dependency on obp-commons to use local module
120+
"com.github.OpenBankProject.OBP-Adapter-Akka-SpringBoot" % "adapter-akka-commons" % "v1.1.0" exclude("com.github.OpenBankProject.OBP-API", "obp-commons"),
121+
122+
// JSON Schema
123+
"com.github.everit-org.json-schema" % "org.everit.json.schema" % "1.6.1",
124+
"com.networknt" % "json-schema-validator" % "1.0.87",
125+
126+
// Swagger
127+
"io.swagger.parser.v3" % "swagger-parser" % "2.0.13",
128+
129+
// Text processing
130+
"org.atteo" % "evo-inflector" % "1.2.2",
131+
132+
// Payment
133+
"com.stripe" % "stripe-java" % "12.1.0",
134+
"com.twilio.sdk" % "twilio" % "9.2.0",
135+
136+
// gRPC
137+
"com.thesamet.scalapb" %% "scalapb-runtime-grpc" % "0.8.4",
138+
"io.grpc" % "grpc-all" % "1.48.1",
139+
"io.netty" % "netty-tcnative-boringssl-static" % "2.0.27.Final",
140+
"org.asynchttpclient" % "async-http-client" % "2.10.4",
141+
142+
// Database utilities
143+
"org.scalikejdbc" %% "scalikejdbc" % "3.4.0",
144+
145+
// XML
146+
"org.scala-lang.modules" %% "scala-xml" % "1.2.0",
147+
148+
// IBAN
149+
"org.iban4j" % "iban4j" % "3.2.7-RELEASE",
150+
151+
// JavaScript
152+
"org.graalvm.js" % "js" % "22.0.0.2",
153+
"org.graalvm.js" % "js-scriptengine" % "22.0.0.2",
154+
"ch.obermuhlner" % "java-scriptengine" % "2.0.0",
155+
156+
// Hydra
157+
"sh.ory.hydra" % "hydra-client" % "1.7.0",
158+
159+
// HTTP
160+
"com.squareup.okhttp3" % "okhttp" % "4.12.0",
161+
"com.squareup.okhttp3" % "logging-interceptor" % "4.12.0",
162+
"org.apache.httpcomponents" % "httpclient" % "4.5.13",
163+
164+
// RabbitMQ
165+
"com.rabbitmq" % "amqp-client" % "5.22.0",
166+
"net.liftmodules" %% "amqp_3.1" % "1.5.0",
167+
168+
// Elasticsearch
169+
"org.elasticsearch" % "elasticsearch" % "8.14.0",
170+
"com.sksamuel.elastic4s" %% "elastic4s-client-esjava" % "8.5.2",
171+
172+
// OAuth
173+
"oauth.signpost" % "signpost-commonshttp4" % "1.2.1.2",
174+
175+
// Utilities
176+
"cglib" % "cglib" % "3.3.0",
177+
"com.sun.activation" % "jakarta.activation" % "1.2.2",
178+
"com.nulab-inc" % "zxcvbn" % "1.9.0",
179+
180+
// Testing - temporarily disabled due to version incompatibility
181+
// "org.scalatest" %% "scalatest" % "2.2.6" % Test,
182+
183+
// Jackson
184+
"com.fasterxml.jackson.core" % "jackson-databind" % "2.12.7.1",
185+
186+
// Flexmark (markdown processing)
187+
"com.vladsch.flexmark" % "flexmark-profile-pegdown" % "0.40.8",
188+
"com.vladsch.flexmark" % "flexmark-util-options" % "0.64.0",
189+
190+
// Connection pool
191+
"com.zaxxer" % "HikariCP" % "4.0.3",
192+
193+
// Test dependencies
194+
"junit" % "junit" % "4.13.2" % Test,
195+
"org.scalatest" %% "scalatest" % "3.2.15" % Test,
196+
"org.seleniumhq.selenium" % "htmlunit-driver" % "2.36.0" % Test,
197+
"org.testcontainers" % "rabbitmq" % "1.20.3" % Test
198+
)
199+
)

obp-api/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@
329329
<artifactId>flexmark-util-options</artifactId>
330330
<version>0.64.0</version>
331331
</dependency>
332+
<!-- https://mvnrepository.com/artifact/org.web3j/core -->
333+
<dependency>
334+
<groupId>org.web3j</groupId>
335+
<artifactId>core</artifactId>
336+
<version>4.9.8</version>
337+
</dependency>
332338
<dependency>
333339
<groupId>com.zaxxer</groupId>
334340
<artifactId>HikariCP</artifactId>

obp-api/src/main/resources/props/sample.props.template

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,6 +1517,18 @@ regulated_entities = []
15171517
# super_admin_email=tom@tesobe.com
15181518

15191519

1520+
## Ethereum Connector Configuration
1521+
## ================================
1522+
## The Ethereum connector uses JSON-RPC to communicate with Ethereum nodes.
1523+
## It supports two transaction modes:
1524+
## 1) eth_sendRawTransaction - for pre-signed transactions (recommended for production)
1525+
## 2) eth_sendTransaction - for unlocked accounts (development/test environments)
1526+
##
1527+
## Ethereum RPC endpoint URL
1528+
## Default: http://127.0.0.1:8545 (local Ethereum node)
1529+
ethereum.rpc.url=http://127.0.0.1:8545
1530+
1531+
15201532
# Note: For secure and http only settings for cookies see resources/web.xml which is mentioned in the README.md
15211533

15221534

obp-api/src/main/scala/code/api/ResourceDocs1_4_0/SwaggerDefinitionsJSON.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import com.openbankproject.commons.model._
2929
import com.openbankproject.commons.model.enums.TransactionRequestTypes._
3030
import com.openbankproject.commons.model.enums.{AttributeCategory, CardAttributeType, ChallengeType, TransactionRequestStatus}
3131
import com.openbankproject.commons.util.{ApiVersion, FieldNameApiVersions, ReflectUtils}
32-
import net.liftweb.common.Full
3332
import net.liftweb.json
3433

3534
import java.net.URLEncoder
@@ -5759,6 +5758,16 @@ object SwaggerDefinitionsJSON {
57595758
description = descriptionExample.value,
57605759
metadata = Some(Map("202507022319" -> cardanoMetadataStringJsonV600))
57615760
)
5761+
5762+
lazy val transactionRequestBodyEthereumJsonV600 = TransactionRequestBodyEthereumJsonV600(
5763+
to = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
5764+
value = AmountOfMoneyJsonV121("ETH", "0.01"),
5765+
description = descriptionExample.value
5766+
)
5767+
lazy val transactionRequestBodyEthSendRawTransactionJsonV600 = TransactionRequestBodyEthSendRawTransactionJsonV600(
5768+
params = "0xf86b018203e882520894627306090abab3a6e1400e9345bc60c78a8bef57880de0b6b3a764000080820ff6a0d0367709eee090a6ebd74c63db7329372db1966e76d28ce219d1e105c47bcba7a0042d52f7d2436ad96e8714bf0309adaf870ad6fb68cfe53ce958792b3da36c12",
5769+
description = descriptionExample.value
5770+
)
57625771

57635772
//The common error or success format.
57645773
//Just some helper format to use in Json

obp-api/src/main/scala/code/api/util/ErrorMessages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ object ErrorMessages {
7979
// General messages (OBP-10XXX)
8080
val InvalidJsonFormat = "OBP-10001: Incorrect json format."
8181
val InvalidNumber = "OBP-10002: Invalid Number. Could not convert value to a number."
82-
val InvalidISOCurrencyCode = """OBP-10003: Invalid Currency Value. Expected a 3-letter ISO Currency Code (e.g., 'USD', 'EUR') or 'lovelace' for Cardano transactions.""".stripMargin
82+
val InvalidISOCurrencyCode = """OBP-10003: Invalid Currency Value. Expected a 3-letter ISO Currency Code (e.g., 'USD', 'EUR'), 'lovelace' (Cardano), or 'ETH' (Ethereum). Refer to ISO 4217 currency codes: https://www.iso.org/iso-4217-currency-codes.html""".stripMargin
8383
val FXCurrencyCodeCombinationsNotSupported = "OBP-10004: ISO Currency code combination not supported for FX. Please modify the FROM_CURRENCY_CODE or TO_CURRENCY_CODE. "
8484
val InvalidDateFormat = "OBP-10005: Invalid Date Format. Could not convert value to a Date."
8585
val InvalidCurrency = "OBP-10006: Invalid Currency Value."

obp-api/src/main/scala/code/api/util/NewStyle.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,8 @@ object NewStyle extends MdcLoggable{
802802
Failure(s"$failMsg. Details: ${e.getMessage}", Full(e), Empty)
803803
}
804804
} map {
805-
x => unboxFullOrFail(x, callContext, failMsg, failCode)
805+
x =>
806+
unboxFullOrFail(x, callContext, failMsg, failCode)
806807
}
807808
}
808809

obp-api/src/main/scala/code/api/v6_0_0/APIMethods600.scala

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import code.bankconnectors.LocalMappedConnectorInternal._
1414
import code.entitlement.Entitlement
1515
import code.views.Views
1616
import com.github.dwickern.macros.NameOf.nameOf
17+
import com.openbankproject.commons.ExecutionContext.Implicits.global
1718
import com.openbankproject.commons.model._
1819
import com.openbankproject.commons.util.{ApiVersion, ScannedApiVersion}
1920
import net.liftweb.common.Full
2021
import net.liftweb.http.rest.RestHelper
21-
import com.openbankproject.commons.ExecutionContext.Implicits.global
2222

2323
import scala.collection.immutable.{List, Nil}
2424
import scala.collection.mutable.ArrayBuffer
@@ -160,6 +160,85 @@ trait APIMethods600 {
160160
val transactionRequestType = TransactionRequestType("CARDANO")
161161
LocalMappedConnectorInternal.createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
162162
}
163+
164+
staticResourceDocs += ResourceDoc(
165+
createTransactionRequestEthereumeSendTransaction,
166+
implementedInApiVersion,
167+
nameOf(createTransactionRequestEthereumeSendTransaction),
168+
"POST",
169+
"/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/ETH_SEND_TRANSACTION/transaction-requests",
170+
"Create Transaction Request (ETH_SEND_TRANSACTION)",
171+
s"""
172+
|
173+
|Send ETH via Ethereum JSON-RPC.
174+
|AccountId should hold the 0x address for now.
175+
|
176+
|${transactionRequestGeneralText}
177+
|
178+
""".stripMargin,
179+
transactionRequestBodyEthereumJsonV600,
180+
transactionRequestWithChargeJSON400,
181+
List(
182+
$UserNotLoggedIn,
183+
$BankNotFound,
184+
$BankAccountNotFound,
185+
InsufficientAuthorisationToCreateTransactionRequest,
186+
InvalidTransactionRequestType,
187+
InvalidJsonFormat,
188+
NotPositiveAmount,
189+
InvalidTransactionRequestCurrency,
190+
TransactionDisabled,
191+
UnknownError
192+
),
193+
List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
194+
)
195+
196+
lazy val createTransactionRequestEthereumeSendTransaction: OBPEndpoint = {
197+
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
198+
"ETH_SEND_TRANSACTION" :: "transaction-requests" :: Nil JsonPost json -> _ =>
199+
cc => implicit val ec = EndpointContext(Some(cc))
200+
val transactionRequestType = TransactionRequestType("ETH_SEND_TRANSACTION")
201+
LocalMappedConnectorInternal.createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
202+
}
203+
staticResourceDocs += ResourceDoc(
204+
createTransactionRequestEthSendRawTransaction,
205+
implementedInApiVersion,
206+
nameOf(createTransactionRequestEthSendRawTransaction),
207+
"POST",
208+
"/banks/BANK_ID/accounts/ACCOUNT_ID/owner/transaction-request-types/ETH_SEND_RAW_TRANSACTION/transaction-requests",
209+
"CREATE TRANSACTION REQUEST (ETH_SEND_RAW_TRANSACTION )",
210+
s"""
211+
|
212+
|Send ETH via Ethereum JSON-RPC.
213+
|AccountId should hold the 0x address for now.
214+
|
215+
|${transactionRequestGeneralText}
216+
|
217+
""".stripMargin,
218+
transactionRequestBodyEthSendRawTransactionJsonV600,
219+
transactionRequestWithChargeJSON400,
220+
List(
221+
$UserNotLoggedIn,
222+
$BankNotFound,
223+
$BankAccountNotFound,
224+
InsufficientAuthorisationToCreateTransactionRequest,
225+
InvalidTransactionRequestType,
226+
InvalidJsonFormat,
227+
NotPositiveAmount,
228+
InvalidTransactionRequestCurrency,
229+
TransactionDisabled,
230+
UnknownError
231+
),
232+
List(apiTagTransactionRequest, apiTagPSD2PIS, apiTagPsd2)
233+
)
234+
235+
lazy val createTransactionRequestEthSendRawTransaction: OBPEndpoint = {
236+
case "banks" :: BankId(bankId) :: "accounts" :: AccountId(accountId) :: ViewId(viewId) :: "transaction-request-types" ::
237+
"ETH_SEND_RAW_TRANSACTION" :: "transaction-requests" :: Nil JsonPost json -> _ =>
238+
cc => implicit val ec = EndpointContext(Some(cc))
239+
val transactionRequestType = TransactionRequestType("ETH_SEND_RAW_TRANSACTION")
240+
LocalMappedConnectorInternal.createTransactionRequest(bankId, accountId, viewId , transactionRequestType, json)
241+
}
163242

164243
}
165244
}

obp-api/src/main/scala/code/api/v6_0_0/JSONFactory6.0.0.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ case class TransactionRequestBodyCardanoJsonV600(
6565
metadata: Option[Map[String, CardanoMetadataStringJsonV600]] = None
6666
) extends TransactionRequestCommonBodyJSON
6767

68+
// ---------------- Ethereum models (V600) ----------------
69+
case class TransactionRequestBodyEthereumJsonV600(
70+
params: Option[String] = None,// This is for eth_sendRawTransaction
71+
to: String, // this is for eth_sendTransaction eg: 0x addressk
72+
value: AmountOfMoneyJsonV121, // currency should be "ETH"; amount string (decimal)
73+
description: String
74+
) extends TransactionRequestCommonBodyJSON
75+
76+
// This is only for the request JSON body; we will construct `TransactionRequestBodyEthereumJsonV600` for OBP.
77+
case class TransactionRequestBodyEthSendRawTransactionJsonV600(
78+
params: String, // eth_sendRawTransaction params field.
79+
description: String
80+
)
81+
6882
case class UserJsonV600(
6983
user_id: String,
7084
email : String,

0 commit comments

Comments
 (0)