From b77b8f6b7538130674b87eaf07fe565e25182844 Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 30 Jan 2025 17:11:51 +0100 Subject: [PATCH 1/4] Register action --- .../actions/eth-send-raw-transaction.ts | 20 +++++++++++++++++++ packages/api-evm/source/actions/index.ts | 1 + packages/api-evm/source/service-provider.ts | 2 ++ 3 files changed, 23 insertions(+) create mode 100644 packages/api-evm/source/actions/eth-send-raw-transaction.ts diff --git a/packages/api-evm/source/actions/eth-send-raw-transaction.ts b/packages/api-evm/source/actions/eth-send-raw-transaction.ts new file mode 100644 index 000000000..38684a0a8 --- /dev/null +++ b/packages/api-evm/source/actions/eth-send-raw-transaction.ts @@ -0,0 +1,20 @@ +import { inject, injectable } from "@mainsail/container"; +import { Contracts, Identifiers } from "@mainsail/contracts"; + +@injectable() +export class EthSendRawTransactionAction implements Contracts.Api.RPC.Action { + @inject(Identifiers.State.Store) + private readonly stateStore!: Contracts.State.Store; + + public readonly name: string = "eth_sendRawTransaction"; + + public readonly schema = { + $id: `jsonRpc_${this.name}`, + maxItems: 0, + type: "array", + }; + + public async handle(parameters: []): Promise { + return `0x${this.stateStore.getHeight().toString(16)}`; + } +} diff --git a/packages/api-evm/source/actions/index.ts b/packages/api-evm/source/actions/index.ts index bb025668f..d0852a6e9 100644 --- a/packages/api-evm/source/actions/index.ts +++ b/packages/api-evm/source/actions/index.ts @@ -18,6 +18,7 @@ export * from "./eth-get-uncle-by-block-hash-and-index.js"; export * from "./eth-get-uncle-by-block-number-and-index.js"; export * from "./eth-get-uncle-count-by-block-hash.js"; export * from "./eth-get-uncle-count-by-block-number.js"; +export * from "./eth-send-raw-transaction.js"; export * from "./net-listening.js"; export * from "./net-peer-count.js"; export * from "./net-version.js"; diff --git a/packages/api-evm/source/service-provider.ts b/packages/api-evm/source/service-provider.ts index 85c6eaee5..5e9706962 100644 --- a/packages/api-evm/source/service-provider.ts +++ b/packages/api-evm/source/service-provider.ts @@ -23,6 +23,7 @@ import { EthGetUncleByBlockNumberAndIndex, EthGetUncleCountByBlockHash, EthGetUncleCountByBlockNumber, + EthSendRawTransactionAction, NetListeningAction, NetPeerCountAction, NetVersion, @@ -97,6 +98,7 @@ export class ServiceProvider extends AbstractServiceProvider { this.app.resolve(EthGetUncleByBlockNumberAndIndex), this.app.resolve(EthGetUncleCountByBlockHash), this.app.resolve(EthGetUncleCountByBlockNumber), + this.app.resolve(EthSendRawTransactionAction), this.app.resolve(NetListeningAction), this.app.resolve(NetPeerCountAction), this.app.resolve(NetVersion), From 88a767768a7faf7f888e3b2e9f15bbd11e3f51be Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 30 Jan 2025 17:16:25 +0100 Subject: [PATCH 2/4] Fix schema --- packages/api-evm/source/actions/eth-send-raw-transaction.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/api-evm/source/actions/eth-send-raw-transaction.ts b/packages/api-evm/source/actions/eth-send-raw-transaction.ts index 38684a0a8..18122fce0 100644 --- a/packages/api-evm/source/actions/eth-send-raw-transaction.ts +++ b/packages/api-evm/source/actions/eth-send-raw-transaction.ts @@ -10,7 +10,10 @@ export class EthSendRawTransactionAction implements Contracts.Api.RPC.Action { public readonly schema = { $id: `jsonRpc_${this.name}`, - maxItems: 0, + maxItems: 1, + minItems: 1, + + prefixItems: [{ $ref: "prefixedHex" }], type: "array", }; From b84a6fb6236bece96a6d4a056bfd1e12847b7bbc Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 30 Jan 2025 18:17:21 +0100 Subject: [PATCH 3/4] Implement action --- packages/api-evm/package.json | 1 + .../actions/eth-send-raw-transaction.ts | 25 +++++++++++++++---- pnpm-lock.yaml | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/packages/api-evm/package.json b/packages/api-evm/package.json index 0c3955fd8..6c7c6b91d 100644 --- a/packages/api-evm/package.json +++ b/packages/api-evm/package.json @@ -28,6 +28,7 @@ "@mainsail/container": "workspace:*", "@mainsail/contracts": "workspace:*", "@mainsail/kernel": "workspace:*", + "@mainsail/utils": "workspace:*", "dayjs": "1.11.10", "ethers": "6.11.0", "joi": "17.12.2" diff --git a/packages/api-evm/source/actions/eth-send-raw-transaction.ts b/packages/api-evm/source/actions/eth-send-raw-transaction.ts index 18122fce0..0909e3aee 100644 --- a/packages/api-evm/source/actions/eth-send-raw-transaction.ts +++ b/packages/api-evm/source/actions/eth-send-raw-transaction.ts @@ -1,10 +1,11 @@ import { inject, injectable } from "@mainsail/container"; -import { Contracts, Identifiers } from "@mainsail/contracts"; +import { Contracts, Exceptions, Identifiers } from "@mainsail/contracts"; +import { http } from "@mainsail/utils"; @injectable() export class EthSendRawTransactionAction implements Contracts.Api.RPC.Action { - @inject(Identifiers.State.Store) - private readonly stateStore!: Contracts.State.Store; + @inject(Identifiers.Cryptography.Transaction.Factory) + private readonly transactionFactory!: Contracts.Crypto.TransactionFactory; public readonly name: string = "eth_sendRawTransaction"; @@ -17,7 +18,21 @@ export class EthSendRawTransactionAction implements Contracts.Api.RPC.Action { type: "array", }; - public async handle(parameters: []): Promise { - return `0x${this.stateStore.getHeight().toString(16)}`; + public async handle(parameters: [string]): Promise { + const response = await http.post("http://localhost:4007/api/transactions", { + body: { transactions: [parameters[0].slice(2)] }, + }); + + if (response.statusCode === 200) { + if (response.data.data.accept.length > 0) { + const tx = await this.transactionFactory.fromHex(parameters[0].slice(2)); + return `0x${tx.id}`; + } else { + throw new Exceptions.RpcError(response.data.errors[0].message); + } + } + + // TODO Improve error handling + throw new Exceptions.RpcError("Error sending transaction"); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 67b7693be..5a7fe4bbf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -324,6 +324,9 @@ importers: '@mainsail/kernel': specifier: workspace:* version: link:../kernel + '@mainsail/utils': + specifier: workspace:* + version: link:../utils dayjs: specifier: 1.11.10 version: 1.11.10 From 4686dd51771ddf7087485815ff3ad9bb32d8753c Mon Sep 17 00:00:00 2001 From: sebastijankuzner Date: Thu, 30 Jan 2025 18:40:35 +0100 Subject: [PATCH 4/4] Create url --- .../actions/eth-send-raw-transaction.ts | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/api-evm/source/actions/eth-send-raw-transaction.ts b/packages/api-evm/source/actions/eth-send-raw-transaction.ts index 0909e3aee..412465199 100644 --- a/packages/api-evm/source/actions/eth-send-raw-transaction.ts +++ b/packages/api-evm/source/actions/eth-send-raw-transaction.ts @@ -1,5 +1,6 @@ import { inject, injectable } from "@mainsail/container"; -import { Contracts, Exceptions, Identifiers } from "@mainsail/contracts"; +import { Constants, Contracts, Exceptions, Identifiers } from "@mainsail/contracts"; +import { Environment } from "@mainsail/kernel"; import { http } from "@mainsail/utils"; @injectable() @@ -19,7 +20,7 @@ export class EthSendRawTransactionAction implements Contracts.Api.RPC.Action { }; public async handle(parameters: [string]): Promise { - const response = await http.post("http://localhost:4007/api/transactions", { + const response = await http.post(this.#getUrl(), { body: { transactions: [parameters[0].slice(2)] }, }); @@ -35,4 +36,29 @@ export class EthSendRawTransactionAction implements Contracts.Api.RPC.Action { // TODO Improve error handling throw new Exceptions.RpcError("Error sending transaction"); } + + #getUrl(): string { + const config = { + http: { + enabled: !Environment.isTrue(Constants.EnvironmentVariables.CORE_API_TRANSACTION_POOL_DISABLED), + host: Environment.get(Constants.EnvironmentVariables.CORE_API_TRANSACTION_POOL_HOST, "0.0.0.0"), + port: Environment.get(Constants.EnvironmentVariables.CORE_API_TRANSACTION_POOL_PORT, 4007), + }, + https: { + enabled: Environment.isTrue(Constants.EnvironmentVariables.CORE_API_TRANSACTION_POOL_SSL), + host: Environment.get(Constants.EnvironmentVariables.CORE_API_TRANSACTION_POOL_SSL_HOST, "0.0.0.0"), + port: Environment.get(Constants.EnvironmentVariables.CORE_API_TRANSACTION_POOL_SSL_PORT, 8447), + }, + }; + + if (config.http.enabled) { + return `http://${config.http.host}:${config.http.port}/api/transactions`; + } + + if (config.https.enabled) { + return `https://${config.https.host}:${config.https.port}/api/transactions`; + } + + throw new Error("Server is not enabled"); + } }