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 new file mode 100644 index 000000000..412465199 --- /dev/null +++ b/packages/api-evm/source/actions/eth-send-raw-transaction.ts @@ -0,0 +1,64 @@ +import { inject, injectable } from "@mainsail/container"; +import { Constants, Contracts, Exceptions, Identifiers } from "@mainsail/contracts"; +import { Environment } from "@mainsail/kernel"; +import { http } from "@mainsail/utils"; + +@injectable() +export class EthSendRawTransactionAction implements Contracts.Api.RPC.Action { + @inject(Identifiers.Cryptography.Transaction.Factory) + private readonly transactionFactory!: Contracts.Crypto.TransactionFactory; + + public readonly name: string = "eth_sendRawTransaction"; + + public readonly schema = { + $id: `jsonRpc_${this.name}`, + maxItems: 1, + minItems: 1, + + prefixItems: [{ $ref: "prefixedHex" }], + type: "array", + }; + + public async handle(parameters: [string]): Promise { + const response = await http.post(this.#getUrl(), { + 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"); + } + + #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"); + } +} 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), 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