From fbdc4de387f5e31ddfad700cac6906edabd10f0e Mon Sep 17 00:00:00 2001 From: Davit Mandzikyan Date: Mon, 15 Sep 2025 15:17:31 +0400 Subject: [PATCH 1/7] Fix new starknet solver. --- js/package-lock.json | 112 +++--- js/package.json | 2 +- .../Infrastructure/AddCoreServices.ts | 3 - ....ts => FuelSignTransactionRequestModel.ts} | 2 +- .../StarknetSignTransactionRequestModel.ts | 5 + .../TreasuryClient/Models/index.ts | 6 +- .../TreasuryClient/treasuryClient.ts | 5 +- .../Models/AllowanceRequest.ts | 1 - .../Models/FeesModels/EstimateFeeRequest.ts | 1 + .../HookedWalletEthTxSubprovider.ts | 50 --- .../WalletsModels/PrivateKeyProvider.ts | 44 --- .../WalletsModels/PrivateKeyRepository.ts | 52 --- .../Activities/FuelBlockchainActivities.ts | 7 +- .../Activities/Helper/FuelEventTracker.ts | 4 +- .../Activities/IFuelBlockchainActivities.ts | 4 +- .../Activities/Models/EventModels.ts | 22 ++ .../Models/FuelSignTransactionModel.ts | 6 +- .../Models/FuelTokenCommitedEvents.ts | 16 - .../Activities/Models/FuelTokenLockedEvent.ts | 6 - .../Workflows/FuelTransactionProcessor.ts | 48 +-- .../Activities/Helper/Client.ts | 25 ++ .../Activities/Helper/ErrorParser.ts | 4 +- .../Activities/Helper/StarknetEventTracker.ts | 8 +- .../Helper/StarknetTransactionBuilder.ts | 14 +- .../IStarknetBlockchainActivities.ts | 19 +- .../StarknetBlockchainActivities.ts | 366 +++++++++--------- .../Models/ComposeRawTxModels.ts | 12 + .../Models/EnsureSufficientBalanceModels.ts | 8 + ...tTokenCommittedEvent.ts => EventModels.ts} | 9 +- .../Models/SignTransactionRequest.ts | 7 + .../StarknetPublishTransactionRequest .ts | 9 - .../Models/StarknetTokenLockedEvent.ts | 6 - .../StarknetTransactioCalculationType.ts | 12 - .../Models/TransactionCalculationType.ts | 11 + .../Models/TransactionModels.ts | 9 + .../Worker/StarknetWorker.ts | 2 - .../Workflows/StarknetTransactionProcessor.ts | 61 ++- 37 files changed, 445 insertions(+), 533 deletions(-) rename js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/{FuelSignTransactionRequest.ts => FuelSignTransactionRequestModel.ts} (54%) create mode 100644 js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/StarknetSignTransactionRequestModel.ts delete mode 100644 js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/HookedWalletEthTxSubprovider.ts delete mode 100644 js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyProvider.ts delete mode 100644 js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyRepository.ts create mode 100644 js/src/Blockchain/Blockchain.Fuel/Activities/Models/EventModels.ts delete mode 100644 js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenCommitedEvents.ts delete mode 100644 js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenLockedEvent.ts create mode 100644 js/src/Blockchain/Blockchain.Starknet/Activities/Helper/Client.ts create mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/ComposeRawTxModels.ts create mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/EnsureSufficientBalanceModels.ts rename js/src/Blockchain/Blockchain.Starknet/Models/{StarknetTokenCommittedEvent.ts => EventModels.ts} (71%) create mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/SignTransactionRequest.ts delete mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/StarknetPublishTransactionRequest .ts delete mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/StarknetTokenLockedEvent.ts delete mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/StarknetTransactioCalculationType.ts create mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/TransactionCalculationType.ts create mode 100644 js/src/Blockchain/Blockchain.Starknet/Models/TransactionModels.ts diff --git a/js/package-lock.json b/js/package-lock.json index 4055d0b1..b84a1cf7 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -19,7 +19,7 @@ "pg": "^8.14.1", "redlock": "^5.0.0-beta.2", "reflect-metadata": "^0.2.2", - "starknet": "^6.23.1", + "starknet": "^7.1.0", "tsyringe": "^4.9.1", "web3-provider-engine": "^17.0.1" }, @@ -7157,40 +7157,6 @@ "bser": "2.1.1" } }, - "node_modules/fetch-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-3.0.1.tgz", - "integrity": "sha512-ZGXe8Y5Z/1FWqQ9q/CrJhkUD73DyBU9VF0hBQmEO/wPHe4A9PKTjplFDLeFX8aOsYypZUcX5Ji/eByn3VCVO3Q==", - "license": "Unlicense", - "dependencies": { - "set-cookie-parser": "^2.4.8", - "tough-cookie": "^4.0.0" - } - }, - "node_modules/fetch-cookie/node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "license": "BSD-3-Clause", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/fetch-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/fflate": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", @@ -8063,14 +8029,19 @@ "node": ">=16" } }, - "node_modules/isomorphic-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", - "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.1", - "whatwg-fetch": "^3.4.1" + "peerDependencies": { + "ws": "*" } }, "node_modules/isstream": { @@ -12356,12 +12327,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "license": "MIT" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -12643,22 +12608,23 @@ "license": "MIT" }, "node_modules/starknet": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/starknet/-/starknet-6.23.1.tgz", - "integrity": "sha512-vQV9luXpmwZZs9RVZaRwm2iD8T0PYx1AzgZeQsCvD89tR0HwUF0paty27ZzuJrdPe0CmAs/ipAYFCE55jbj0RQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/starknet/-/starknet-7.1.0.tgz", + "integrity": "sha512-7e5UCmRAng4hwYntNBYmsRo2ox+1ORh8GLO06uJnuW+SKPH6oBf+MSH+g/UntVb4tVUeQVeMrGLkLZ8h1Ghu2Q==", "license": "MIT", "dependencies": { "@noble/curves": "1.7.0", "@noble/hashes": "1.6.0", "@scure/base": "1.2.1", "@scure/starknet": "1.1.0", - "abi-wan-kanabi": "^2.2.3", - "fetch-cookie": "~3.0.0", - "isomorphic-fetch": "~3.0.0", + "abi-wan-kanabi": "2.2.4", + "isows": "^1.0.6", "lossless-json": "^4.0.1", "pako": "^2.0.4", - "starknet-types-07": "npm:@starknet-io/types-js@^0.7.10", - "ts-mixer": "^6.0.3" + "starknet-types-07": "npm:@starknet-io/types-js@~0.7.10", + "starknet-types-08": "npm:@starknet-io/types-js@~0.8.1", + "ts-mixer": "^6.0.3", + "ws": "^8.18.0" } }, "node_modules/starknet-types-07": { @@ -12668,6 +12634,13 @@ "integrity": "sha512-1VtCqX4AHWJlRRSYGSn+4X1mqolI1Tdq62IwzoU2vUuEE72S1OlEeGhpvd6XsdqXcfHmVzYfj8k1XtKBQqwo9w==", "license": "MIT" }, + "node_modules/starknet-types-08": { + "name": "@starknet-io/types-js", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@starknet-io/types-js/-/types-js-0.8.4.tgz", + "integrity": "sha512-0RZ3TZHcLsUTQaq1JhDSCM8chnzO4/XNsSCozwDET64JK5bjFDIf2ZUkta+tl5Nlbf4usoU7uZiDI/Q57kt2SQ==", + "license": "MIT" + }, "node_modules/starknet/node_modules/@noble/curves": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz", @@ -12704,6 +12677,27 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/starknet/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/std-env": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", @@ -13849,12 +13843,6 @@ "node": ">=10.13.0" } }, - "node_modules/whatwg-fetch": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", - "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", - "license": "MIT" - }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", diff --git a/js/package.json b/js/package.json index d915576d..074b5edb 100644 --- a/js/package.json +++ b/js/package.json @@ -21,7 +21,7 @@ "pg": "^8.14.1", "redlock": "^5.0.0-beta.2", "reflect-metadata": "^0.2.2", - "starknet": "^6.23.1", + "starknet": "^7.1.0", "tsyringe": "^4.9.1", "web3-provider-engine": "^17.0.1" }, diff --git a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/AddCoreServices.ts b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/AddCoreServices.ts index a569efad..3de7d604 100644 --- a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/AddCoreServices.ts +++ b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/AddCoreServices.ts @@ -3,7 +3,6 @@ import Redis from 'ioredis'; import Redlock from 'redlock'; import { container } from 'tsyringe'; import { ConvertToRedisUrl } from './RedisHelper/RedisFactory'; -import { TreasuryClient } from './TreasuryClient/treasuryClient'; export async function AddCoreServices(): Promise { @@ -14,9 +13,7 @@ export async function AddCoreServices(): Promise { retryDelay: 200, retryJitter: 100, }); - // const treasuryClient = new TreasuryClient(); container.register("Redlock", { useValue: redlock }); container.register("Redis", { useValue: redis }); - // container.register("TreasuryClient", { useValue: treasuryClient }); } \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/FuelSignTransactionRequest.ts b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/FuelSignTransactionRequestModel.ts similarity index 54% rename from js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/FuelSignTransactionRequest.ts rename to js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/FuelSignTransactionRequestModel.ts index cca3f062..2a8a5262 100644 --- a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/FuelSignTransactionRequest.ts +++ b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/FuelSignTransactionRequestModel.ts @@ -1,5 +1,5 @@ import { BaseSignTransactionRequestModel } from "./TreasurySignTransactionRequestModel"; -export interface FuelSignTransactionRequest extends BaseSignTransactionRequestModel { +export interface FuelSignTransactionRequestModel extends BaseSignTransactionRequestModel { nodeUrl: string; } \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/StarknetSignTransactionRequestModel.ts b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/StarknetSignTransactionRequestModel.ts new file mode 100644 index 00000000..4142e086 --- /dev/null +++ b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/StarknetSignTransactionRequestModel.ts @@ -0,0 +1,5 @@ +import { BaseSignTransactionRequestModel } from "./TreasurySignTransactionRequestModel"; + +export interface StarknetSignTransactionRequestModel extends BaseSignTransactionRequestModel { + signerInvocationDetails: string +} \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/index.ts b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/index.ts index 65edba61..ff363b0d 100644 --- a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/index.ts +++ b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/index.ts @@ -1,11 +1,13 @@ import { TreasuryGenerateAddressResponseModel } from './TreasuryGenerateAddressResponseModel'; import { TreasurySignTransactionResponseModel } from './TreasurySignTransactionResponseModel'; import { BaseSignTransactionRequestModel } from './TreasurySignTransactionRequestModel'; -import { FuelSignTransactionRequest } from './FuelSignTransactionRequest'; +import { FuelSignTransactionRequestModel } from './FuelSignTransactionRequestModel'; +import { StarknetSignTransactionRequestModel } from './StarknetSignTransactionRequestModel'; export { TreasuryGenerateAddressResponseModel, TreasurySignTransactionResponseModel, BaseSignTransactionRequestModel, - FuelSignTransactionRequest + FuelSignTransactionRequestModel, + StarknetSignTransactionRequestModel }; \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts index 8666080c..bcfa28f3 100644 --- a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts +++ b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts @@ -2,7 +2,8 @@ import { BaseSignTransactionRequestModel, TreasuryGenerateAddressResponseModel, TreasurySignTransactionResponseModel, - FuelSignTransactionRequest + FuelSignTransactionRequestModel, + StarknetSignTransactionRequestModel } from "./Models"; import axios from "axios"; @@ -19,7 +20,7 @@ export class TreasuryClient { async signTransaction( networkType: string, - request: BaseSignTransactionRequestModel | FuelSignTransactionRequest + request: BaseSignTransactionRequestModel | FuelSignTransactionRequestModel | StarknetSignTransactionRequestModel ): Promise { const res = await this.apiClient.post( `${networkType.toLowerCase()}/sign`, diff --git a/js/src/Blockchain/Blockchain.Abstraction/Models/AllowanceRequest.ts b/js/src/Blockchain/Blockchain.Abstraction/Models/AllowanceRequest.ts index 107cd1be..244bb479 100644 --- a/js/src/Blockchain/Blockchain.Abstraction/Models/AllowanceRequest.ts +++ b/js/src/Blockchain/Blockchain.Abstraction/Models/AllowanceRequest.ts @@ -2,6 +2,5 @@ import { BaseRequest } from "./BaseRequest"; export interface AllowanceRequest extends BaseRequest { ownerAddress: string; - spenderAddress: string; asset: string; } \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Abstraction/Models/FeesModels/EstimateFeeRequest.ts b/js/src/Blockchain/Blockchain.Abstraction/Models/FeesModels/EstimateFeeRequest.ts index 3c3d3252..6f6e32ac 100644 --- a/js/src/Blockchain/Blockchain.Abstraction/Models/FeesModels/EstimateFeeRequest.ts +++ b/js/src/Blockchain/Blockchain.Abstraction/Models/FeesModels/EstimateFeeRequest.ts @@ -6,4 +6,5 @@ export interface EstimateFeeRequest extends BaseRequest { fromAddress: string, asset: string, callData?: string + nonce: string } \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/HookedWalletEthTxSubprovider.ts b/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/HookedWalletEthTxSubprovider.ts deleted file mode 100644 index beeb9e73..00000000 --- a/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/HookedWalletEthTxSubprovider.ts +++ /dev/null @@ -1,50 +0,0 @@ -// From https://github.com/trufflesuite/truffle/blob/v5.7.2/packages/hdwallet-provider/src/index.ts - -const HookedWalletProvider = require('web3-provider-engine/subproviders/hooked-wallet'); -import { signTypedData, SignTypedDataVersion, personalSign } from "@metamask/eth-sig-util"; - -export class HookedWalletTypedSignatureSubprovider extends HookedWalletProvider { - - constructor(private _opts: any) { - super(_opts) - } - - // https://github.com/trufflesuite/truffle/blob/v5.7.2/packages/hdwallet-provider/src/index.ts#L228 - signTypedMessage({ data, from }: { data: string; from: string }, cb: any) { - this._opts.getPrivateKey(from, function (err: any, privateKey: any) { - if (err) return cb(err) - - if (!data) { - cb("No data to sign"); - return; - } - - const signature = signTypedData({ - data: JSON.parse(data), - privateKey: privateKey, - version: SignTypedDataVersion.V4 - }); - - cb(null, signature); - }) - } - - signMessage({ data, from }: any, cb: any) { - this._opts.getPrivateKey(from, function (err: any, privateKey: any) { - if (err) return cb(err) - - if (!data) { - cb("No data to sign"); - return; - } - - const signature = personalSign({ privateKey, data }) - - cb(null, signature); - }) - } - - signPersonalMessage(payload: any, cb: any) { - this.signMessage(payload, cb); - }; -} diff --git a/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyProvider.ts b/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyProvider.ts deleted file mode 100644 index 5609af6f..00000000 --- a/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyProvider.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { HookedWalletTypedSignatureSubprovider } from "./HookedWalletEthTxSubprovider"; -import RpcSubprovider from 'web3-provider-engine/subproviders/rpc'; -import Web3ProviderEngine from 'web3-provider-engine'; -import { Wallet } from 'ethers' - -function PrivateKeyProvider(privateKey: string, providerUrl: string = null) { - if (!privateKey) { - throw new Error(`Private Key missing, non-empty string expected, got "${privateKey}"`); - } - - this._providers = [] - - let wallet = new Wallet(privateKey); - var walletProvider = new HookedWalletTypedSignatureSubprovider({ - getAccounts: function (cb) { - cb(null, [wallet.address]) - }, - getPrivateKey: function (address, cb) { - if (address.toLowerCase() !== wallet.address.toLowerCase()) { - return cb('Account not found') - } - - let privateKey = wallet.privateKey; - if (privateKey.startsWith("0x")) { - privateKey = privateKey.substring(2); - } - - cb(null, privateKey) - } - }); - - this._providers.push(walletProvider); - if (providerUrl) { - this._providers.push(new RpcSubprovider({ rpcUrl: providerUrl })); - } -} - -PrivateKeyProvider.prototype._handleAsync = Web3ProviderEngine.prototype._handleAsync; - -PrivateKeyProvider.prototype.sendAsync = function (payload, cb) { - this._handleAsync(payload, cb) -} - -export default PrivateKeyProvider; diff --git a/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyRepository.ts b/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyRepository.ts deleted file mode 100644 index 9b78961d..00000000 --- a/js/src/Blockchain/Blockchain.Abstraction/Models/WalletsModels/PrivateKeyRepository.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { promises as fs } from 'fs'; -import nodeVault, { client } from 'node-vault' - -export class PrivateKeyRepository { - private pkKey: string = 'private_key'; - private vault: client; - private getTokenAsync!: () => Promise; - - constructor() { - this.vault = nodeVault({ - endpoint: process.env.TrainSolver__HashicorpKeyVaultUri - }); - - this.initLogin(); - } - - public async getAsync(address: string): Promise { - await this.getTokenAsync(); - const keyVaultMount = process.env.TrainSolver__HashicorpKeyVaultMountPath ?? 'secret'; - const {data} = await this.vault.read(`${keyVaultMount}/data/${address}`); - return data.data[this.pkKey]; - } - - public async getStarkPKAsync(address: string, network: string): Promise { - var key = `STARK-${network.replace('_', '-')}--${address.toLowerCase()}`; - return this.getAsync(key); - } - - private initLogin(): void { - const useKubernetesAuth = process.env.TrainSolver__HashicorpEnableKubernetesAuth === 'true'; - - this.getTokenAsync = useKubernetesAuth - ? async () => { - const k8sJWTPath = process.env.K8S_SERVICE_ACCOUNT_TOKEN_PATH; - var k8sRole = process.env.TrainSolver__HashicorpKeyVaultK8sAppRole; - const k8sJWT = await fs.readFile(k8sJWTPath, 'utf8'); - - await this.vault.kubernetesLogin({role: k8sRole , jwt: k8sJWT, mount_point: "kubernetes"}); - } - : async () => { - const userName = process.env.TrainSolver__HashicorpKeyVaultUsername; - const password = process.env.TrainSolver__HashicorpKeyVaultPassword; - - await this.vault - .userpassLogin({ - username: userName, - password: password, - mount_point: 'userpass', - }) - }; - } -} \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts index 944005b0..262354f3 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts @@ -23,8 +23,8 @@ import { InvalidTimelockException } from "../../Blockchain.Abstraction/Exception import { inject, injectable } from "tsyringe"; import Redis from "ioredis"; import Redlock from "redlock"; -import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient"; -import { FuelSignTransactionRequestModel } from "./Models/FuelSignTransactionModel"; +import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/TreasuryClient"; +import { SignTransactionRequest } from "./Models/FuelSignTransactionModel"; import { TransactionFailedException } from "../../Blockchain.Abstraction/Exceptions/TransactionFailedException"; import { CurrentNonceRequest } from "../../Blockchain.Abstraction/Models/NonceModels/CurrentNonceRequest"; import { NextNonceRequest } from "../../Blockchain.Abstraction/Models/NonceModels/NextNonceRequest"; @@ -37,7 +37,6 @@ export class FuelBlockchainActivities implements IFuelBlockchainActivities { constructor( @inject("Redis") private redis: Redis, @inject("Redlock") private lockFactory: Redlock, - // @inject("TreasuryClient") private treasuryClient: TreasuryClient ) { } @@ -296,7 +295,7 @@ export class FuelBlockchainActivities implements IFuelBlockchainActivities { } } - public async SignTransaction(request: FuelSignTransactionRequestModel): Promise { + public async SignTransaction(request: SignTransactionRequest): Promise { const treasuryClient = new TreasuryClient(request.signerAgentUrl); diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelEventTracker.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelEventTracker.ts index 0edde747..1d46a1a0 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelEventTracker.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/Helper/FuelEventTracker.ts @@ -2,11 +2,9 @@ import { bn, Contract, DateTime, Provider, ReceiptType } from "fuels"; import abi from '../ABIs/train.json'; import { HTLCBlockEventResponse, HTLCCommitEventMessage, HTLCLockEventMessage } from "../../../Blockchain.Abstraction/Models/EventModels/HTLCBlockEventResposne"; -import { TokenCommittedEvent } from "../Models/FuelTokenCommitedEvents"; -import { TokenLockedEvent } from "../Models/FuelTokenLockedEvent"; import { DetailedNetworkDto } from "../../../Blockchain.Abstraction/Models/DetailedNetworkDto"; import { FormatAddress } from "../FuelBlockchainActivities"; -import { ethers } from "ethers"; +import { TokenCommittedEvent, TokenLockedEvent } from "../Models/EventModels"; export default async function TrackBlockEventsAsync( network: DetailedNetworkDto, diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/IFuelBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/IFuelBlockchainActivities.ts index 26950591..1c5c0f59 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/IFuelBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/IFuelBlockchainActivities.ts @@ -3,7 +3,7 @@ import { GetTransactionRequest } from "../../Blockchain.Abstraction/Models/Recei import { TransactionResponse } from "../../Blockchain.Abstraction/Models/ReceiptModels/TransactionResponse"; import { FuelPublishTransactionRequest } from "../Models/FuelPublishTransactionRequest"; import { FuelComposeTransactionRequest } from "../Models/FuelComposeTransactionRequest"; -import { FuelSignTransactionRequestModel } from "./Models/FuelSignTransactionModel"; +import { SignTransactionRequest } from "./Models/FuelSignTransactionModel"; import { NextNonceRequest } from "../../Blockchain.Abstraction/Models/NonceModels/NextNonceRequest"; import { CurrentNonceRequest } from "../../Blockchain.Abstraction/Models/NonceModels/CurrentNonceRequest"; @@ -15,7 +15,7 @@ export interface IFuelBlockchainActivities extends IBlockchainActivities { ComposeRawTransaction(request: FuelComposeTransactionRequest): Promise; - SignTransaction(request: FuelSignTransactionRequestModel): Promise; + SignTransaction(request: SignTransactionRequest): Promise; GetNextNonce(request: NextNonceRequest): Promise; diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/Models/EventModels.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/Models/EventModels.ts new file mode 100644 index 00000000..458f6c14 --- /dev/null +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/Models/EventModels.ts @@ -0,0 +1,22 @@ +export interface TokenCommittedEvent { + Id: string; + dstChain: string; + dstAddress: string; + dstAsset: string; + srcAsset: string; + amount: string; + timelock: string; + srcReceiver: AddressBits; + sender: AddressBits; + assetId: AddressBits; +} + +interface AddressBits { + bits: string; +} + +export interface TokenLockedEvent { + hashlock: string; + timelock: string; + Id: string; +} \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelSignTransactionModel.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelSignTransactionModel.ts index 52f5cd82..de08be64 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelSignTransactionModel.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelSignTransactionModel.ts @@ -1,7 +1,7 @@ -import { FuelSignTransactionRequest } from "../../../Blockchain.Abstraction/Infrastructure/TreasuryClient/Models"; +import { FuelSignTransactionRequestModel } from "../../../Blockchain.Abstraction/Infrastructure/TreasuryClient/Models"; -export interface FuelSignTransactionRequestModel { +export interface SignTransactionRequest { networkType: string; - signRequest: FuelSignTransactionRequest; + signRequest: FuelSignTransactionRequestModel; signerAgentUrl: string; } \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenCommitedEvents.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenCommitedEvents.ts deleted file mode 100644 index 4f0315f5..00000000 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenCommitedEvents.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface TokenCommittedEvent { - Id: string; - dstChain: string; - dstAddress: string; - dstAsset: string; - srcAsset: string; - amount: string; - timelock: string; - srcReceiver: AddressBits; - sender: AddressBits; - assetId: AddressBits; -} - -interface AddressBits { - bits: string; -} diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenLockedEvent.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenLockedEvent.ts deleted file mode 100644 index 597a3ee7..00000000 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/Models/FuelTokenLockedEvent.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface TokenLockedEvent { - hashlock: string; - timelock: string; - Id: string; - } - \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Fuel/Workflows/FuelTransactionProcessor.ts b/js/src/Blockchain/Blockchain.Fuel/Workflows/FuelTransactionProcessor.ts index eba3cc9c..ecb8fcb3 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Workflows/FuelTransactionProcessor.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Workflows/FuelTransactionProcessor.ts @@ -35,12 +35,12 @@ export async function FuelTransactionProcessor( context: TransactionExecutionContext ): Promise { - const nextNonce = await defaultActivities.GetNextNonce({ - address: request.fromAddress, - network: request.network - }); + const nextNonce = await defaultActivities.GetNextNonce({ + address: request.fromAddress, + network: request.network + }); - try { + try { await defaultActivities.CheckCurrentNonce( { @@ -65,19 +65,16 @@ export async function FuelTransactionProcessor( callDataAmount: Number(preparedTransaction.callDataAmount), }); - const signedRawData = await defaultActivities.SignTransaction( - { - signerAgentUrl: request.signerAgentUrl, - networkType: NetworkType[request.network.type], - signRequest: { - unsignedTxn: rawTx, - address: request.fromAddress, - nodeUrl: request.network.nodes[0].url, - } + const signedRawData = await defaultActivities.SignTransaction({ + signerAgentUrl: request.signerAgentUrl, + networkType: NetworkType[request.network.type], + signRequest: { + unsignedTxn: rawTx, + address: request.fromAddress, + nodeUrl: request.network.nodes[0].url, } - ); + }); - // sign transaction const publishedTransaction = await nonRetryableActivities.PublishTransaction({ network: request.network, signedRawData: signedRawData @@ -89,28 +86,25 @@ export async function FuelTransactionProcessor( }); transactionResponse.asset = preparedTransaction.callDataAsset; - transactionResponse.amount = preparedTransaction.callDataAmount.toString(); + transactionResponse.amount = preparedTransaction.callDataAmount; - await defaultActivities.UpdateCurrentNonce( - { - address: request.fromAddress, - network: request.network, - currentNonce: nextNonce - } - ) + await defaultActivities.UpdateCurrentNonce({ + address: request.fromAddress, + network: request.network, + currentNonce: nextNonce + }); return transactionResponse; } catch (error) { - await defaultActivities.UpdateCurrentNonce( + await defaultActivities.UpdateCurrentNonce( { address: request.fromAddress, network: request.network, currentNonce: nextNonce - } - ) + }); if ((error instanceof ApplicationFailure && error.type === 'TransactionFailedException')) { diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/Client.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/Client.ts new file mode 100644 index 00000000..0845f7fa --- /dev/null +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/Client.ts @@ -0,0 +1,25 @@ +export async function sendInvocation(rpcUrl: string, invocation: object): Promise { + + const res = await fetch( + rpcUrl, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: 1, + method: "starknet_addInvokeTransaction", + params: [invocation], + }), + }); + + const body = await res.json(); + + if (body.error) { + throw new Error(`RPC error ${body.error.code}: ${body.error.message}`); + } + + if (body.result.transaction_hash) { + return body.result.transaction_hash; + } +} diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/ErrorParser.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/ErrorParser.ts index f33cbbc9..6e9c3ef1 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/ErrorParser.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/ErrorParser.ts @@ -1,8 +1,8 @@ export function ParseNonces(errorMessage: string): { expectedNonce: BigInt; providedNonce: BigInt; -} | null { - +} { + if (!errorMessage) { return null; } diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetEventTracker.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetEventTracker.ts index 3f6124f1..2678b99b 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetEventTracker.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetEventTracker.ts @@ -1,13 +1,11 @@ import { CallData, hash, num, Provider } from "starknet"; -import { TokenLockedEvent as TokenLockAddedEvent, TokenLockedEvent } from "../../Models/StarknetTokenLockedEvent"; import { events } from 'starknet'; import trainAbi from '../ABIs/Train.json'; -import { TokenCommittedEvent as TokenCommittedEvent } from "../../Models/StarknetTokenCommittedEvent"; import { formatAddress} from "../StarknetBlockchainActivities"; -import { formatUnits } from "ethers/lib/utils"; import { HTLCBlockEventResponse, HTLCCommitEventMessage, HTLCLockEventMessage } from "../../../Blockchain.Abstraction/Models/EventModels/HTLCBlockEventResposne"; import { BigIntToAscii, ToHex } from "../../../Blockchain.Abstraction/Extensions/StringExtensions"; import { DetailedNetworkDto } from "../../../Blockchain.Abstraction/Models/DetailedNetworkDto"; +import { TokenCommittedEvent, TokenLockedEvent } from "../../Models/EventModels"; export async function TrackBlockEventsAsync( @@ -76,7 +74,7 @@ export async function TrackBlockEventsAsync( response.htlcCommitEventMessages.push(commitMsg); } else if (eventName.endsWith("TokenLockAdded")) { - const data = eventData as unknown as TokenLockAddedEvent; + const data = eventData as unknown as TokenLockedEvent; const lockMsg: HTLCLockEventMessage = { txId: parsed.transaction_hash, @@ -94,4 +92,4 @@ export async function TrackBlockEventsAsync( export type ContractEvent = | Partial<{ TokenCommitted: TokenCommittedEvent }> - | Partial<{ TokenLockAdded: TokenLockAddedEvent }>; \ No newline at end of file + | Partial<{ TokenLockAdded: TokenLockedEvent }>; \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetTransactionBuilder.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetTransactionBuilder.ts index 0b9d1774..1de78cc6 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetTransactionBuilder.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/Helper/StarknetTransactionBuilder.ts @@ -1,5 +1,5 @@ import { utils } from "ethers"; -import { cairo, Call, shortString, byteArray } from "starknet"; +import { cairo, Call, shortString, byteArray, Invocation } from "starknet"; import { decodeJson } from "../../../Blockchain.Abstraction/Extensions/StringExtensions"; import { ApprovePrepareRequest } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/ApprovePrepareRequest"; import { HTLCAddLockSigTransactionPrepareRequest } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/HTLCAddLockSigTransactionPrepareRequest"; @@ -27,7 +27,7 @@ export function createRefundCallData(network: DetailedNetworkDto, args: string): const callData = [cairo.uint256(refundRequest.commitId)]; - const methodCall: Call = { + const methodCall: Invocation = { contractAddress: htlcContractAddress, entrypoint: "refund", calldata: callData @@ -62,7 +62,7 @@ export function createRedeemCallData(network: DetailedNetworkDto, args: string): cairo.uint256(redeemRequest.secret) ]; - const methodCall: Call = { + const methodCall: Invocation = { contractAddress: htlcContractAddress, entrypoint: "redeem", calldata: callData @@ -107,7 +107,7 @@ export function createLockCallData(network: DetailedNetworkDto, args: string): P token.contract ]; - const methodCall: Call = { + const methodCall: Invocation = { contractAddress: htlcContractAddress, entrypoint: "lock", calldata: callData @@ -145,7 +145,7 @@ export function createAddLockSigCallData(network: DetailedNetworkDto, args: stri cairo.uint256(addLockSigRequest.timelock), addLockSigRequest.signatureArray ]; - const methodCall: Call = { + const methodCall: Invocation = { contractAddress: htlcContractAddress, entrypoint: "addLockSig", calldata: callData @@ -180,7 +180,7 @@ export function createApproveCallData(network: DetailedNetworkDto, args: string) cairo.uint256(Number(utils.parseUnits(approveRequest.amount.toString(), token.decimals))) ]; - const methodCall: Call = { + const methodCall: Invocation = { contractAddress: token.contract, entrypoint: "approve", calldata: callData @@ -210,7 +210,7 @@ export function createTransferCallData(network: DetailedNetworkDto, args: string cairo.uint256(Number(utils.parseUnits(transferRequest.amount.toString(), token.decimals))) ]; - const methodCall: Call = { + const methodCall: Invocation = { contractAddress: token.contract, entrypoint: "transfer", calldata: callData diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/IStarknetBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/IStarknetBlockchainActivities.ts index e172a4f5..7b55d754 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Activities/IStarknetBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/IStarknetBlockchainActivities.ts @@ -10,24 +10,33 @@ import { TransactionResponse } from "../../Blockchain.Abstraction/Models/Receipt import { AddLockSignatureRequest } from "../../Blockchain.Abstraction/Models/TransactionBuilderModels/AddLockSignatureRequest"; import { TransactionBuilderRequest } from "../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransactionBuilderRequest"; import { PrepareTransactionResponse } from "../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransferBuilderResponse"; -import { StarknetPublishTransactionRequest } from "../Models/StarknetPublishTransactionRequest "; +import { ComposeRawTransactionRequest, ComposeRawTransactionResponse } from "../Models/ComposeRawTxModels"; +import { EnsureSufficientBalanceRequest } from "../Models/EnsureSufficientBalanceModels"; +import { PublishTransactionRequest, SimulateTransactionRequest } from "../Models/TransactionModels"; +import { SignTransactionRequest } from "../Models/SignTransactionRequest"; export interface IStarknetBlockchainActivities extends IBlockchainActivities { - SimulateTransaction(request: StarknetPublishTransactionRequest): Promise; + SimulateTransaction(request: SimulateTransactionRequest): Promise; GetSpenderAllowance(request: AllowanceRequest): Promise; - PublishTransaction(request: StarknetPublishTransactionRequest): Promise; + PublishTransaction(request: PublishTransactionRequest): Promise; GetBatchTransaction(request: GetBatchTransactionRequest): Promise; EstimateFee(request: EstimateFeeRequest): Promise; - getNextNonce(request: NextNonceRequest): Promise; + GetNextNonce(request: NextNonceRequest): Promise; BuildTransaction(request: TransactionBuilderRequest): Promise; GetTransaction(request: GetTransactionRequest): Promise; - ValidateAddLockSignature(request: AddLockSignatureRequest): Promise + ValidateAddLockSignature(request: AddLockSignatureRequest): Promise; + + EnsureSufficientBalance(request: EnsureSufficientBalanceRequest): Promise; + + ComposeRawTransaction(request: ComposeRawTransactionRequest): Promise; + + SignTransaction(request: SignTransactionRequest): Promise; } \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts index 01f488cd..1844a1de 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts @@ -1,13 +1,11 @@ -import { Abi, Account, cairo, Call, constants, Contract, hash, RpcProvider, shortString, transaction, TransactionType as StarknetTransactionType, uint256, addAddressPadding } from "starknet"; -import { ETransactionVersion2, TypedData, TypedDataRevision } from "starknet-types-07"; +import { Abi, cairo, Call, Contract, hash, RpcProvider, shortString, uint256, addAddressPadding, Invocation, SuccessfulTransactionReceiptResponse, InvocationsSignerDetails, stark, AccountInvocations, TransactionType as StarknetTransactionType, v3hash } from "starknet"; +import { TypedData, TypedDataRevision } from "starknet-types-07"; import { injectable, inject } from "tsyringe"; import erc20Json from './ABIs/ERC20.json' -import { StarknetPublishTransactionRequest } from "../Models/StarknetPublishTransactionRequest "; +import { PublishTransactionRequest, SimulateTransactionRequest } from "../Models/TransactionModels"; import { BigNumber, utils } from "ethers"; import { InvalidTimelockException } from "../../Blockchain.Abstraction/Exceptions/InvalidTimelockException"; -import { PrivateKeyRepository } from "../../Blockchain.Abstraction/Models/WalletsModels/PrivateKeyRepository"; import { ParseNonces } from "./Helper/ErrorParser"; -import { CalcV2InvokeTxHashArgs } from "../Models/StarknetTransactioCalculationType"; import { TransactionFailedException } from "../../Blockchain.Abstraction/Exceptions/TransactionFailedException"; import { TrackBlockEventsAsync } from "./Helper/StarknetEventTracker"; import Redis from "ioredis"; @@ -38,40 +36,94 @@ import { TransactionType } from "../../Blockchain.Abstraction/Models/Transaciton import { TransactionBuilderRequest } from "../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransactionBuilderRequest"; import { TransactionNotComfirmedException } from "../../Blockchain.Abstraction/Exceptions/TransactionNotComfirmedException"; import { DetailedNetworkDto } from "../../Blockchain.Abstraction/Models/DetailedNetworkDto"; -import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient"; +import { EnsureSufficientBalanceRequest } from "../Models/EnsureSufficientBalanceModels"; +import { ComposeRawTransactionRequest, ComposeRawTransactionResponse } from "../Models/ComposeRawTxModels"; +import { SignTransactionRequest } from "../Models/SignTransactionRequest"; +import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/TreasuryClient"; +import { sendInvocation } from "./Helper/Client"; @injectable() export class StarknetBlockchainActivities implements IStarknetBlockchainActivities { constructor( @inject("Redis") private redis: Redis, @inject("Redlock") private lockFactory: Redlock, - @inject("TreasuryClient") private treasuryClient: TreasuryClient ) { } - readonly FeeSymbol = "ETH"; - readonly FeeDecimals = 18; readonly FEE_ESTIMATE_MULTIPLIER = BigInt(4); - public async GetBatchTransaction(request: GetBatchTransactionRequest): Promise { - let transaction: TransactionResponse = null; + public async BuildTransaction(request: TransactionBuilderRequest): Promise { + try { + switch (request.type) { + case TransactionType.HTLCLock: + return createLockCallData(request.network, request.prepareArgs); + case TransactionType.HTLCRedeem: + return createRedeemCallData(request.network, request.prepareArgs); + case TransactionType.HTLCRefund: + return createRefundCallData(request.network, request.prepareArgs); + case TransactionType.HTLCAddLockSig: + return createAddLockSigCallData(request.network, request.prepareArgs); + case TransactionType.Approve: + return createApproveCallData(request.network, request.prepareArgs); + case TransactionType.Transfer: + return createTransferCallData(request.network, request.prepareArgs); + case TransactionType.HTLCCommit: + return createCommitCallData(request.network, request.prepareArgs); + default: + throw new Error(`Unknown function name ${request.type}`); + } + } + catch (error) { + throw error; + } + } - for (const transactionId of request.TransactionHashes) { - transaction = await this.GetTransactionByHashAsync(request.network, transactionId); + public async GetBalance(request: BalanceRequest): Promise { + try { + const token = request.network.tokens.find(t => t.symbol === request.asset); + + if (!token) { + throw new Error(`Token not found for network ${request.network.name} and asset ${request.asset}`); + } + + const provider = new RpcProvider({ + nodeUrl: request.network.nodes[0].url + }); + + const erc20 = new Contract(erc20Json as Abi, token.contract, provider); + const balanceResult = await erc20.balanceOf(request.address); + const balanceInWei = BigNumber.from(uint256.uint256ToBN(balanceResult.balance as any).toString()); + + let result: BalanceResponse = { + amount: Number(balanceInWei) + } + + return result; } + catch (error) { + throw error; + } + } + + public async GetTransaction(request: GetTransactionRequest): Promise { + + const transaction = await this.GetTransactionByHashAsync(request.network, request.transactionHash); if (!transaction) { - throw new TransactionNotComfirmedException("Transaction not confirmed"); + throw new TransactionNotComfirmedException(`Transaction ${request.transactionHash} not found`); } return transaction; } - public async GetTransaction(request: GetTransactionRequest): Promise { + public async GetBatchTransaction(request: GetBatchTransactionRequest): Promise { + let transaction: TransactionResponse = null; - const transaction = await this.GetTransactionByHashAsync(request.network, request.transactionHash); + for (const transactionId of request.TransactionHashes) { + transaction = await this.GetTransactionByHashAsync(request.network, transactionId); + } if (!transaction) { - throw new TransactionNotComfirmedException(`Transaction ${request.transactionHash} not found`); + throw new TransactionNotComfirmedException("Transaction not confirmed"); } return transaction; @@ -93,15 +145,15 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti const transactionReceiptResponse = await provider.getTransactionReceipt(transactionHash); - const confrimedTransaction = transactionReceiptResponse.isSuccess() ? transactionReceiptResponse : null; + const confrimedTransaction = transactionReceiptResponse.value as SuccessfulTransactionReceiptResponse if (!confrimedTransaction) { return null; } - const feeInWei = confrimedTransaction.actual_fee.amount; + const blockData = await provider.getBlockWithTxHashes(confrimedTransaction.block_number); - const feeAmount = Number(utils.formatUnits(BigNumber.from(feeInWei), this.FeeDecimals)); + const feeAmount = confrimedTransaction.actual_fee; let transactionModel: TransactionResponse = { transactionHash: transactionHash, @@ -111,19 +163,10 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti status: transactionStatus, feeAsset: network.nativeToken.symbol, feeAmount: feeAmount.toString(), - timestamp: new Date(), - networkName: network.name, + timestamp: new Date(blockData.timestamp * 1000), + networkName: network.name }; - const isConfirmed = "block_number" in confrimedTransaction; - - if (isConfirmed) { - const blockNumber = confrimedTransaction.block_number as string; - const blockData = await provider.getBlockWithTxHashes(blockNumber); - - transactionModel.timestamp = new Date(blockData.timestamp * 1000); - } - return transactionModel; } @@ -158,7 +201,7 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti ); } - public async getNextNonce(request: NextNonceRequest): Promise { + public async GetNextNonce(request: NextNonceRequest): Promise { const provider = new RpcProvider({ nodeUrl: request.network.nodes[0].url }); const formattedAddress = formatAddress(request.address); @@ -197,153 +240,39 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti } } - public async PublishTransaction(request: StarknetPublishTransactionRequest): Promise { - let result: string; - - const privateKey = await new PrivateKeyRepository().getAsync(request.fromAddress); - - const provider = new RpcProvider({ - nodeUrl: request.network.nodes[0].url - }); - - const account = new Account(provider, request.fromAddress, privateKey, '1'); - - var transferCall: Call = JSON.parse(request.callData); - - const compiledCallData = transaction.getExecuteCalldata([transferCall], await account.getCairoVersion()); - - const args: CalcV2InvokeTxHashArgs = { - senderAddress: request.fromAddress, - version: ETransactionVersion2.V1, - compiledCalldata: compiledCallData, - maxFee: request.fee.FixedFeeData.FeeInWei, - chainId: request.network.chainId as constants.StarknetChainId, - nonce: request.nonce - }; - - const calcualtedTxHash = hash.calculateInvokeTransactionHash(args); - - try { - - const executeResponse = await account.execute( - [transferCall], - undefined, - { - maxFee: request.fee.FixedFeeData.FeeInWei, - nonce: request.nonce - }, - ); - - result = executeResponse.transaction_hash; - - if (!result || !result.startsWith("0x")) { - throw new Error(`Withdrawal response didn't contain a correct transaction hash. Response: ${JSON.stringify(executeResponse)}`); - } - - return result; - } - catch (error) { - const nonceInfo = ParseNonces(error?.message); - - if (nonceInfo && nonceInfo.providedNonce < nonceInfo.expectedNonce) { - return calcualtedTxHash; - } - - throw error; - } - } - - public async BuildTransaction(request: TransactionBuilderRequest): Promise { - try { - switch (request.type) { - case TransactionType.HTLCLock: - return createLockCallData(request.network, request.prepareArgs); - case TransactionType.HTLCRedeem: - return createRedeemCallData(request.network, request.prepareArgs); - case TransactionType.HTLCRefund: - return createRefundCallData(request.network, request.prepareArgs); - case TransactionType.HTLCAddLockSig: - return createAddLockSigCallData(request.network, request.prepareArgs); - case TransactionType.Approve: - return createApproveCallData(request.network, request.prepareArgs); - case TransactionType.Transfer: - return createTransferCallData(request.network, request.prepareArgs); - case TransactionType.HTLCCommit: - return createCommitCallData(request.network, request.prepareArgs); - default: - throw new Error(`Unknown function name ${request.type}`); - } - } - catch (error) { - throw error; - } - } + public async PublishTransaction(request: PublishTransactionRequest): Promise { - public async GetBalance(request: BalanceRequest): Promise { - try { - const token = request.network.tokens.find(t => t.symbol === request.asset); + const invocation: Invocation = JSON.parse(request.signedRawData); + const nodeUrl = request.network.nodes[0].url; - if (!token) { - throw new Error(`Token not found for network ${request.network.name} and asset ${request.asset}`); - } - - const provider = new RpcProvider({ - nodeUrl: request.network.nodes[0].url - }); + const txHash = await sendInvocation(nodeUrl, invocation); - const erc20 = new Contract(erc20Json as Abi, token.contract, provider); - const balanceResult = await erc20.balanceOf(request.address); - const balanceInWei = BigNumber.from(uint256.uint256ToBN(balanceResult.balance as any).toString()); - - let result: BalanceResponse = { - amount: Number(balanceInWei) - } - - return result; - } - catch (error) { - throw error; - } + return txHash; } - public async SimulateTransaction(request: StarknetPublishTransactionRequest): Promise { - - const privateKey = await new PrivateKeyRepository().getAsync(request.fromAddress); + public async SimulateTransaction(request: SimulateTransactionRequest): Promise { const provider = new RpcProvider({ nodeUrl: request.network.nodes[0].url }); - const account = new Account(provider, request.fromAddress, privateKey, '1'); - - var transferCall: Call = JSON.parse(request.callData); + const invocation: Invocation = JSON.parse(request.signedRawData); - const compiledCallData = transaction.getExecuteCalldata([transferCall], await account.getCairoVersion()); - - const args: CalcV2InvokeTxHashArgs = { - senderAddress: request.fromAddress, - version: ETransactionVersion2.V1, - compiledCalldata: compiledCallData, - maxFee: request.fee.FixedFeeData.FeeInWei, - chainId: request.network.chainId as constants.StarknetChainId, - nonce: request.nonce - }; - - const calcualtedTxHash = await hash.calculateInvokeTransactionHash(args); + const accountInvocations: AccountInvocations = + [ + { + type: StarknetTransactionType.INVOKE, + contractAddress: invocation.contractAddress, + entrypoint: invocation.entrypoint, + nonce: request.nonce, + signature: invocation.signature + } + ]; try { - await account.simulateTransaction( - [ - { - type: StarknetTransactionType.INVOKE, - payload: [transferCall] - } - ], - { - nonce: request.nonce - }); + await provider.getSimulateTransaction(accountInvocations); - return calcualtedTxHash; + return; } catch (error) { const nonceInfo = ParseNonces(error?.message); @@ -364,17 +293,18 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti public async EstimateFee(feeRequest: EstimateFeeRequest): Promise { try { - const privateKey = await new PrivateKeyRepository().getAsync(feeRequest.fromAddress); const provider = new RpcProvider({ nodeUrl: feeRequest.network.nodes[0].url }); - const account = new Account(provider, feeRequest.fromAddress, privateKey, '1'); - - var transferCall: Call = JSON.parse(feeRequest.callData); + const transferCall: Invocation = JSON.parse(feeRequest.callData); - let feeEstimateResponse = await account.estimateFee(transferCall); + const feeEstimateResponse = await provider.getInvokeEstimateFee( + transferCall, + { + nonce: feeRequest.nonce + }); if (!feeEstimateResponse?.suggestedMaxFee) { throw new Error(`Couldn't get fee estimation for the transfer. Response: ${JSON.stringify(feeEstimateResponse)}`); @@ -388,24 +318,12 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti FeeInWei: feeInWei.toString(), }; - let result: Fee = + const result: Fee = { - Asset: this.FeeSymbol, + Asset: feeRequest.network.nativeToken.symbol, FixedFeeData: fixedfeeData, } - const balanceResponse = await this.GetBalance({ - address: feeRequest.fromAddress, - network: feeRequest.network, - asset: this.FeeSymbol - }); - - const amount = feeInWei.add(BigNumber.from(feeRequest.amount)); - - if (BigNumber.from(balanceResponse.amount).lt(amount)) { - throw new Error(`Insufficient balance for fee. Balance: ${balanceResponse.amount}, Fee: ${amount}`); - } - return result; } catch (error: any) { @@ -416,6 +334,42 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti } } + public async EnsureSufficientBalance(request: EnsureSufficientBalanceRequest): Promise { + + const nativeTokenAsset = request.network.nativeToken.symbol; + + const nativeTokenBalance = await this.GetBalance({ + address: request.address, + network: request.network, + asset: nativeTokenAsset + }); + + const amount = BigNumber.from(request.amount); + const feeAmount = BigNumber.from(request.feeAmount); + + if (nativeTokenAsset === request.asset) { + + if (BigNumber.from(nativeTokenBalance.amount).lt(amount.add(feeAmount))) { + throw new Error(`Insufficient balance for fee. Balance: ${nativeTokenBalance.amount} asset ${nativeTokenAsset}, Fee: ${amount.add(feeAmount)}`); + } + } + else { + const tokenBalance = await this.GetBalance({ + address: request.address, + network: request.network, + asset: request.asset + }); + + if (BigNumber.from(nativeTokenBalance.amount).lt(feeAmount)) { + throw new Error(`Insufficient balance for fee. Balance: ${nativeTokenBalance.amount} asset ${nativeTokenAsset}, Fee: ${feeAmount}`); + } + + if (BigNumber.from(tokenBalance.amount).lt(amount)) { + throw new Error(`Insufficient balance for fee. Balance: ${tokenBalance.amount} asset ${request.asset}, Fee: ${amount}`); + } + } + } + public async ValidateAddLockSignature(request: AddLockSignatureRequest): Promise { try { @@ -494,6 +448,50 @@ export class StarknetBlockchainActivities implements IStarknetBlockchainActiviti throw error; } } + + public async ComposeRawTransaction(request: ComposeRawTransactionRequest): Promise { + + const provider = new RpcProvider({ + nodeUrl: request.network.nodes[0].url + }); + + const chainId = await provider.getChainId(); + + const signerDetails: InvocationsSignerDetails = { + ...stark.v3Details({}), + walletAddress: request.address, + nonce: request.nonce, + version: "0x3", + chainId, + cairoVersion: '1', + skipValidate: false + }; + + const parsedInvocation: Invocation = JSON.parse(request.callData); + + const transferCall: Call = + { + contractAddress: parsedInvocation.contractAddress, + entrypoint: parsedInvocation.entrypoint, + calldata: parsedInvocation.calldata + }; + + const result: ComposeRawTransactionResponse = + { + signerInvocationDetails: JSON.stringify(signerDetails), + unsignedTxn: JSON.stringify(transferCall) + }; + + return result; + }; + + public async SignTransaction(request: SignTransactionRequest): Promise { + const treasuryClient = new TreasuryClient(request.signerAgentUrl); + + const response = await treasuryClient.signTransaction(request.networkType, request.signRequest); + + return response.signedTxn; + } } export function formatAddress(address: string): string { diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/ComposeRawTxModels.ts b/js/src/Blockchain/Blockchain.Starknet/Models/ComposeRawTxModels.ts new file mode 100644 index 00000000..e10e844d --- /dev/null +++ b/js/src/Blockchain/Blockchain.Starknet/Models/ComposeRawTxModels.ts @@ -0,0 +1,12 @@ +import { BaseRequest } from "../../Blockchain.Abstraction/Models/BaseRequest"; + +export interface ComposeRawTransactionRequest extends BaseRequest { + callData: string, + nonce: string, + address: string +} + +export interface ComposeRawTransactionResponse { + unsignedTxn: string, + signerInvocationDetails: string +} \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/EnsureSufficientBalanceModels.ts b/js/src/Blockchain/Blockchain.Starknet/Models/EnsureSufficientBalanceModels.ts new file mode 100644 index 00000000..369c5664 --- /dev/null +++ b/js/src/Blockchain/Blockchain.Starknet/Models/EnsureSufficientBalanceModels.ts @@ -0,0 +1,8 @@ +import { BaseRequest } from "../../Blockchain.Abstraction/Models/BaseRequest"; + +export interface EnsureSufficientBalanceRequest extends BaseRequest{ + address: string, + asset: string, + amount: string, + feeAmount: string +} \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTokenCommittedEvent.ts b/js/src/Blockchain/Blockchain.Starknet/Models/EventModels.ts similarity index 71% rename from js/src/Blockchain/Blockchain.Starknet/Models/StarknetTokenCommittedEvent.ts rename to js/src/Blockchain/Blockchain.Starknet/Models/EventModels.ts index 66da92e0..ed9f1fa8 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTokenCommittedEvent.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Models/EventModels.ts @@ -1,3 +1,9 @@ +export interface TokenLockedEvent { + hashlock: bigint; + timelock: bigint; + Id: bigint; +} + export interface TokenCommittedEvent { Id: bigint; dstChain: bigint; @@ -9,5 +15,4 @@ export interface TokenCommittedEvent { tokenContract: string; srcReceiver: bigint; sender: bigint; - } - \ No newline at end of file +} diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/SignTransactionRequest.ts b/js/src/Blockchain/Blockchain.Starknet/Models/SignTransactionRequest.ts new file mode 100644 index 00000000..703f2845 --- /dev/null +++ b/js/src/Blockchain/Blockchain.Starknet/Models/SignTransactionRequest.ts @@ -0,0 +1,7 @@ +import { StarknetSignTransactionRequestModel } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/Models/StarknetSignTransactionRequestModel"; + +export interface SignTransactionRequest{ + signRequest: StarknetSignTransactionRequestModel; + networkType: string; + signerAgentUrl: string; +} \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetPublishTransactionRequest .ts b/js/src/Blockchain/Blockchain.Starknet/Models/StarknetPublishTransactionRequest .ts deleted file mode 100644 index 3c68cbb0..00000000 --- a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetPublishTransactionRequest .ts +++ /dev/null @@ -1,9 +0,0 @@ -import { BaseRequest } from "../../Blockchain.Abstraction/Models/BaseRequest"; -import { Fee } from "../../Blockchain.Abstraction/Models/FeesModels/Fee"; - -export interface StarknetPublishTransactionRequest extends BaseRequest { - fromAddress: string; - callData: string; - nonce: string; - fee: Fee; - } \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTokenLockedEvent.ts b/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTokenLockedEvent.ts deleted file mode 100644 index 01e0893b..00000000 --- a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTokenLockedEvent.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface TokenLockedEvent { - hashlock: bigint; - timelock: bigint; - Id: bigint; - } - \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTransactioCalculationType.ts b/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTransactioCalculationType.ts deleted file mode 100644 index 28d81b58..00000000 --- a/js/src/Blockchain/Blockchain.Starknet/Models/StarknetTransactioCalculationType.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { BigNumberish, Calldata, constants } from "starknet"; -import { ETransactionVersion2 } from "starknet-types-07"; - - -export type CalcV2InvokeTxHashArgs = { - senderAddress: BigNumberish; - version: ETransactionVersion2; - compiledCalldata: Calldata; - maxFee: BigNumberish; - chainId: constants.StarknetChainId; - nonce: BigNumberish; - }; \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/TransactionCalculationType.ts b/js/src/Blockchain/Blockchain.Starknet/Models/TransactionCalculationType.ts new file mode 100644 index 00000000..19d76b0e --- /dev/null +++ b/js/src/Blockchain/Blockchain.Starknet/Models/TransactionCalculationType.ts @@ -0,0 +1,11 @@ +import { BigNumberish, Calldata, constants } from "starknet"; +import { ETransactionVersion2 } from "starknet-types-07"; + +export type CalcV2InvokeTxHashArgs = { + senderAddress: BigNumberish; + version: ETransactionVersion2; + compiledCalldata: Calldata; + maxFee: BigNumberish; + chainId: constants.StarknetChainId; + nonce: BigNumberish; +}; \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Models/TransactionModels.ts b/js/src/Blockchain/Blockchain.Starknet/Models/TransactionModels.ts new file mode 100644 index 00000000..b22c547a --- /dev/null +++ b/js/src/Blockchain/Blockchain.Starknet/Models/TransactionModels.ts @@ -0,0 +1,9 @@ +import { BaseRequest } from "../../Blockchain.Abstraction/Models/BaseRequest"; + +export interface PublishTransactionRequest extends BaseRequest { + signedRawData: string; +} + +export interface SimulateTransactionRequest extends PublishTransactionRequest { + nonce: string; +} \ No newline at end of file diff --git a/js/src/Blockchain/Blockchain.Starknet/Worker/StarknetWorker.ts b/js/src/Blockchain/Blockchain.Starknet/Worker/StarknetWorker.ts index c7827779..3074343f 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Worker/StarknetWorker.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Worker/StarknetWorker.ts @@ -1,5 +1,4 @@ import { Worker, NativeConnection } from '@temporalio/worker'; -import * as dotenv from 'dotenv'; import 'reflect-metadata'; import { StarknetBlockchainActivities } from '../Activities/StarknetBlockchainActivities'; import { extractActivities as ExtractActivities } from '../../../TemporalHelper/ActivityParser'; @@ -7,7 +6,6 @@ import { container } from 'tsyringe'; import { AddCoreServices } from '../../Blockchain.Abstraction/Infrastructure/AddCoreServices'; export default async function run( taskQueue: string): Promise { - dotenv.config(); try { diff --git a/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts b/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts index 754bc6d5..60ed5648 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts @@ -6,13 +6,13 @@ import { AlreadyClaimedExceptions } from '../../Blockchain.Abstraction/Exception import { HTLCAlreadyExistsException } from '../../Blockchain.Abstraction/Exceptions/HTLCAlreadyExistsException'; import { TransactionFailedException } from '../../Blockchain.Abstraction/Exceptions/TransactionFailedException'; import { buildProcessorId, decodeJson } from '../../Blockchain.Abstraction/Extensions/StringExtensions'; -import { AllowanceRequest } from '../../Blockchain.Abstraction/Models/AllowanceRequest'; import { TransactionResponse } from '../../Blockchain.Abstraction/Models/ReceiptModels/TransactionResponse'; import { TransactionExecutionContext } from '../../Blockchain.Abstraction/Models/TransacitonModels/TransactionExecutionContext'; import { TransactionRequest } from '../../Blockchain.Abstraction/Models/TransacitonModels/TransactionRequest'; import { HTLCLockTransactionPrepareRequest } from '../../Blockchain.Abstraction/Models/TransactionBuilderModels/HTLCLockTransactionPrepareRequest'; import { TransferPrepareRequest } from '../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransferPrepareRequest'; import { TransactionType } from '../../Blockchain.Abstraction/Models/TransacitonModels/TransactionType'; +import { NetworkType } from '../../Blockchain.Abstraction/Models/Dtos/NetworkDto'; const defaultActivities = proxyActivities({ startToCloseTimeout: '1 hour', @@ -49,8 +49,16 @@ export async function StarknetTransactionProcessor( fromAddress: request.fromAddress, swapId: request.swapId, }); + try { + if (!context.nonce) { + context.nonce = await defaultActivities.GetNextNonce({ + network: request.network, + address: request.fromAddress, + }); + } + if (!context.fee) { context.fee = await nonRetryableActivities.EstimateFee({ network: request.network, @@ -59,32 +67,46 @@ export async function StarknetTransactionProcessor( fromAddress: request.fromAddress, asset: preparedTransaction.asset!, callData: preparedTransaction.data, + nonce: context.nonce }); } - if (!context.nonce) { - context.nonce = await defaultActivities.getNextNonce({ - network: request.network, + await defaultActivities.EnsureSufficientBalance( + { address: request.fromAddress, - }); - } - - const simulationTxId = await nonRetryableActivities.SimulateTransaction({ - network: request.network, - fromAddress: request.fromAddress, - nonce: context.nonce, + amount: preparedTransaction.callDataAmount, + asset: preparedTransaction.asset, + feeAmount: context.fee.FixedFeeData.FeeInWei, + network: request.network + } + ); + + const rawTx = await defaultActivities.ComposeRawTransaction({ + address: request.fromAddress, callData: preparedTransaction.data, - fee: context.fee, + network: request.network, + nonce: context.nonce }); - context.publishedTransactionIds.push(simulationTxId); + const signedRawData = await defaultActivities.SignTransaction({ + signerAgentUrl: request.signerAgentUrl, + networkType: NetworkType[request.network.type], + signRequest: { + unsignedTxn: rawTx.unsignedTxn, + signerInvocationDetails: rawTx.signerInvocationDetails, + address: request.fromAddress, + } + }); + + await nonRetryableActivities.SimulateTransaction({ + nonce: context.nonce, + network: request.network, + signedRawData: signedRawData + }); const txId = await nonRetryableActivities.PublishTransaction({ network: request.network, - fromAddress: request.fromAddress, - nonce: context.nonce, - callData: preparedTransaction.data, - fee: context.fee, + signedRawData: signedRawData }); context.publishedTransactionIds.push(txId); @@ -98,7 +120,6 @@ export async function StarknetTransactionProcessor( confirmed.amount = preparedTransaction.callDataAmount.toString(); return confirmed; - } catch (error) { if (error instanceof InvalidTimelockException && context.nonce) { @@ -146,7 +167,7 @@ export async function checkAllowance(context: TransactionRequest): Promise network: context.network, ownerAddress: context.fromAddress!, asset: lockRequest.sourceAsset, - } as AllowanceRequest); + }); if (lockRequest.amount > allowance) { @@ -171,7 +192,7 @@ export async function checkAllowance(context: TransactionRequest): Promise }; const processorId = buildProcessorId(uuid4(), context.network.name, context.type); - + await executeChild(StarknetTransactionProcessor, { args: [approveRequest, childContext], From 32c2e0a62de153b7b7d2ee230589f372aedc7d63 Mon Sep 17 00:00:00 2001 From: Davit Mandzikyan Date: Mon, 15 Sep 2025 17:18:16 +0400 Subject: [PATCH 2/7] Minor fixes. --- .../Infrastructure/TreasuryClient/treasuryClient.ts | 2 +- .../Workflows/StarknetTransactionProcessor.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts index bcfa28f3..ad1dc154 100644 --- a/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts +++ b/js/src/Blockchain/Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient.ts @@ -8,7 +8,7 @@ import { import axios from "axios"; export class TreasuryClient { - private apiClient + private apiClient; constructor(signerAgentUrl: string) { this.apiClient = axios.create({ diff --git a/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts b/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts index 60ed5648..fd4a4873 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Workflows/StarknetTransactionProcessor.ts @@ -159,7 +159,7 @@ export async function StarknetTransactionProcessor( } } -export async function checkAllowance(context: TransactionRequest): Promise { +async function checkAllowance(context: TransactionRequest): Promise { const lockRequest = decodeJson(context.prepareArgs); const allowance = await defaultActivities.GetSpenderAllowance( From cbb15e006fd8029e67c729725d67c465dedf89f5 Mon Sep 17 00:00:00 2001 From: Davit Mandzikyan Date: Mon, 15 Sep 2025 17:18:31 +0400 Subject: [PATCH 3/7] Starknet signing part. --- .../src/treasury/starknet/starknet.dto.ts | 4 +-- .../src/treasury/starknet/starknet.service.ts | 32 +++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/treasury/src/treasury/starknet/starknet.dto.ts b/treasury/src/treasury/starknet/starknet.dto.ts index 93f3ea9c..240197ff 100644 --- a/treasury/src/treasury/starknet/starknet.dto.ts +++ b/treasury/src/treasury/starknet/starknet.dto.ts @@ -1,7 +1,5 @@ import { BaseSignRequest, BaseSignResponse } from "src/app/dto/base.dto"; export class StarknetSignRequest extends BaseSignRequest { -} - -export class StarknetSignResponse extends BaseSignResponse { + signerInvocationDetails: string; } \ No newline at end of file diff --git a/treasury/src/treasury/starknet/starknet.service.ts b/treasury/src/treasury/starknet/starknet.service.ts index 99a755a3..3db54e3b 100644 --- a/treasury/src/treasury/starknet/starknet.service.ts +++ b/treasury/src/treasury/starknet/starknet.service.ts @@ -1,26 +1,40 @@ import { Injectable } from '@nestjs/common'; import { TreasuryService } from '../../app/interfaces/treasury.interface'; import { Network } from '../shared/networks.types'; -import { StarknetSignRequest, StarknetSignResponse } from './starknet.dto'; +import { StarknetSignRequest } from './starknet.dto'; import { PrivateKeyService } from 'src/kv/vault.service'; -import { GenerateResponse } from '../../app/dto/base.dto'; +import { BaseSignResponse, GenerateResponse } from '../../app/dto/base.dto'; +import { Call, ec, Invocation, InvocationsSignerDetails, Signer, stark, transaction } from 'starknet'; @Injectable() export class StarknetTreasuryService extends TreasuryService { - + readonly network: Network = 'starknet'; - constructor(privateKeyService: PrivateKeyService){ + constructor(privateKeyService: PrivateKeyService) { super(privateKeyService); } - // TODO: Implement the Starknet signing logic - sign(req: StarknetSignRequest): Promise { - throw new Error('Method not implemented.'); + async sign(request: StarknetSignRequest): Promise { + const privateKey = await this.privateKeyService.getAsync(request.address); + + const transferCalls: Call = JSON.parse(request.unsignedTxn); + const signerDetails: InvocationsSignerDetails = JSON.parse(request.signerInvocationDetails); + + const calldata = transaction.getExecuteCalldata([transferCalls], signerDetails.cairoVersion); + const signature = await new Signer(privateKey).signTransaction([transferCalls], signerDetails); + + const response: Invocation = { + ...stark.v3Details(signerDetails), + contractAddress: request.address, + calldata, + signature, + }; + + return { signedTxn: JSON.stringify(response) }; } - // TODO: Implement the Starknet address generation(if applicable) - generate(): Promise { + async generate(): Promise { throw new Error('Method not implemented.'); } } \ No newline at end of file From 2c081dcff0d0ac3b00c439c36542da7b99c08d81 Mon Sep 17 00:00:00 2001 From: Davit Mandzikyan Date: Wed, 15 Oct 2025 17:23:59 +0400 Subject: [PATCH 4/7] Commit. --- .../src/treasury/starknet/starknet.dto.ts | 1 + .../src/treasury/starknet/starknet.service.ts | 85 ++++++++++++++++--- 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/treasury/src/treasury/starknet/starknet.dto.ts b/treasury/src/treasury/starknet/starknet.dto.ts index 240197ff..175a7cbb 100644 --- a/treasury/src/treasury/starknet/starknet.dto.ts +++ b/treasury/src/treasury/starknet/starknet.dto.ts @@ -2,4 +2,5 @@ import { BaseSignRequest, BaseSignResponse } from "src/app/dto/base.dto"; export class StarknetSignRequest extends BaseSignRequest { signerInvocationDetails: string; + type: string } \ No newline at end of file diff --git a/treasury/src/treasury/starknet/starknet.service.ts b/treasury/src/treasury/starknet/starknet.service.ts index 3db54e3b..41b0b5a1 100644 --- a/treasury/src/treasury/starknet/starknet.service.ts +++ b/treasury/src/treasury/starknet/starknet.service.ts @@ -4,37 +4,96 @@ import { Network } from '../shared/networks.types'; import { StarknetSignRequest } from './starknet.dto'; import { PrivateKeyService } from 'src/kv/vault.service'; import { BaseSignResponse, GenerateResponse } from '../../app/dto/base.dto'; -import { Call, ec, Invocation, InvocationsSignerDetails, Signer, stark, transaction } from 'starknet'; +import { CairoCustomEnum, CairoOption, CairoOptionVariant, Call, CallData, DeployAccountSignerDetails, ec, hash, Invocation, InvocationsSignerDetails, Signer, stark, transaction } from 'starknet'; @Injectable() export class StarknetTreasuryService extends TreasuryService { readonly network: Network = 'starknet'; + readonly argentXaccountClassHash = '0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f'; constructor(privateKeyService: PrivateKeyService) { super(privateKeyService); } async sign(request: StarknetSignRequest): Promise { + const privateKey = await this.privateKeyService.getAsync(request.address); + const signer = new Signer(privateKey); + + if (request.type === "Deploy") { + const pubKey = await signer.getPubKey(); + + const axSigner = new CairoCustomEnum({ Starknet: { pubkey: pubKey } }); + const axGuardian = new CairoOption(CairoOptionVariant.None); + + const AXConstructorCallData = CallData.compile({ + owner: axSigner, + guardian: axGuardian, + }); + + const AXcontractAddress = hash.calculateContractAddressFromHash( + pubKey, + this.argentXaccountClassHash, + AXConstructorCallData, + 0 + ); + + const deployAccountPayload = { + classHash: this.argentXaccountClassHash, + constructorCalldata: AXConstructorCallData, + contractAddress: request.address, + addressSalt: pubKey, + }; + + const deployDetails: DeployAccountSignerDetails = + { + + } - const transferCalls: Call = JSON.parse(request.unsignedTxn); - const signerDetails: InvocationsSignerDetails = JSON.parse(request.signerInvocationDetails); - const calldata = transaction.getExecuteCalldata([transferCalls], signerDetails.cairoVersion); - const signature = await new Signer(privateKey).signTransaction([transferCalls], signerDetails); - const response: Invocation = { - ...stark.v3Details(signerDetails), - contractAddress: request.address, - calldata, - signature, - }; - return { signedTxn: JSON.stringify(response) }; + + } + else { + const transferCalls: Call = JSON.parse(request.unsignedTxn); + const signerDetails: InvocationsSignerDetails = JSON.parse(request.signerInvocationDetails); + + const calldata = transaction.getExecuteCalldata([transferCalls], signerDetails.cairoVersion); + const signature = await signer.signTransaction([transferCalls], signerDetails); + + const response: Invocation = { + ...stark.v3Details(signerDetails), + contractAddress: request.address, + calldata, + signature, + }; + + return { signedTxn: JSON.stringify(response) }; + } } async generate(): Promise { - throw new Error('Method not implemented.'); + + const privateKeyAX = stark.randomAddress(); + const starkKeyPubAX = ec.starkCurve.getStarkKey(privateKeyAX); + + // Calculate future address of the ArgentX account + const axSigner = new CairoCustomEnum({ Starknet: { pubkey: starkKeyPubAX } }); + const axGuardian = new CairoOption(CairoOptionVariant.None); + const AXConstructorCallData = CallData.compile({ + owner: axSigner, + guardian: axGuardian, + }); + + const address = hash.calculateContractAddressFromHash( + starkKeyPubAX, + this.argentXaccountClassHash, + AXConstructorCallData, + 0 + ); + + return { address } } } \ No newline at end of file From b64d91320bf6fef9b54281ef17f6afbf93df325d Mon Sep 17 00:00:00 2001 From: maxim055 Date: Wed, 12 Nov 2025 15:35:29 +0400 Subject: [PATCH 5/7] Fix build erros. --- .../StarknetBlockchainActivities.ts | 2 +- treasury/src/app/treasury.types.ts | 5 +- .../src/treasury/starknet/starknet.service.ts | 69 +++++++++---------- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts index 1844a1de..31069975 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts @@ -39,8 +39,8 @@ import { DetailedNetworkDto } from "../../Blockchain.Abstraction/Models/Detailed import { EnsureSufficientBalanceRequest } from "../Models/EnsureSufficientBalanceModels"; import { ComposeRawTransactionRequest, ComposeRawTransactionResponse } from "../Models/ComposeRawTxModels"; import { SignTransactionRequest } from "../Models/SignTransactionRequest"; -import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/TreasuryClient"; import { sendInvocation } from "./Helper/Client"; +import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/TreasuryClient"; @injectable() export class StarknetBlockchainActivities implements IStarknetBlockchainActivities { diff --git a/treasury/src/app/treasury.types.ts b/treasury/src/app/treasury.types.ts index dbece533..22563590 100644 --- a/treasury/src/app/treasury.types.ts +++ b/treasury/src/app/treasury.types.ts @@ -1,6 +1,6 @@ import { EVMSignRequest, EVMSignResponse } from "../treasury/evm/evm.dto"; import { BaseSignRequest, BaseSignResponse } from "./dto/base.dto"; -import { StarknetSignRequest, StarknetSignResponse } from "../treasury/starknet/starknet.dto"; +import { StarknetSignRequest } from "../treasury/starknet/starknet.dto"; import { FuelSignRequest } from "../treasury/fuel/fuel.dto"; export type SignRequest = @@ -9,5 +9,4 @@ export type SignRequest = | FuelSignRequest) & BaseSignRequest; export type SignResponse = - (EVMSignResponse - | StarknetSignResponse) & BaseSignResponse; + (EVMSignResponse) & BaseSignResponse; diff --git a/treasury/src/treasury/starknet/starknet.service.ts b/treasury/src/treasury/starknet/starknet.service.ts index 41b0b5a1..a7865c49 100644 --- a/treasury/src/treasury/starknet/starknet.service.ts +++ b/treasury/src/treasury/starknet/starknet.service.ts @@ -21,42 +21,37 @@ export class StarknetTreasuryService extends TreasuryService { const privateKey = await this.privateKeyService.getAsync(request.address); const signer = new Signer(privateKey); - if (request.type === "Deploy") { - const pubKey = await signer.getPubKey(); - - const axSigner = new CairoCustomEnum({ Starknet: { pubkey: pubKey } }); - const axGuardian = new CairoOption(CairoOptionVariant.None); - - const AXConstructorCallData = CallData.compile({ - owner: axSigner, - guardian: axGuardian, - }); - - const AXcontractAddress = hash.calculateContractAddressFromHash( - pubKey, - this.argentXaccountClassHash, - AXConstructorCallData, - 0 - ); - - const deployAccountPayload = { - classHash: this.argentXaccountClassHash, - constructorCalldata: AXConstructorCallData, - contractAddress: request.address, - addressSalt: pubKey, - }; - - const deployDetails: DeployAccountSignerDetails = - { - - } - - - - - - } - else { + // if (request.type === "Deploy") { + // const pubKey = await signer.getPubKey(); + + // const axSigner = new CairoCustomEnum({ Starknet: { pubkey: pubKey } }); + // const axGuardian = new CairoOption(CairoOptionVariant.None); + + // const AXConstructorCallData = CallData.compile({ + // owner: axSigner, + // guardian: axGuardian, + // }); + + // const AXcontractAddress = hash.calculateContractAddressFromHash( + // pubKey, + // this.argentXaccountClassHash, + // AXConstructorCallData, + // 0 + // ); + + // const deployAccountPayload = { + // classHash: this.argentXaccountClassHash, + // constructorCalldata: AXConstructorCallData, + // contractAddress: request.address, + // addressSalt: pubKey, + // }; + + // const deployDetails: DeployAccountSignerDetails = + // { + + // } + // } + //else { const transferCalls: Call = JSON.parse(request.unsignedTxn); const signerDetails: InvocationsSignerDetails = JSON.parse(request.signerInvocationDetails); @@ -71,7 +66,7 @@ export class StarknetTreasuryService extends TreasuryService { }; return { signedTxn: JSON.stringify(response) }; - } + //} } async generate(): Promise { From c041281f96a6e860227af9940b635f364fef11fe Mon Sep 17 00:00:00 2001 From: maxim055 Date: Wed, 12 Nov 2025 16:40:49 +0400 Subject: [PATCH 6/7] Remove aztec. --- js/src/index.ts | 6 +++--- treasury/src/treasury/treasury.module.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/js/src/index.ts b/js/src/index.ts index 75cd6dc2..d34b189c 100644 --- a/js/src/index.ts +++ b/js/src/index.ts @@ -14,9 +14,9 @@ switch (network) { case 'Fuel': fuelWorker(network); break; - case 'Aztec': - aztecWorker(network); - break; + // case 'Aztec': + // aztecWorker(network); + // break; default: console.error(`Unknown network: ${network}. Supported networks are: Starknet, Fuel.`); process.exit(1); diff --git a/treasury/src/treasury/treasury.module.ts b/treasury/src/treasury/treasury.module.ts index bae4e137..0aed57d9 100644 --- a/treasury/src/treasury/treasury.module.ts +++ b/treasury/src/treasury/treasury.module.ts @@ -17,8 +17,8 @@ import { AztecConfigService } from './aztec/aztec.config'; AztecConfigService, { provide: TREASURIES, - useFactory: (evm, starknet, fuel, aztec) => [evm, starknet, fuel, aztec], - inject: [EvmTreasuryService, StarknetTreasuryService, FuelTreasuryService, AztecTreasuryService], + useFactory: (evm, starknet, fuel) => [evm, starknet, fuel], + inject: [EvmTreasuryService, StarknetTreasuryService, FuelTreasuryService], }, ], exports: [TREASURIES], From 788b35dc24f1f9bd55ba458a25a31030699b0e24 Mon Sep 17 00:00:00 2001 From: maxim055 Date: Wed, 12 Nov 2025 16:54:03 +0400 Subject: [PATCH 7/7] Rename back treasury client. --- .../Blockchain.Aztec/Activities/AztecBlockchainActivities.ts | 2 +- .../Blockchain.Fuel/Activities/FuelBlockchainActivities.ts | 2 +- .../Activities/StarknetBlockchainActivities.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/Blockchain/Blockchain.Aztec/Activities/AztecBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Aztec/Activities/AztecBlockchainActivities.ts index d4a4d771..a360bd34 100644 --- a/js/src/Blockchain/Blockchain.Aztec/Activities/AztecBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Aztec/Activities/AztecBlockchainActivities.ts @@ -18,7 +18,7 @@ import { TransactionFailedException } from "../../Blockchain.Abstraction/Excepti import { createAztecNodeClient, Tx, TxHash } from "@aztec/aztec.js"; import { mapAztecStatusToInternal } from "./Helper/AztecTransactionStatusMapper"; import { AztecPublishTransactionRequest } from "../Models/AztecPublishTransactionRequest"; -import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/TreasuryClient"; +import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient"; import { AztecSignTransactionRequestModel } from "./Models/AztecSignTransactionModel"; import { buildLockKey as buildLockKey, buildCurrentNonceKey, buildNextNonceKey } from "../../Blockchain.Abstraction/Infrastructure/RedisHelper/RedisHelper"; import { NextNonceRequest } from "../../Blockchain.Abstraction/Models/NonceModels/NextNonceRequest"; diff --git a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts index 5e556314..c511cd63 100644 --- a/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Fuel/Activities/FuelBlockchainActivities.ts @@ -23,7 +23,7 @@ import { InvalidTimelockException } from "../../Blockchain.Abstraction/Exception import { inject, injectable } from "tsyringe"; import Redis from "ioredis"; import Redlock from "redlock"; -import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/TreasuryClient"; +import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient"; import { SignTransactionRequest } from "./Models/FuelSignTransactionModel"; import { TransactionFailedException } from "../../Blockchain.Abstraction/Exceptions/TransactionFailedException"; import { CurrentNonceRequest } from "../../Blockchain.Abstraction/Models/NonceModels/CurrentNonceRequest"; diff --git a/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts b/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts index 2b775b66..5c71b5c7 100644 --- a/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts +++ b/js/src/Blockchain/Blockchain.Starknet/Activities/StarknetBlockchainActivities.ts @@ -39,7 +39,7 @@ import { EnsureSufficientBalanceRequest } from "../Models/EnsureSufficientBalanc import { ComposeRawTransactionRequest, ComposeRawTransactionResponse } from "../Models/ComposeRawTxModels"; import { SignTransactionRequest } from "../Models/SignTransactionRequest"; import { sendInvocation } from "./Helper/Client"; -import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/TreasuryClient"; +import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient"; @injectable() export class StarknetBlockchainActivities implements IStarknetBlockchainActivities {