From 10bdd24e8a1ec3865813ce39a27b13ef2b67fb08 Mon Sep 17 00:00:00 2001 From: tomide Date: Fri, 13 Mar 2026 12:24:41 +0100 Subject: [PATCH 1/5] feat(sdk-provider-tron): add Tron ecosystem support Changes: - Add TronProvider with wallet integration, balance fetching, and address resolution - Add TronStepExecutor with sign, broadcast, and confirmation tasks - Add RPC retry with multi-URL fallback - Add Tron-specific error parsing for wallet and transaction errors - Add unit tests for error parsing, address resolution, and zero address utils - Register ChainType.TVM in SDK client storage --- packages/sdk-provider-tron/package.json | 102 ++++++ .../sdk-provider-tron/src/TronProvider.ts | 48 +++ .../src/actions/getTronBalance.ts | 81 +++++ .../src/actions/resolveTronAddress.ts | 4 + .../actions/resolveTronAddress.unit.spec.ts | 10 + .../src/core/TronStepExecutor.ts | 88 +++++ .../src/core/tasks/TronSignAndExecuteTask.ts | 53 +++ .../core/tasks/TronWaitForTransactionTask.ts | 106 ++++++ .../src/errors/parseTronErrors.ts | 83 +++++ .../src/errors/parseTronErrors.unit.spec.ts | 155 +++++++++ packages/sdk-provider-tron/src/index.ts | 4 + .../src/rpc/callTronRpcsWithRetry.ts | 25 ++ packages/sdk-provider-tron/src/types.ts | 40 +++ .../src/utils/isZeroAddress.ts | 5 + .../src/utils/isZeroAddress.unit.spec.ts | 18 + packages/sdk-provider-tron/tsconfig.json | 18 + packages/sdk/src/client/getClientStorage.ts | 1 + .../src/client/getClientStorage.unit.spec.ts | 1 + pnpm-lock.yaml | 320 +++++++++++++++--- 19 files changed, 1113 insertions(+), 49 deletions(-) create mode 100644 packages/sdk-provider-tron/package.json create mode 100644 packages/sdk-provider-tron/src/TronProvider.ts create mode 100644 packages/sdk-provider-tron/src/actions/getTronBalance.ts create mode 100644 packages/sdk-provider-tron/src/actions/resolveTronAddress.ts create mode 100644 packages/sdk-provider-tron/src/actions/resolveTronAddress.unit.spec.ts create mode 100644 packages/sdk-provider-tron/src/core/TronStepExecutor.ts create mode 100644 packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts create mode 100644 packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts create mode 100644 packages/sdk-provider-tron/src/errors/parseTronErrors.ts create mode 100644 packages/sdk-provider-tron/src/errors/parseTronErrors.unit.spec.ts create mode 100644 packages/sdk-provider-tron/src/index.ts create mode 100644 packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts create mode 100644 packages/sdk-provider-tron/src/types.ts create mode 100644 packages/sdk-provider-tron/src/utils/isZeroAddress.ts create mode 100644 packages/sdk-provider-tron/src/utils/isZeroAddress.unit.spec.ts create mode 100644 packages/sdk-provider-tron/tsconfig.json diff --git a/packages/sdk-provider-tron/package.json b/packages/sdk-provider-tron/package.json new file mode 100644 index 00000000..31f4c91b --- /dev/null +++ b/packages/sdk-provider-tron/package.json @@ -0,0 +1,102 @@ +{ + "name": "@lifi/sdk-provider-tron", + "version": "4.0.0-alpha.21", + "description": "LI.FI Tron SDK Provider for Any-to-Any Cross-Chain-Swap", + "homepage": "https://github.com/lifinance/sdk", + "bugs": { + "url": "https://github.com/lifinance/sdk/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/lifinance/sdk.git", + "directory": "packages/sdk-provider-tron" + }, + "license": "Apache-2.0", + "author": "Eugene Chybisov ", + "type": "module", + "sideEffects": false, + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/types/index.d.ts", + "typings": "./dist/types/index.d.ts", + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.js", + "default": "./dist/cjs/index.js" + }, + "./package.json": "./package.json" + }, + "scripts": { + "build": "pnpm clean && pnpm build:version && pnpm build:cjs && pnpm build:esm && pnpm build:types && pnpm build:clean", + "build:cjs": "tsc --project ./tsconfig.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && mkdir -p ./dist/cjs && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json", + "build:esm": "tsc --project ./tsconfig.json --outDir ./dist/esm && mkdir -p ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json", + "build:types": "tsc --project ./tsconfig.json --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", + "build:prerelease": "node ../../scripts/prerelease.js && cpy '../../*.md' .", + "build:postrelease": "node ../../scripts/postrelease.js && rm -rf *.md", + "build:clean": "rm -rf tsconfig.tsbuildinfo ./dist/tsconfig.tsbuildinfo", + "build:version": "node ../../scripts/version.js", + "clean": "pnpm build:clean && rm -rf dist", + "coverage": "vitest run --coverage", + "test": "vitest --run --dangerouslyIgnoreUnhandledErrors", + "test:cov": "pnpm test --coverage", + "test:unit": "pnpm test .unit.spec.ts --passWithNoTests", + "check:types": "tsc --noEmit", + "check:circular-deps": "madge --circular $(find ./src -name '*.ts')", + "check:circular-deps-graph": "madge --circular $(find ./src -name '*.ts') --image graph.svg", + "watch": "tsc -w -p ./tsconfig.json" + }, + "dependencies": { + "@lifi/sdk": "workspace:*", + "@tronweb3/tronwallet-abstract-adapter": "^1.1.10", + "tronweb": "^6.0.4" + }, + "devDependencies": { + "@vitest/coverage-v8": "^4.0.18", + "cpy-cli": "^7.0.0", + "madge": "^8.0.0", + "typescript": "^5.9.3", + "vitest": "^4.0.18" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "dist/**", + "!dist/**/*.tsbuildinfo", + "src/**/*.ts", + "!src/**/*.spec.ts", + "!src/**/*.test.ts", + "!src/**/*.mock.ts", + "!src/**/*.spec.ts", + "!src/**/*.handlers.ts", + "!src/**/*.tsbuildinfo", + "!**/__mocks__/**", + "!*.tmp", + "!*.env", + "!tsconfig.json" + ], + "keywords": [ + "swap", + "bridge", + "bridge-aggregation", + "cross-chain", + "cross-chain-applications", + "cross-chain-bridge", + "dapp", + "defi", + "ethereum", + "bitcoin", + "solana", + "sui", + "tron", + "lifi", + "multi-chain", + "sdk", + "ethers", + "viem", + "wagmi", + "web3", + "web3-react" + ] +} diff --git a/packages/sdk-provider-tron/src/TronProvider.ts b/packages/sdk-provider-tron/src/TronProvider.ts new file mode 100644 index 00000000..e5572f89 --- /dev/null +++ b/packages/sdk-provider-tron/src/TronProvider.ts @@ -0,0 +1,48 @@ +import { + ChainType, + LiFiErrorCode, + ProviderError, + type StepExecutorOptions, +} from '@lifi/sdk' +import { TronWeb } from 'tronweb' +import { getTronBalance } from './actions/getTronBalance.js' +import { resolveTronAddress } from './actions/resolveTronAddress.js' +import { TronStepExecutor } from './core/TronStepExecutor.js' +import type { TronProviderOptions, TronSDKProvider } from './types.js' + +export function TronProvider(options?: TronProviderOptions): TronSDKProvider { + const _options: TronProviderOptions = options ?? {} + return { + get type() { + return ChainType.TVM + }, + isAddress: (address: string) => TronWeb.isAddress(address), + resolveAddress: resolveTronAddress, + getBalance: getTronBalance, + async getStepExecutor( + options: StepExecutorOptions + ): Promise { + if (!_options.getWallet) { + throw new ProviderError( + LiFiErrorCode.ProviderUnavailable, + 'TronProvider requires a getWallet function.' + ) + } + + const wallet = await _options.getWallet() + + const executor = new TronStepExecutor({ + wallet, + routeId: options.routeId, + executionOptions: { + ...options.executionOptions, + }, + }) + + return executor + }, + setOptions(options: TronProviderOptions) { + Object.assign(_options, options) + }, + } +} diff --git a/packages/sdk-provider-tron/src/actions/getTronBalance.ts b/packages/sdk-provider-tron/src/actions/getTronBalance.ts new file mode 100644 index 00000000..8cefff5c --- /dev/null +++ b/packages/sdk-provider-tron/src/actions/getTronBalance.ts @@ -0,0 +1,81 @@ +import type { SDKClient, Token, TokenAmount } from '@lifi/sdk' +import { withDedupe } from '@lifi/sdk' +import { callTronRpcsWithRetry } from '../rpc/callTronRpcsWithRetry.js' +import { isZeroAddress } from '../utils/isZeroAddress.js' + +export const getTronBalance = async ( + client: SDKClient, + walletAddress: string, + tokens: Token[] +): Promise => { + if (tokens.length === 0) { + return [] + } + const { chainId } = tokens[0] + for (const token of tokens) { + if (token.chainId !== chainId) { + console.warn('Requested tokens have to be on the same chain.') + } + } + + return getTronBalanceDefault(client, tokens, walletAddress) +} + +const getTronBalanceDefault = async ( + client: SDKClient, + tokens: Token[], + walletAddress: string +): Promise => { + const [blockNumber, results] = await callTronRpcsWithRetry( + client, + async (tronWeb) => { + const host = tronWeb.fullNode.host + const queue: Promise[] = tokens.map((token) => { + if (isZeroAddress(token.address)) { + return withDedupe( + async () => BigInt(await tronWeb.trx.getBalance(walletAddress)), + { id: `${getTronBalanceDefault.name}.getBalance.${host}` } + ) + } + return withDedupe( + async () => { + const contract = await tronWeb.contract().at(token.address) + const balance = await contract.balanceOf(walletAddress).call() + return BigInt(balance.toString()) + }, + { + id: `${getTronBalanceDefault.name}.balanceOf.${token.address}.${host}`, + } + ) + }) + + return Promise.all([ + withDedupe( + async () => { + const block = await tronWeb.trx.getCurrentBlock() + return BigInt(block.block_header?.raw_data?.number ?? 0) + }, + { id: `${getTronBalanceDefault.name}.getCurrentBlock.${host}` } + ), + Promise.allSettled(queue), + ]) + } + ) + + const tokenAmounts: TokenAmount[] = tokens.map((token, index) => { + const result = results[index] + if (result.status === 'rejected') { + return { + ...token, + blockNumber, + } + } + return { + ...token, + amount: result.value, + blockNumber, + } + }) + + return tokenAmounts +} diff --git a/packages/sdk-provider-tron/src/actions/resolveTronAddress.ts b/packages/sdk-provider-tron/src/actions/resolveTronAddress.ts new file mode 100644 index 00000000..a345b7c4 --- /dev/null +++ b/packages/sdk-provider-tron/src/actions/resolveTronAddress.ts @@ -0,0 +1,4 @@ +export async function resolveTronAddress(name: string): Promise { + // Tron does not have a name service, return the address as-is + return name +} diff --git a/packages/sdk-provider-tron/src/actions/resolveTronAddress.unit.spec.ts b/packages/sdk-provider-tron/src/actions/resolveTronAddress.unit.spec.ts new file mode 100644 index 00000000..e1f7a853 --- /dev/null +++ b/packages/sdk-provider-tron/src/actions/resolveTronAddress.unit.spec.ts @@ -0,0 +1,10 @@ +import { describe, expect, it } from 'vitest' +import { resolveTronAddress } from './resolveTronAddress.js' + +describe('resolveTronAddress', () => { + it('should return the address as-is', async () => { + const address = 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8' + + expect(await resolveTronAddress(address)).toBe(address) + }) +}) diff --git a/packages/sdk-provider-tron/src/core/TronStepExecutor.ts b/packages/sdk-provider-tron/src/core/TronStepExecutor.ts new file mode 100644 index 00000000..17b8cc20 --- /dev/null +++ b/packages/sdk-provider-tron/src/core/TronStepExecutor.ts @@ -0,0 +1,88 @@ +import { + BaseStepExecutor, + CheckBalanceTask, + type ExecutionAction, + LiFiErrorCode, + type LiFiStepExtended, + PrepareTransactionTask, + type SDKError, + type StepExecutorBaseContext, + TaskPipeline, + TransactionError, + WaitForTransactionStatusTask, +} from '@lifi/sdk' +import type { Adapter } from '@tronweb3/tronwallet-abstract-adapter' +import { parseTronErrors } from '../errors/parseTronErrors.js' +import type { + TronStepExecutorContext, + TronStepExecutorOptions, +} from '../types.js' +import { TronSignAndExecuteTask } from './tasks/TronSignAndExecuteTask.js' +import { TronWaitForTransactionTask } from './tasks/TronWaitForTransactionTask.js' + +export class TronStepExecutor extends BaseStepExecutor { + private wallet: Adapter + + constructor(options: TronStepExecutorOptions) { + super(options) + this.wallet = options.wallet + } + + checkWallet = (step: LiFiStepExtended) => { + const address = this.wallet.address + if (address && address !== step.action.fromAddress) { + throw new TransactionError( + LiFiErrorCode.WalletChangedDuringExecution, + 'The wallet address that requested the quote does not match the wallet address attempting to sign the transaction.' + ) + } + } + + override parseErrors = ( + error: Error, + step?: LiFiStepExtended, + action?: ExecutionAction + ): Promise => parseTronErrors(error, step, action) + + override createContext = async ( + baseContext: StepExecutorBaseContext + ): Promise => { + return { + ...baseContext, + wallet: this.wallet, + checkWallet: this.checkWallet, + } + } + + override createPipeline = (context: TronStepExecutorContext) => { + const { step, isBridgeExecution } = context + + const tasks = [ + new CheckBalanceTask(), + new PrepareTransactionTask(), + new TronSignAndExecuteTask(), + new TronWaitForTransactionTask(), + new WaitForTransactionStatusTask( + isBridgeExecution ? 'RECEIVING_CHAIN' : 'SWAP' + ), + ] + + const swapOrBridgeAction = this.statusManager.findAction( + step, + isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP' + ) + + const taskName = + swapOrBridgeAction?.txHash && swapOrBridgeAction?.status === 'DONE' + ? WaitForTransactionStatusTask.name + : CheckBalanceTask.name + + const firstTaskIndex = tasks.findIndex( + (task) => task.constructor.name === taskName + ) + + const tasksToRun = tasks.slice(firstTaskIndex) + + return new TaskPipeline(tasksToRun) + } +} diff --git a/packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts new file mode 100644 index 00000000..3513f48c --- /dev/null +++ b/packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts @@ -0,0 +1,53 @@ +import { + BaseStepExecutionTask, + getTransactionRequestData, + LiFiErrorCode, + type TaskResult, + TransactionError, +} from '@lifi/sdk' +import type { TronStepExecutorContext } from '../../types.js' + +export class TronSignAndExecuteTask extends BaseStepExecutionTask { + async run(context: TronStepExecutorContext): Promise { + const { + step, + wallet, + statusManager, + executionOptions, + isBridgeExecution, + checkWallet, + } = context + + const action = statusManager.findAction( + step, + isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP' + ) + + if (!action) { + throw new TransactionError( + LiFiErrorCode.TransactionUnprepared, + 'Unable to prepare transaction. Action not found.' + ) + } + + const transactionRequestData = await getTransactionRequestData( + step, + executionOptions + ) + + checkWallet(step) + + const unsignedTransaction = JSON.parse(transactionRequestData) + + const signedTransaction = await wallet.signTransaction(unsignedTransaction) + + statusManager.updateAction(step, action.type, 'PENDING', { + signedAt: Date.now(), + }) + + return { + status: 'COMPLETED', + context: { signedTransaction }, + } + } +} diff --git a/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts new file mode 100644 index 00000000..55664f68 --- /dev/null +++ b/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts @@ -0,0 +1,106 @@ +import { + BaseStepExecutionTask, + LiFiErrorCode, + type SDKClient, + type TaskResult, + TransactionError, +} from '@lifi/sdk' +import type { TronWeb } from 'tronweb' +import { + callTronRpcsWithRetry, + getTronWebInstance, +} from '../../rpc/callTronRpcsWithRetry.js' +import type { TronStepExecutorContext } from '../../types.js' + +export class TronWaitForTransactionTask extends BaseStepExecutionTask { + async run(context: TronStepExecutorContext): Promise { + const { + client, + step, + statusManager, + fromChain, + isBridgeExecution, + signedTransaction, + } = context + + if (!signedTransaction) { + throw new TransactionError( + LiFiErrorCode.TransactionUnprepared, + 'Unable to prepare transaction. Signed transaction is not found.' + ) + } + + const action = statusManager.findAction( + step, + isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP' + ) + if (!action) { + throw new TransactionError( + LiFiErrorCode.TransactionUnprepared, + 'Unable to prepare transaction. Action not found.' + ) + } + + const tronWeb = await getTronWebInstance(client) + const broadcastResult = + await tronWeb.trx.sendRawTransaction(signedTransaction) + + if (!broadcastResult.result) { + throw new TransactionError( + LiFiErrorCode.TransactionFailed, + `Transaction broadcast failed: ${broadcastResult.code || 'Unknown error'}` + ) + } + + const txHash = broadcastResult.transaction.txID + + statusManager.updateAction(step, action.type, 'PENDING', { + txHash, + txLink: `${fromChain.metamask.blockExplorerUrls[0]}#/transaction/${txHash}`, + }) + + await waitForTronConfirmation(client, txHash) + + if (isBridgeExecution) { + statusManager.updateAction(step, action.type, 'DONE') + } + + return { status: 'COMPLETED' } + } +} + +async function waitForTronConfirmation( + client: SDKClient, + txHash: string, + maxRetries = 20, + intervalMs = 3000 +): Promise { + for (let i = 0; i < maxRetries; i++) { + try { + const txInfo = await callTronRpcsWithRetry(client, (tronWeb: TronWeb) => + tronWeb.trx.getTransactionInfo(txHash) + ) + + if (txInfo?.id) { + if (txInfo.receipt?.result === 'FAILED') { + throw new TransactionError( + LiFiErrorCode.TransactionFailed, + `Transaction failed on-chain: ${txInfo.receipt.result}` + ) + } + return + } + } catch (error) { + if (error instanceof TransactionError) { + throw error + } + // Transaction info not yet available, continue polling + } + await new Promise((resolve) => setTimeout(resolve, intervalMs)) + } + + throw new TransactionError( + LiFiErrorCode.TransactionFailed, + 'Transaction confirmation timeout.' + ) +} diff --git a/packages/sdk-provider-tron/src/errors/parseTronErrors.ts b/packages/sdk-provider-tron/src/errors/parseTronErrors.ts new file mode 100644 index 00000000..325a2715 --- /dev/null +++ b/packages/sdk-provider-tron/src/errors/parseTronErrors.ts @@ -0,0 +1,83 @@ +import { + BaseError, + ErrorMessage, + type ExecutionAction, + LiFiErrorCode, + type LiFiStep, + SDKError, + TransactionError, + UnknownError, +} from '@lifi/sdk' +import { + WalletDisconnectedError, + WalletNotFoundError, + WalletNotSelectedError, + WalletSignTransactionError, + WalletWindowClosedError, +} from '@tronweb3/tronwallet-abstract-adapter' + +export const parseTronErrors = async ( + e: Error, + step?: LiFiStep, + action?: ExecutionAction +): Promise => { + if (e instanceof SDKError) { + e.step = e.step ?? step + e.action = e.action ?? action + return e + } + + const baseError = handleSpecificErrors(e) + + return new SDKError(baseError, step, action) +} + +const handleSpecificErrors = (e: any) => { + const message: string = typeof e === 'string' ? e : e.message || '' + + if ( + e instanceof WalletSignTransactionError || + e instanceof WalletWindowClosedError + ) { + return new TransactionError(LiFiErrorCode.SignatureRejected, message, e) + } + + if ( + e instanceof WalletNotFoundError || + e instanceof WalletNotSelectedError || + e instanceof WalletDisconnectedError + ) { + return new TransactionError( + LiFiErrorCode.WalletChangedDuringExecution, + message, + e + ) + } + + // TronWeb trx.sign() validation errors + if ( + message === 'Invalid transaction provided' || + message === 'Invalid transaction' || + message === 'Transaction is not signed' + ) { + return new TransactionError(LiFiErrorCode.TransactionUnprepared, message, e) + } + + if (message === 'Transaction is already signed') { + return new TransactionError(LiFiErrorCode.TransactionFailed, message, e) + } + + if (message === 'Private key does not match address in transaction') { + return new TransactionError( + LiFiErrorCode.WalletChangedDuringExecution, + message, + e + ) + } + + if (e instanceof BaseError) { + return e + } + + return new UnknownError(message || ErrorMessage.UnknownError, e) +} diff --git a/packages/sdk-provider-tron/src/errors/parseTronErrors.unit.spec.ts b/packages/sdk-provider-tron/src/errors/parseTronErrors.unit.spec.ts new file mode 100644 index 00000000..c2b75137 --- /dev/null +++ b/packages/sdk-provider-tron/src/errors/parseTronErrors.unit.spec.ts @@ -0,0 +1,155 @@ +import { + BaseError, + ErrorName, + LiFiErrorCode, + SDKError, + TransactionError, + UnknownError, +} from '@lifi/sdk' +import { + WalletDisconnectedError, + WalletNotFoundError, + WalletNotSelectedError, + WalletSignTransactionError, + WalletWindowClosedError, +} from '@tronweb3/tronwallet-abstract-adapter' +import { describe, expect, it } from 'vitest' +import { parseTronErrors } from './parseTronErrors.js' + +describe('parseTronErrors', () => { + it('should return SDKError as-is', async () => { + const error = new SDKError( + new BaseError( + ErrorName.UnknownError, + LiFiErrorCode.InternalError, + 'error' + ) + ) + + const result = await parseTronErrors(error) + + expect(result).toBe(error) + }) + + it('should handle WalletSignTransactionError', async () => { + const error = new WalletSignTransactionError() + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.SignatureRejected) + }) + + it('should handle WalletWindowClosedError', async () => { + const error = new WalletWindowClosedError() + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.SignatureRejected) + }) + + it('should handle WalletNotFoundError', async () => { + const error = new WalletNotFoundError() + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.WalletChangedDuringExecution) + }) + + it('should handle WalletNotSelectedError', async () => { + const error = new WalletNotSelectedError() + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.WalletChangedDuringExecution) + }) + + it('should handle WalletDisconnectedError', async () => { + const error = new WalletDisconnectedError() + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.WalletChangedDuringExecution) + }) + + it('should handle "Invalid transaction provided"', async () => { + const error = new Error('Invalid transaction provided') + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.TransactionUnprepared) + }) + + it('should handle "Invalid transaction"', async () => { + const error = new Error('Invalid transaction') + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.TransactionUnprepared) + }) + + it('should handle "Transaction is not signed"', async () => { + const error = new Error('Transaction is not signed') + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.TransactionUnprepared) + }) + + it('should handle "Transaction is already signed"', async () => { + const error = new Error('Transaction is already signed') + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.TransactionFailed) + }) + + it('should handle "Private key does not match address in transaction"', async () => { + const error = new Error('Private key does not match address in transaction') + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(TransactionError) + expect(result.cause.code).toBe(LiFiErrorCode.WalletChangedDuringExecution) + }) + + it('should handle BaseError as-is', async () => { + const error = new BaseError( + ErrorName.TransactionError, + LiFiErrorCode.TransactionFailed, + 'base error' + ) + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBe(error) + }) + + it('should handle generic Error as UnknownError', async () => { + const error = new Error('Something unexpected') + + const result = await parseTronErrors(error) + + expect(result).toBeInstanceOf(SDKError) + expect(result.cause).toBeInstanceOf(UnknownError) + }) +}) diff --git a/packages/sdk-provider-tron/src/index.ts b/packages/sdk-provider-tron/src/index.ts new file mode 100644 index 00000000..ff81930e --- /dev/null +++ b/packages/sdk-provider-tron/src/index.ts @@ -0,0 +1,4 @@ +// biome-ignore lint/performance/noBarrelFile: module entrypoint +export { TronProvider } from './TronProvider.js' +export type { TronProviderOptions, TronSDKProvider } from './types.js' +export { isTronProvider } from './types.js' diff --git a/packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts b/packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts new file mode 100644 index 00000000..10b0e8cf --- /dev/null +++ b/packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts @@ -0,0 +1,25 @@ +import { ChainId, type SDKClient } from '@lifi/sdk' +import { TronWeb } from 'tronweb' + +export async function getTronWebInstance(client: SDKClient): Promise { + const urls = await client.getRpcUrlsByChainId(ChainId.TRN) + return new TronWeb({ fullHost: urls[0] }) +} + +export async function callTronRpcsWithRetry( + client: SDKClient, + fn: (tronWeb: TronWeb) => Promise +): Promise { + const urls = await client.getRpcUrlsByChainId(ChainId.TRN) + + const errors: Error[] = [] + for (const url of urls) { + try { + return await fn(new TronWeb({ fullHost: url })) + } catch (error) { + errors.push(error instanceof Error ? error : new Error(String(error))) + } + } + + throw new AggregateError(errors, `All ${urls.length} Tron RPCs failed`) +} diff --git a/packages/sdk-provider-tron/src/types.ts b/packages/sdk-provider-tron/src/types.ts new file mode 100644 index 00000000..cc1d8e9f --- /dev/null +++ b/packages/sdk-provider-tron/src/types.ts @@ -0,0 +1,40 @@ +import { + ChainType, + type LiFiStepExtended, + type SDKProvider, + type StepExecutorContext, + type StepExecutorOptions, +} from '@lifi/sdk' +import type { + Adapter, + SignedTransaction, +} from '@tronweb3/tronwallet-abstract-adapter' + +export interface TronProviderOptions { + getWallet?: () => Promise +} + +export interface TronTaskContext { + signedTransaction?: SignedTransaction +} + +export interface TronStepExecutorContext + extends StepExecutorContext, + TronTaskContext { + wallet: Adapter + checkWallet: (step: LiFiStepExtended) => void +} + +export interface TronSDKProvider extends SDKProvider { + setOptions(options: TronProviderOptions): void +} + +export function isTronProvider( + provider: SDKProvider +): provider is TronSDKProvider { + return provider.type === ChainType.TVM +} + +export interface TronStepExecutorOptions extends StepExecutorOptions { + wallet: Adapter +} diff --git a/packages/sdk-provider-tron/src/utils/isZeroAddress.ts b/packages/sdk-provider-tron/src/utils/isZeroAddress.ts new file mode 100644 index 00000000..b5e4fe40 --- /dev/null +++ b/packages/sdk-provider-tron/src/utils/isZeroAddress.ts @@ -0,0 +1,5 @@ +export const AddressZero = '0x0000000000000000000000000000000000000000' +export const TronAddressZero = 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb' + +export const isZeroAddress = (address: string): boolean => + address === AddressZero || address === TronAddressZero diff --git a/packages/sdk-provider-tron/src/utils/isZeroAddress.unit.spec.ts b/packages/sdk-provider-tron/src/utils/isZeroAddress.unit.spec.ts new file mode 100644 index 00000000..ea2ae72a --- /dev/null +++ b/packages/sdk-provider-tron/src/utils/isZeroAddress.unit.spec.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from 'vitest' +import { isZeroAddress } from './isZeroAddress.js' + +describe('isZeroAddress', () => { + it('should return true for EVM zero address', () => { + expect(isZeroAddress('0x0000000000000000000000000000000000000000')).toBe( + true + ) + }) + + it('should return true for Tron zero address', () => { + expect(isZeroAddress('T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb')).toBe(true) + }) + + it('should return false for a valid address', () => { + expect(isZeroAddress('TJRabPrwbZy45sbavfcjinPJC18kjpRTv8')).toBe(false) + }) +}) diff --git a/packages/sdk-provider-tron/tsconfig.json b/packages/sdk-provider-tron/tsconfig.json new file mode 100644 index 00000000..238d18de --- /dev/null +++ b/packages/sdk-provider-tron/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", + "composite": true, + "sourceMap": true, + "rootDir": "./src", + "moduleResolution": "Node", + "outDir": "./dist" + }, + "include": ["./src/**/*", "./src/**/*.json"], + "exclude": [ + "tests", + "./src/**/*.spec.ts", + "./src/**/*.mock.ts", + "./src/**/*.handlers.ts" + ] +} diff --git a/packages/sdk/src/client/getClientStorage.ts b/packages/sdk/src/client/getClientStorage.ts index 85ad3593..c3fa81e1 100644 --- a/packages/sdk/src/client/getClientStorage.ts +++ b/packages/sdk/src/client/getClientStorage.ts @@ -49,6 +49,7 @@ export const getClientStorage = (config: SDKBaseConfig): ClientStorage => { ChainType.SVM, ChainType.UTXO, ChainType.MVM, + ChainType.TVM, ], }) _chainsUpdatedAt = Date.now() diff --git a/packages/sdk/src/client/getClientStorage.unit.spec.ts b/packages/sdk/src/client/getClientStorage.unit.spec.ts index b214c232..73bdcd6d 100644 --- a/packages/sdk/src/client/getClientStorage.unit.spec.ts +++ b/packages/sdk/src/client/getClientStorage.unit.spec.ts @@ -159,6 +159,7 @@ describe('getClientStorage', () => { ChainType.SVM, ChainType.UTXO, ChainType.MVM, + ChainType.TVM, ], }) expect(chains).toEqual(mockChains) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ced597ea..3c1511fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,7 +49,7 @@ importers: dependencies: '@lifi/types': specifier: 17.68.1 - version: 17.68.1(typescript@5.9.3) + version: 17.68.1(typescript@5.9.3)(zod@4.3.6) devDependencies: '@lifi/data-types': specifier: ^6.69.0 @@ -200,6 +200,34 @@ importers: specifier: ^4.1.0 version: 4.1.0(@types/node@25.5.0)(jiti@2.6.1)(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(yaml@2.8.3) + packages/sdk-provider-tron: + dependencies: + '@lifi/sdk': + specifier: workspace:* + version: link:../sdk + '@tronweb3/tronwallet-abstract-adapter': + specifier: ^1.1.10 + version: 1.1.10 + tronweb: + specifier: ^6.0.4 + version: 6.2.1 + devDependencies: + '@vitest/coverage-v8': + specifier: ^4.0.18 + version: 4.1.0(vitest@4.1.0(@types/node@25.5.0)(jiti@2.6.1)(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(yaml@2.8.3)) + cpy-cli: + specifier: ^7.0.0 + version: 7.0.0 + madge: + specifier: ^8.0.0 + version: 8.0.0(typescript@5.9.3) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vitest: + specifier: ^4.0.18 + version: 4.1.0(@types/node@25.5.0)(jiti@2.6.1)(msw@2.12.14(@types/node@25.5.0)(typescript@5.9.3))(yaml@2.8.3) + packages: '@0no-co/graphql.web@1.2.0': @@ -216,6 +244,9 @@ packages: graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 typescript: ^5.0.0 + '@adraffy/ens-normalize@1.10.1': + resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} + '@adraffy/ens-normalize@1.11.1': resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} @@ -253,6 +284,10 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + '@babel/runtime@7.26.10': + resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} + engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} @@ -660,6 +695,12 @@ packages: resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} + '@noble/curves@1.2.0': + resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + + '@noble/curves@1.4.2': + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} + '@noble/curves@1.9.1': resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} engines: {node: ^14.21.3 || >=16} @@ -672,6 +713,14 @@ packages: resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} engines: {node: '>= 20.19.0'} + '@noble/hashes@1.3.2': + resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} + engines: {node: '>= 16'} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -1354,18 +1403,27 @@ packages: '@rolldown/pluginutils@1.0.0-rc.9': resolution: {integrity: sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==} + '@scure/base@1.1.9': + resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} + '@scure/base@1.2.6': resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} '@scure/base@2.0.0': resolution: {integrity: sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==} + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + '@scure/bip32@1.7.0': resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} '@scure/bip32@2.0.1': resolution: {integrity: sha512-4Md1NI5BzoVP+bhyJaY3K6yMesEFzNS1sE/cP+9nuvE7p/b0kx9XbpDHHFl8dHtufcbdHRUUQdRqLIPHN/s7yA==} + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + '@scure/bip39@1.6.0': resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} @@ -1791,6 +1849,10 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tronweb3/tronwallet-abstract-adapter@1.1.10': + resolution: {integrity: sha512-gZExaEZwPfI9oI7qSi56p/5Zl/DEzo1JlcD3lQzz1cuz0rZmEFpIqDS2mhY4r/IwEPwilIU7lg7T8/RQDVk9gA==} + engines: {node: '>=16', pnpm: '>=7'} + '@ts-graphviz/adapter@2.0.6': resolution: {integrity: sha512-kJ10lIMSWMJkLkkCG5gt927SnGZcBuG0s0HHswGzcHTgvtUe7yk5/3zTEr0bafzsodsOq5Gi6FhQeV775nC35Q==} engines: {node: '>=18'} @@ -1836,6 +1898,9 @@ packages: '@types/minimist@1.2.5': resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@types/node@22.7.5': + resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@25.5.0': resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} @@ -1912,20 +1977,20 @@ packages: '@vitest/utils@4.1.0': resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} - '@vue/compiler-core@3.5.30': - resolution: {integrity: sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==} + '@vue/compiler-core@3.5.29': + resolution: {integrity: sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw==} - '@vue/compiler-dom@3.5.30': - resolution: {integrity: sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==} + '@vue/compiler-dom@3.5.29': + resolution: {integrity: sha512-n0G5o7R3uBVmVxjTIYcz7ovr8sy7QObFG8OQJ3xGCDNhbG60biP/P5KnyY8NLd81OuT1WJflG7N4KWYHaeeaIg==} - '@vue/compiler-sfc@3.5.30': - resolution: {integrity: sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==} + '@vue/compiler-sfc@3.5.29': + resolution: {integrity: sha512-oJZhN5XJs35Gzr50E82jg2cYdZQ78wEwvRO6Y63TvLVTc+6xICzJHP1UIecdSPPYIbkautNBanDiWYa64QSFIA==} - '@vue/compiler-ssr@3.5.30': - resolution: {integrity: sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==} + '@vue/compiler-ssr@3.5.29': + resolution: {integrity: sha512-Y/ARJZE6fpjzL5GH/phJmsFwx3g6t2KmHKHx5q+MLl2kencADKIrhH5MLF6HHpRMmlRAYBRSvv347Mepf1zVNw==} - '@vue/shared@3.5.30': - resolution: {integrity: sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==} + '@vue/shared@3.5.29': + resolution: {integrity: sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==} '@wallet-standard/base@1.1.0': resolution: {integrity: sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==} @@ -1972,6 +2037,9 @@ packages: add-stream@1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} + aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -2050,6 +2118,9 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + axios@1.13.5: + resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} + axios@1.13.6: resolution: {integrity: sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==} @@ -2072,6 +2143,9 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + bin-links@5.0.0: resolution: {integrity: sha512-sdleLVfCjBtgO5cNjA2HVRvWBJAHs4zwenaCPMNJAJU0yNxpzj80IpjOIimkpkr+mhlA+how5poQtt53PygbHA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -2688,6 +2762,13 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + ethereum-cryptography@2.2.1: + resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} + + ethers@6.13.5: + resolution: {integrity: sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==} + engines: {node: '>=14.0.0'} + eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -2917,6 +2998,9 @@ packages: engines: {node: '>=0.6.0'} hasBin: true + google-protobuf@3.21.4: + resolution: {integrity: sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -4020,7 +4104,6 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} deprecated: |- You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. - (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) quansync@1.0.0: @@ -4082,6 +4165,9 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4203,6 +4289,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} @@ -4459,6 +4550,9 @@ packages: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} + tronweb@6.2.1: + resolution: {integrity: sha512-qDzdz5Qzuc9dfxYzo6yodfwtoIL+C/h1l3HbzwYJwNGgaj/owbzlLROjrlF/3Py7gO8QbTD0v4GuPQRJ1ZzseA==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -4501,6 +4595,9 @@ packages: unplugin-unused: optional: true + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -4552,6 +4649,9 @@ packages: unconfig-core@7.5.0: resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} @@ -4604,6 +4704,10 @@ packages: resolution: {integrity: sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==} engines: {node: ^18.17.0 || >=20.5.0} + validator@13.15.23: + resolution: {integrity: sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==} + engines: {node: '>= 0.10'} + varuint-bitcoin@2.0.0: resolution: {integrity: sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==} @@ -4748,6 +4852,18 @@ packages: resolution: {integrity: sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==} engines: {node: ^18.17.0 || >=20.5.0} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + 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 + ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} @@ -4849,6 +4965,8 @@ snapshots: graphql: 16.13.1 typescript: 5.9.3 + '@adraffy/ens-normalize@1.10.1': {} + '@adraffy/ens-normalize@1.11.1': {} '@babel/code-frame@7.29.0': @@ -4882,6 +5000,10 @@ snapshots: dependencies: '@babel/types': 8.0.0-rc.2 + '@babel/runtime@7.26.10': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -5282,7 +5404,7 @@ snapshots: - utf-8-validate - zod - '@lifi/types@17.68.1(typescript@5.9.3)': + '@lifi/types@17.68.1(typescript@5.9.3)(zod@4.3.6)': dependencies: viem: 2.47.6(typescript@5.9.3)(zod@4.3.6) transitivePeerDependencies: @@ -5348,6 +5470,14 @@ snapshots: '@noble/ciphers@1.3.0': {} + '@noble/curves@1.2.0': + dependencies: + '@noble/hashes': 1.3.2 + + '@noble/curves@1.4.2': + dependencies: + '@noble/hashes': 1.4.0 + '@noble/curves@1.9.1': dependencies: '@noble/hashes': 1.8.0 @@ -5360,6 +5490,10 @@ snapshots: dependencies: '@noble/hashes': 2.0.1 + '@noble/hashes@1.3.2': {} + + '@noble/hashes@1.4.0': {} + '@noble/hashes@1.8.0': {} '@noble/hashes@2.0.1': {} @@ -5417,7 +5551,7 @@ snapshots: proggy: 3.0.0 promise-all-reject-late: 1.0.1 promise-call-limit: 3.0.2 - semver: 7.7.2 + semver: 7.7.4 ssri: 12.0.0 treeverse: 3.0.0 walk-up-path: 4.0.0 @@ -5426,11 +5560,11 @@ snapshots: '@npmcli/fs@4.0.0': dependencies: - semver: 7.7.2 + semver: 7.7.4 '@npmcli/fs@5.0.0': dependencies: - semver: 7.7.2 + semver: 7.7.4 '@npmcli/git@6.0.3': dependencies: @@ -5440,7 +5574,7 @@ snapshots: npm-pick-manifest: 10.0.0 proc-log: 5.0.0 promise-retry: 2.0.1 - semver: 7.7.2 + semver: 7.7.4 which: 5.0.0 '@npmcli/git@7.0.2': @@ -5451,7 +5585,7 @@ snapshots: lru-cache: 11.2.7 npm-pick-manifest: 11.0.3 proc-log: 6.1.0 - semver: 7.7.2 + semver: 7.7.4 which: 6.0.1 '@npmcli/installed-package-contents@3.0.0': @@ -5477,7 +5611,7 @@ snapshots: json-parse-even-better-errors: 5.0.0 pacote: 21.5.0 proc-log: 6.1.0 - semver: 7.7.2 + semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -5496,7 +5630,7 @@ snapshots: hosted-git-info: 9.0.2 json-parse-even-better-errors: 5.0.0 proc-log: 6.1.0 - semver: 7.7.2 + semver: 7.7.4 validate-npm-package-license: 3.0.4 '@npmcli/promise-spawn@8.0.3': @@ -5533,7 +5667,7 @@ snapshots: enquirer: 2.3.6 minimatch: 10.2.4 nx: 22.6.1 - semver: 7.7.2 + semver: 7.7.4 tslib: 2.8.1 yargs-parser: 21.1.1 @@ -5884,10 +6018,18 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.9': {} + '@scure/base@1.1.9': {} + '@scure/base@1.2.6': {} '@scure/base@2.0.0': {} + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + '@scure/bip32@1.7.0': dependencies: '@noble/curves': 1.9.1 @@ -5900,6 +6042,11 @@ snapshots: '@noble/hashes': 2.0.1 '@scure/base': 2.0.0 + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + '@scure/bip39@1.6.0': dependencies: '@noble/hashes': 1.8.0 @@ -6417,6 +6564,15 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@tronweb3/tronwallet-abstract-adapter@1.1.10': + dependencies: + eventemitter3: 4.0.7 + tronweb: 6.2.1 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + '@ts-graphviz/adapter@2.0.6': dependencies: '@ts-graphviz/common': 2.1.5 @@ -6461,6 +6617,10 @@ snapshots: '@types/minimist@1.2.5': {} + '@types/node@22.7.5': + dependencies: + undici-types: 6.19.8 + '@types/node@25.5.0': dependencies: undici-types: 7.18.2 @@ -6564,37 +6724,37 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@vue/compiler-core@3.5.30': + '@vue/compiler-core@3.5.29': dependencies: '@babel/parser': 7.29.2 - '@vue/shared': 3.5.30 + '@vue/shared': 3.5.29 entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.30': + '@vue/compiler-dom@3.5.29': dependencies: - '@vue/compiler-core': 3.5.30 - '@vue/shared': 3.5.30 + '@vue/compiler-core': 3.5.29 + '@vue/shared': 3.5.29 - '@vue/compiler-sfc@3.5.30': + '@vue/compiler-sfc@3.5.29': dependencies: '@babel/parser': 7.29.2 - '@vue/compiler-core': 3.5.30 - '@vue/compiler-dom': 3.5.30 - '@vue/compiler-ssr': 3.5.30 - '@vue/shared': 3.5.30 + '@vue/compiler-core': 3.5.29 + '@vue/compiler-dom': 3.5.29 + '@vue/compiler-ssr': 3.5.29 + '@vue/shared': 3.5.29 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.8 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.30': + '@vue/compiler-ssr@3.5.29': dependencies: - '@vue/compiler-dom': 3.5.30 - '@vue/shared': 3.5.30 + '@vue/compiler-dom': 3.5.29 + '@vue/shared': 3.5.29 - '@vue/shared@3.5.30': {} + '@vue/shared@3.5.29': {} '@wallet-standard/base@1.1.0': {} @@ -6629,6 +6789,8 @@ snapshots: add-stream@1.0.0: {} + aes-js@4.0.0-beta.5: {} + agent-base@7.1.4: {} aggregate-error@3.1.0: @@ -6695,6 +6857,14 @@ snapshots: asynckit@0.4.0: {} + axios@1.13.5: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axios@1.13.6: dependencies: follow-redirects: 1.15.11 @@ -6715,6 +6885,8 @@ snapshots: before-after-hook@2.2.3: {} + bignumber.js@9.1.2: {} + bin-links@5.0.0: dependencies: cmd-shim: 7.0.0 @@ -7028,7 +7200,7 @@ snapshots: handlebars: 4.7.8 json-stringify-safe: 5.0.1 meow: 8.1.2 - semver: 7.7.2 + semver: 7.7.4 split: 1.0.1 conventional-changelog@3.1.25: @@ -7248,7 +7420,7 @@ snapshots: detective-vue2@2.2.0(typescript@5.9.3): dependencies: '@dependents/detective-less': 5.0.1 - '@vue/compiler-sfc': 3.5.30 + '@vue/compiler-sfc': 3.5.29 detective-es6: 5.0.1 detective-sass: 6.0.1 detective-scss: 5.0.1 @@ -7364,6 +7536,26 @@ snapshots: esutils@2.0.3: {} + ethereum-cryptography@2.2.1: + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + + ethers@6.13.5: + dependencies: + '@adraffy/ens-normalize': 1.10.1 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.2 + '@types/node': 22.7.5 + aes-js: 4.0.0-beta.5 + tslib: 2.7.0 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + eventemitter3@4.0.7: {} eventemitter3@5.0.1: {} @@ -7571,7 +7763,7 @@ snapshots: git-semver-tags@5.0.1: dependencies: meow: 8.1.2 - semver: 7.7.2 + semver: 7.7.4 git-up@7.0.0: dependencies: @@ -7626,6 +7818,8 @@ snapshots: dependencies: minimist: 1.2.8 + google-protobuf@3.21.4: {} + gopd@1.2.0: {} gql.tada@1.9.0(graphql@16.13.1)(typescript@5.9.3): @@ -7762,7 +7956,7 @@ snapshots: npm-package-arg: 13.0.1 promzard: 2.0.0 read: 4.1.0 - semver: 7.7.2 + semver: 7.7.4 validate-npm-package-license: 3.0.4 validate-npm-package-name: 6.0.2 @@ -8039,7 +8233,7 @@ snapshots: npm-package-arg: 13.0.1 npm-registry-fetch: 19.1.0 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.4 sigstore: 4.1.0 ssri: 12.0.0 transitivePeerDependencies: @@ -8394,7 +8588,7 @@ snapshots: make-fetch-happen: 15.0.2 nopt: 9.0.0 proc-log: 6.1.0 - semver: 7.7.2 + semver: 7.7.4 tar: 7.5.11 tinyglobby: 0.2.12 which: 6.0.1 @@ -8424,7 +8618,7 @@ snapshots: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.16.1 - semver: 7.7.2 + semver: 7.7.4 validate-npm-package-license: 3.0.4 npm-bundled@4.0.0: @@ -8437,11 +8631,11 @@ snapshots: npm-install-checks@7.1.2: dependencies: - semver: 7.7.2 + semver: 7.7.4 npm-install-checks@8.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.4 npm-normalize-package-bin@4.0.0: {} @@ -8451,14 +8645,14 @@ snapshots: dependencies: hosted-git-info: 8.1.0 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.4 validate-npm-package-name: 6.0.2 npm-package-arg@13.0.1: dependencies: hosted-git-info: 9.0.2 proc-log: 5.0.0 - semver: 7.7.2 + semver: 7.7.4 validate-npm-package-name: 6.0.2 npm-packlist@10.0.3: @@ -8471,14 +8665,14 @@ snapshots: npm-install-checks: 7.1.2 npm-normalize-package-bin: 4.0.0 npm-package-arg: 12.0.2 - semver: 7.7.2 + semver: 7.7.4 npm-pick-manifest@11.0.3: dependencies: npm-install-checks: 8.0.0 npm-normalize-package-bin: 5.0.0 npm-package-arg: 13.0.1 - semver: 7.7.2 + semver: 7.7.4 npm-registry-fetch@19.1.0: dependencies: @@ -8525,7 +8719,7 @@ snapshots: ora: 5.3.0 picocolors: 1.1.1 resolve.exports: 2.0.3 - semver: 7.7.2 + semver: 7.7.4 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.5 @@ -8984,6 +9178,8 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 + regenerator-runtime@0.14.1: {} + require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -9110,6 +9306,8 @@ snapshots: semver@6.3.1: {} + semver@7.7.1: {} + semver@7.7.2: {} semver@7.7.4: {} @@ -9348,6 +9546,22 @@ snapshots: trim-newlines@3.0.1: {} + tronweb@6.2.1: + dependencies: + '@babel/runtime': 7.26.10 + axios: 1.13.5 + bignumber.js: 9.1.2 + ethereum-cryptography: 2.2.1 + ethers: 6.13.5 + eventemitter3: 5.0.1 + google-protobuf: 3.21.4 + semver: 7.7.1 + validator: 13.15.23 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -9392,6 +9606,8 @@ snapshots: - synckit - vue-tsc + tslib@2.7.0: {} + tslib@2.8.1: {} tuf-js@4.1.0: @@ -9430,6 +9646,8 @@ snapshots: '@quansync/fs': 1.0.0 quansync: 1.0.0 + undici-types@6.19.8: {} + undici-types@7.18.2: {} undici-types@7.24.5: {} @@ -9461,6 +9679,8 @@ snapshots: validate-npm-package-name@6.0.2: {} + validator@13.15.23: {} + varuint-bitcoin@2.0.0: dependencies: uint8array-tools: 0.0.8 @@ -9588,6 +9808,8 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@8.17.1: {} + ws@8.18.3: {} ws@8.20.0: {} From 2d39fcc8480d31d880f76ae2800b3a196741c42f Mon Sep 17 00:00:00 2001 From: tomide Date: Mon, 16 Mar 2026 12:50:37 +0000 Subject: [PATCH 2/5] fix(sdk-provider-sui): use ESM for main and default exports --- packages/sdk-provider-sui/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sdk-provider-sui/package.json b/packages/sdk-provider-sui/package.json index 06b7aa23..1cb73028 100644 --- a/packages/sdk-provider-sui/package.json +++ b/packages/sdk-provider-sui/package.json @@ -15,7 +15,7 @@ "author": "Eugene Chybisov ", "type": "module", "sideEffects": false, - "main": "./dist/cjs/index.js", + "main": "./dist/esm/index.js", "module": "./dist/esm/index.js", "types": "./dist/esm/index.d.ts", "typings": "./dist/esm/index.d.ts", @@ -23,7 +23,7 @@ ".": { "types": "./dist/esm/index.d.ts", "import": "./dist/esm/index.js", - "default": "./dist/cjs/index.js" + "default": "./dist/esm/index.js" }, "./package.json": "./package.json" }, From 8ab1265652c071a6b1b9b3af22b15787388daea5 Mon Sep 17 00:00:00 2001 From: tomide Date: Mon, 16 Mar 2026 12:51:14 +0000 Subject: [PATCH 3/5] feat(sdk-provider-tron): add allowance tasks and improve tx handling - Add TronCheckAllowanceTask and TronSetAllowanceTask for TRC-20 approval flow - Refactor TronSignAndExecuteTask to deserialize raw tx data from the API - Separate build, sign, and broadcast phases in approval to avoid re-signing on RPC retry - Add bandwidth error handling in parseTronErrors - Add stripHexPrefix utility and shared polling constants - Pass `from` address in TRC-20 balanceOf calls --- .../src/actions/getTronBalance.ts | 4 +- .../src/core/TronStepExecutor.ts | 26 +++- .../sdk-provider-tron/src/core/constants.ts | 2 + .../src/core/tasks/TronCheckAllowanceTask.ts | 61 ++++++++ .../src/core/tasks/TronSetAllowanceTask.ts | 131 ++++++++++++++++++ .../src/core/tasks/TronSignAndExecuteTask.ts | 50 +++++-- .../core/tasks/TronWaitForTransactionTask.ts | 8 +- .../src/errors/parseTronErrors.ts | 20 +++ packages/sdk-provider-tron/src/types.ts | 1 + .../src/utils/stripHexPrefix.ts | 2 + packages/sdk-provider-tron/src/version.ts | 2 + 11 files changed, 284 insertions(+), 23 deletions(-) create mode 100644 packages/sdk-provider-tron/src/core/constants.ts create mode 100644 packages/sdk-provider-tron/src/core/tasks/TronCheckAllowanceTask.ts create mode 100644 packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts create mode 100644 packages/sdk-provider-tron/src/utils/stripHexPrefix.ts create mode 100644 packages/sdk-provider-tron/src/version.ts diff --git a/packages/sdk-provider-tron/src/actions/getTronBalance.ts b/packages/sdk-provider-tron/src/actions/getTronBalance.ts index 8cefff5c..606e958c 100644 --- a/packages/sdk-provider-tron/src/actions/getTronBalance.ts +++ b/packages/sdk-provider-tron/src/actions/getTronBalance.ts @@ -40,7 +40,9 @@ const getTronBalanceDefault = async ( return withDedupe( async () => { const contract = await tronWeb.contract().at(token.address) - const balance = await contract.balanceOf(walletAddress).call() + const balance = await contract + .balanceOf(walletAddress) + .call({ from: walletAddress }) return BigInt(balance.toString()) }, { diff --git a/packages/sdk-provider-tron/src/core/TronStepExecutor.ts b/packages/sdk-provider-tron/src/core/TronStepExecutor.ts index 17b8cc20..21c716d1 100644 --- a/packages/sdk-provider-tron/src/core/TronStepExecutor.ts +++ b/packages/sdk-provider-tron/src/core/TronStepExecutor.ts @@ -17,6 +17,9 @@ import type { TronStepExecutorContext, TronStepExecutorOptions, } from '../types.js' +import { isZeroAddress } from '../utils/isZeroAddress.js' +import { TronCheckAllowanceTask } from './tasks/TronCheckAllowanceTask.js' +import { TronSetAllowanceTask } from './tasks/TronSetAllowanceTask.js' import { TronSignAndExecuteTask } from './tasks/TronSignAndExecuteTask.js' import { TronWaitForTransactionTask } from './tasks/TronWaitForTransactionTask.js' @@ -57,7 +60,11 @@ export class TronStepExecutor extends BaseStepExecutor { override createPipeline = (context: TronStepExecutorContext) => { const { step, isBridgeExecution } = context + const isFromNativeToken = isZeroAddress(step.action.fromToken.address) + const tasks = [ + new TronCheckAllowanceTask(), + new TronSetAllowanceTask(), new CheckBalanceTask(), new PrepareTransactionTask(), new TronSignAndExecuteTask(), @@ -72,10 +79,21 @@ export class TronStepExecutor extends BaseStepExecutor { isBridgeExecution ? 'CROSS_CHAIN' : 'SWAP' ) - const taskName = - swapOrBridgeAction?.txHash && swapOrBridgeAction?.status === 'DONE' - ? WaitForTransactionStatusTask.name - : CheckBalanceTask.name + const doCheckAllowance = + !swapOrBridgeAction?.txHash && + !isFromNativeToken && + !!step.estimate.approvalAddress && + !step.estimate.skipApproval + + let taskName: string + if (doCheckAllowance) { + taskName = TronCheckAllowanceTask.name + } else { + taskName = + swapOrBridgeAction?.txHash && swapOrBridgeAction?.status === 'DONE' + ? WaitForTransactionStatusTask.name + : CheckBalanceTask.name + } const firstTaskIndex = tasks.findIndex( (task) => task.constructor.name === taskName diff --git a/packages/sdk-provider-tron/src/core/constants.ts b/packages/sdk-provider-tron/src/core/constants.ts new file mode 100644 index 00000000..bf2d60db --- /dev/null +++ b/packages/sdk-provider-tron/src/core/constants.ts @@ -0,0 +1,2 @@ +export const TRON_POLL_INTERVAL_MS = 3000 +export const TRON_POLL_MAX_RETRIES = 20 diff --git a/packages/sdk-provider-tron/src/core/tasks/TronCheckAllowanceTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronCheckAllowanceTask.ts new file mode 100644 index 00000000..a0a3b4ae --- /dev/null +++ b/packages/sdk-provider-tron/src/core/tasks/TronCheckAllowanceTask.ts @@ -0,0 +1,61 @@ +import { + BaseStepExecutionTask, + LiFiErrorCode, + type TaskResult, + TransactionError, +} from '@lifi/sdk' +import { callTronRpcsWithRetry } from '../../rpc/callTronRpcsWithRetry.js' +import type { TronStepExecutorContext } from '../../types.js' + +export class TronCheckAllowanceTask extends BaseStepExecutionTask { + override async shouldRun(context: TronStepExecutorContext): Promise { + return !context.hasSufficientAllowance + } + + async run(context: TronStepExecutorContext): Promise { + const { step, client, wallet, statusManager } = context + + const action = statusManager.initializeAction({ + step, + type: 'CHECK_ALLOWANCE', + chainId: step.action.fromChainId, + status: 'STARTED', + }) + + if (!wallet.address) { + throw new TransactionError( + LiFiErrorCode.WalletChangedDuringExecution, + 'Wallet address is not available. Wallet may have been disconnected.' + ) + } + + if (!step.estimate.approvalAddress) { + throw new TransactionError( + LiFiErrorCode.TransactionUnprepared, + 'Approval address is not available.' + ) + } + + const ownerAddress = wallet.address + const tokenAddress = step.action.fromToken.address + const spenderAddress = step.estimate.approvalAddress + const fromAmount = BigInt(step.action.fromAmount) + + const allowance = await callTronRpcsWithRetry(client, async (tronWeb) => { + const contract = await tronWeb.contract().at(tokenAddress) + const result = await contract + .allowance(ownerAddress, spenderAddress) + .call({ from: ownerAddress }) + return BigInt(result.toString()) + }) + + statusManager.updateAction(step, action.type, 'DONE') + + return { + status: 'COMPLETED', + context: { + hasSufficientAllowance: fromAmount <= allowance, + }, + } + } +} diff --git a/packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts new file mode 100644 index 00000000..602b520e --- /dev/null +++ b/packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts @@ -0,0 +1,131 @@ +import { + BaseStepExecutionTask, + LiFiErrorCode, + type TaskResult, + TransactionError, + waitForResult, +} from '@lifi/sdk' +import { callTronRpcsWithRetry } from '../../rpc/callTronRpcsWithRetry.js' +import type { TronStepExecutorContext } from '../../types.js' +import { stripHexPrefix } from '../../utils/stripHexPrefix.js' +import { TRON_POLL_INTERVAL_MS, TRON_POLL_MAX_RETRIES } from '../constants.js' + +const DEFAULT_APPROVE_FEE_LIMIT = 100_000_000 + +export class TronSetAllowanceTask extends BaseStepExecutionTask { + override async shouldRun(context: TronStepExecutorContext): Promise { + return !context.hasSufficientAllowance + } + + async run(context: TronStepExecutorContext): Promise { + const { step, client, wallet, statusManager, fromChain } = context + + const action = statusManager.initializeAction({ + step, + type: 'SET_ALLOWANCE', + chainId: step.action.fromChainId, + status: 'STARTED', + }) + + statusManager.updateAction(step, action.type, 'ACTION_REQUIRED') + + if (!wallet.address) { + throw new TransactionError( + LiFiErrorCode.WalletChangedDuringExecution, + 'Wallet address is not available. Wallet may have been disconnected.' + ) + } + + if (!step.estimate.approvalAddress) { + throw new TransactionError( + LiFiErrorCode.TransactionUnprepared, + 'Approval address is not available.' + ) + } + + const tokenAddress = step.action.fromToken.address + const spenderAddress = step.estimate.approvalAddress + const ownerAddress = wallet.address + const approveAmount = BigInt(step.action.fromAmount).toString() + + const approveGasCost = step.estimate.gasCosts?.find( + (gc) => gc.type === 'APPROVE' + ) + const feeLimit = approveGasCost?.limit + ? parseInt(approveGasCost.limit, 10) + : DEFAULT_APPROVE_FEE_LIMIT + + const transaction = await callTronRpcsWithRetry(client, async (tronWeb) => { + const { transaction } = + await tronWeb.transactionBuilder.triggerSmartContract( + tokenAddress, + 'approve(address,uint256)', + { feeLimit }, + [ + { type: 'address', value: spenderAddress }, + { type: 'uint256', value: approveAmount }, + ], + ownerAddress + ) + return transaction + }) + + const signedTransaction = await wallet.signTransaction(transaction) + + statusManager.updateAction(step, action.type, 'PENDING') + + const broadcastResult = await callTronRpcsWithRetry( + client, + async (tronWeb) => { + const result = await tronWeb.trx.sendRawTransaction(signedTransaction) + + if (!result.result) { + throw new TransactionError( + LiFiErrorCode.TransactionFailed, + `Approval broadcast failed: ${result.code || 'Unknown error'}` + ) + } + + return result + } + ) + + const txHash = stripHexPrefix(broadcastResult.transaction.txID) + + statusManager.updateAction(step, action.type, 'PENDING', { + txHash, + txLink: `${fromChain.metamask.blockExplorerUrls[0]}#/transaction/${txHash}`, + }) + + // Wait for confirmation + await waitForResult( + async () => { + const txInfo = await callTronRpcsWithRetry(client, (tronWeb) => + tronWeb.trx.getTransactionInfo(txHash) + ) + if (txInfo?.id) { + if (txInfo.receipt?.result === 'FAILED') { + throw new TransactionError( + LiFiErrorCode.TransactionFailed, + 'Approval transaction failed on-chain.' + ) + } + return txInfo + } + return undefined + }, + TRON_POLL_INTERVAL_MS, + TRON_POLL_MAX_RETRIES + ) + + statusManager.updateAction(step, action.type, 'DONE', { + txHash, + txLink: `${fromChain.metamask.blockExplorerUrls[0]}#/transaction/${txHash}`, + }) + + return { + status: 'COMPLETED', + context: { hasSufficientAllowance: true }, + } + } +} diff --git a/packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts index 3513f48c..9412b548 100644 --- a/packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts +++ b/packages/sdk-provider-tron/src/core/tasks/TronSignAndExecuteTask.ts @@ -1,22 +1,18 @@ import { BaseStepExecutionTask, - getTransactionRequestData, LiFiErrorCode, type TaskResult, TransactionError, } from '@lifi/sdk' +import type { Transaction } from '@tronweb3/tronwallet-abstract-adapter' +import { utils } from 'tronweb' import type { TronStepExecutorContext } from '../../types.js' +import { stripHexPrefix } from '../../utils/stripHexPrefix.js' export class TronSignAndExecuteTask extends BaseStepExecutionTask { async run(context: TronStepExecutorContext): Promise { - const { - step, - wallet, - statusManager, - executionOptions, - isBridgeExecution, - checkWallet, - } = context + const { step, wallet, statusManager, isBridgeExecution, checkWallet } = + context const action = statusManager.findAction( step, @@ -30,16 +26,40 @@ export class TronSignAndExecuteTask extends BaseStepExecutionTask { ) } - const transactionRequestData = await getTransactionRequestData( - step, - executionOptions + checkWallet(step) + + if (!step.transactionRequest?.data) { + throw new TransactionError( + LiFiErrorCode.TransactionUnprepared, + 'Unable to prepare transaction. Transaction request is not found.' + ) + } + + const rawDataHex = stripHexPrefix(step.transactionRequest.data as string) + + const contractType = + (step.transactionRequest.customData?.contractType as string) ?? + 'TriggerSmartContract' + + const raw_data = utils.deserializeTx.deserializeTransaction( + contractType, + rawDataHex ) - checkWallet(step) + const transactionPb = utils.transaction.txJsonToPb({ + visible: false, + raw_data, + }) + const txID = stripHexPrefix(utils.transaction.txPbToTxID(transactionPb)) - const unsignedTransaction = JSON.parse(transactionRequestData) + const transaction: Transaction = { + visible: false, + txID, + raw_data, + raw_data_hex: rawDataHex, + } - const signedTransaction = await wallet.signTransaction(unsignedTransaction) + const signedTransaction = await wallet.signTransaction(transaction) statusManager.updateAction(step, action.type, 'PENDING', { signedAt: Date.now(), diff --git a/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts index 55664f68..d2492c83 100644 --- a/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts +++ b/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts @@ -11,6 +11,8 @@ import { getTronWebInstance, } from '../../rpc/callTronRpcsWithRetry.js' import type { TronStepExecutorContext } from '../../types.js' +import { stripHexPrefix } from '../../utils/stripHexPrefix.js' +import { TRON_POLL_INTERVAL_MS, TRON_POLL_MAX_RETRIES } from '../constants.js' export class TronWaitForTransactionTask extends BaseStepExecutionTask { async run(context: TronStepExecutorContext): Promise { @@ -52,7 +54,7 @@ export class TronWaitForTransactionTask extends BaseStepExecutionTask { ) } - const txHash = broadcastResult.transaction.txID + const txHash = stripHexPrefix(broadcastResult.transaction.txID) statusManager.updateAction(step, action.type, 'PENDING', { txHash, @@ -72,8 +74,8 @@ export class TronWaitForTransactionTask extends BaseStepExecutionTask { async function waitForTronConfirmation( client: SDKClient, txHash: string, - maxRetries = 20, - intervalMs = 3000 + maxRetries = TRON_POLL_MAX_RETRIES, + intervalMs = TRON_POLL_INTERVAL_MS ): Promise { for (let i = 0; i < maxRetries; i++) { try { diff --git a/packages/sdk-provider-tron/src/errors/parseTronErrors.ts b/packages/sdk-provider-tron/src/errors/parseTronErrors.ts index 325a2715..db2829e6 100644 --- a/packages/sdk-provider-tron/src/errors/parseTronErrors.ts +++ b/packages/sdk-provider-tron/src/errors/parseTronErrors.ts @@ -16,12 +16,24 @@ import { WalletWindowClosedError, } from '@tronweb3/tronwallet-abstract-adapter' +// "BANDWITH" is the Tron protocol's own misspelling +const isBandwidthError = (message?: string): boolean => + !!message?.includes('BANDWITH_ERROR') + export const parseTronErrors = async ( e: Error, step?: LiFiStep, action?: ExecutionAction ): Promise => { if (e instanceof SDKError) { + if (isBandwidthError(e.message)) { + const baseError = new TransactionError( + LiFiErrorCode.InsufficientFunds, + 'Insufficient TRX for network bandwidth. The account needs more TRX to cover transaction fees.', + e + ) + return new SDKError(baseError, step ?? e.step, action ?? e.action) + } e.step = e.step ?? step e.action = e.action ?? action return e @@ -75,6 +87,14 @@ const handleSpecificErrors = (e: any) => { ) } + if (isBandwidthError(message)) { + return new TransactionError( + LiFiErrorCode.InsufficientFunds, + 'Insufficient TRX for network bandwidth. The account needs more TRX to cover transaction fees.', + e + ) + } + if (e instanceof BaseError) { return e } diff --git a/packages/sdk-provider-tron/src/types.ts b/packages/sdk-provider-tron/src/types.ts index cc1d8e9f..0b06c139 100644 --- a/packages/sdk-provider-tron/src/types.ts +++ b/packages/sdk-provider-tron/src/types.ts @@ -16,6 +16,7 @@ export interface TronProviderOptions { export interface TronTaskContext { signedTransaction?: SignedTransaction + hasSufficientAllowance?: boolean } export interface TronStepExecutorContext diff --git a/packages/sdk-provider-tron/src/utils/stripHexPrefix.ts b/packages/sdk-provider-tron/src/utils/stripHexPrefix.ts new file mode 100644 index 00000000..8bfb5d82 --- /dev/null +++ b/packages/sdk-provider-tron/src/utils/stripHexPrefix.ts @@ -0,0 +1,2 @@ +export const stripHexPrefix = (value: string): string => + value.replace(/^0x/, '') diff --git a/packages/sdk-provider-tron/src/version.ts b/packages/sdk-provider-tron/src/version.ts new file mode 100644 index 00000000..08d4445c --- /dev/null +++ b/packages/sdk-provider-tron/src/version.ts @@ -0,0 +1,2 @@ +export const name = '@lifi/sdk-provider-tron' +export const version = '4.0.0-alpha.21' From da006f5e1c9dbdc7bc50a7d9ce5e6bbebc387618 Mon Sep 17 00:00:00 2001 From: tomide Date: Mon, 16 Mar 2026 13:05:29 +0000 Subject: [PATCH 4/5] fix(sdk-provider-tron): add broadcast retry and handle dup tx errors - Use callTronRpcsWithRetry for broadcast in WaitForTransactionTask - Treat DUP_TRANSACTION_ERROR as success in both broadcast tasks - Remove unused getTronWebInstance - Add empty URLs guard in callTronRpcsWithRetry --- .../src/core/tasks/TronSetAllowanceTask.ts | 2 +- .../core/tasks/TronWaitForTransactionTask.ts | 32 +++++++++++-------- .../src/rpc/callTronRpcsWithRetry.ts | 9 +++--- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts index 602b520e..0fb37fcd 100644 --- a/packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts +++ b/packages/sdk-provider-tron/src/core/tasks/TronSetAllowanceTask.ts @@ -79,7 +79,7 @@ export class TronSetAllowanceTask extends BaseStepExecutionTask { async (tronWeb) => { const result = await tronWeb.trx.sendRawTransaction(signedTransaction) - if (!result.result) { + if (!result.result && String(result.code) !== 'DUP_TRANSACTION_ERROR') { throw new TransactionError( LiFiErrorCode.TransactionFailed, `Approval broadcast failed: ${result.code || 'Unknown error'}` diff --git a/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts b/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts index d2492c83..a494e34f 100644 --- a/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts +++ b/packages/sdk-provider-tron/src/core/tasks/TronWaitForTransactionTask.ts @@ -6,10 +6,7 @@ import { TransactionError, } from '@lifi/sdk' import type { TronWeb } from 'tronweb' -import { - callTronRpcsWithRetry, - getTronWebInstance, -} from '../../rpc/callTronRpcsWithRetry.js' +import { callTronRpcsWithRetry } from '../../rpc/callTronRpcsWithRetry.js' import type { TronStepExecutorContext } from '../../types.js' import { stripHexPrefix } from '../../utils/stripHexPrefix.js' import { TRON_POLL_INTERVAL_MS, TRON_POLL_MAX_RETRIES } from '../constants.js' @@ -43,18 +40,25 @@ export class TronWaitForTransactionTask extends BaseStepExecutionTask { ) } - const tronWeb = await getTronWebInstance(client) - const broadcastResult = - await tronWeb.trx.sendRawTransaction(signedTransaction) + const broadcastResult = await callTronRpcsWithRetry( + client, + async (tronWeb) => { + const result = await tronWeb.trx.sendRawTransaction(signedTransaction) - if (!broadcastResult.result) { - throw new TransactionError( - LiFiErrorCode.TransactionFailed, - `Transaction broadcast failed: ${broadcastResult.code || 'Unknown error'}` - ) - } + if (!result.result && String(result.code) !== 'DUP_TRANSACTION_ERROR') { + throw new TransactionError( + LiFiErrorCode.TransactionFailed, + `Transaction broadcast failed: ${result.code || 'Unknown error'}` + ) + } + + return result + } + ) - const txHash = stripHexPrefix(broadcastResult.transaction.txID) + const txHash = stripHexPrefix( + broadcastResult.transaction?.txID ?? signedTransaction.txID + ) statusManager.updateAction(step, action.type, 'PENDING', { txHash, diff --git a/packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts b/packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts index 10b0e8cf..c9142b96 100644 --- a/packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts +++ b/packages/sdk-provider-tron/src/rpc/callTronRpcsWithRetry.ts @@ -1,17 +1,16 @@ import { ChainId, type SDKClient } from '@lifi/sdk' import { TronWeb } from 'tronweb' -export async function getTronWebInstance(client: SDKClient): Promise { - const urls = await client.getRpcUrlsByChainId(ChainId.TRN) - return new TronWeb({ fullHost: urls[0] }) -} - export async function callTronRpcsWithRetry( client: SDKClient, fn: (tronWeb: TronWeb) => Promise ): Promise { const urls = await client.getRpcUrlsByChainId(ChainId.TRN) + if (!urls.length) { + throw new Error('No Tron RPC URLs available') + } + const errors: Error[] = [] for (const url of urls) { try { From e8ac163a3e84cb872e8af711457c55471bb30544 Mon Sep 17 00:00:00 2001 From: tomide Date: Wed, 18 Mar 2026 16:04:54 +0000 Subject: [PATCH 5/5] chore(release): 4.0.0-alpha.22 --- package.json | 2 +- packages/sdk-provider-bitcoin/package.json | 2 +- packages/sdk-provider-bitcoin/src/version.ts | 2 +- packages/sdk-provider-ethereum/package.json | 2 +- packages/sdk-provider-ethereum/src/version.ts | 2 +- packages/sdk-provider-solana/package.json | 2 +- packages/sdk-provider-solana/src/version.ts | 2 +- packages/sdk-provider-sui/package.json | 2 +- packages/sdk-provider-sui/src/version.ts | 2 +- packages/sdk-provider-tron/package.json | 2 +- packages/sdk-provider-tron/src/version.ts | 2 +- packages/sdk/package.json | 2 +- packages/sdk/src/version.ts | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 2ba5c20f..e14f9c30 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "4.0.0-beta.3", + "version": "4.0.0-alpha.22", "private": true, "sideEffects": false, "type": "module", diff --git a/packages/sdk-provider-bitcoin/package.json b/packages/sdk-provider-bitcoin/package.json index ab922741..bfbee5e9 100644 --- a/packages/sdk-provider-bitcoin/package.json +++ b/packages/sdk-provider-bitcoin/package.json @@ -1,6 +1,6 @@ { "name": "@lifi/sdk-provider-bitcoin", - "version": "4.0.0-beta.3", + "version": "4.0.0-alpha.22", "description": "LI.FI Bitcoin SDK Provider for Any-to-Any Cross-Chain-Swap", "homepage": "https://github.com/lifinance/sdk", "bugs": { diff --git a/packages/sdk-provider-bitcoin/src/version.ts b/packages/sdk-provider-bitcoin/src/version.ts index 6fab5f39..fe51a061 100644 --- a/packages/sdk-provider-bitcoin/src/version.ts +++ b/packages/sdk-provider-bitcoin/src/version.ts @@ -1,2 +1,2 @@ export const name = '@lifi/sdk-provider-bitcoin' -export const version = '4.0.0-beta.3' +export const version = '4.0.0-alpha.22' diff --git a/packages/sdk-provider-ethereum/package.json b/packages/sdk-provider-ethereum/package.json index f6808341..ab5f8d5a 100644 --- a/packages/sdk-provider-ethereum/package.json +++ b/packages/sdk-provider-ethereum/package.json @@ -1,6 +1,6 @@ { "name": "@lifi/sdk-provider-ethereum", - "version": "4.0.0-beta.3", + "version": "4.0.0-alpha.22", "description": "LI.FI Ethereum SDK Provider for Any-to-Any Cross-Chain-Swap", "homepage": "https://github.com/lifinance/sdk", "bugs": { diff --git a/packages/sdk-provider-ethereum/src/version.ts b/packages/sdk-provider-ethereum/src/version.ts index 45edd35d..646b07c4 100644 --- a/packages/sdk-provider-ethereum/src/version.ts +++ b/packages/sdk-provider-ethereum/src/version.ts @@ -1,2 +1,2 @@ export const name = '@lifi/sdk-provider-ethereum' -export const version = '4.0.0-beta.3' +export const version = '4.0.0-alpha.22' diff --git a/packages/sdk-provider-solana/package.json b/packages/sdk-provider-solana/package.json index a8602e2b..7fe8f2ef 100644 --- a/packages/sdk-provider-solana/package.json +++ b/packages/sdk-provider-solana/package.json @@ -1,6 +1,6 @@ { "name": "@lifi/sdk-provider-solana", - "version": "4.0.0-beta.3", + "version": "4.0.0-alpha.22", "description": "LI.FI Solana SDK Provider for Any-to-Any Cross-Chain-Swap", "homepage": "https://github.com/lifinance/sdk", "bugs": { diff --git a/packages/sdk-provider-solana/src/version.ts b/packages/sdk-provider-solana/src/version.ts index b497c0a8..89e6fe81 100644 --- a/packages/sdk-provider-solana/src/version.ts +++ b/packages/sdk-provider-solana/src/version.ts @@ -1,2 +1,2 @@ export const name = '@lifi/sdk-provider-solana' -export const version = '4.0.0-beta.3' +export const version = '4.0.0-alpha.22' diff --git a/packages/sdk-provider-sui/package.json b/packages/sdk-provider-sui/package.json index 1cb73028..fba3afaf 100644 --- a/packages/sdk-provider-sui/package.json +++ b/packages/sdk-provider-sui/package.json @@ -1,6 +1,6 @@ { "name": "@lifi/sdk-provider-sui", - "version": "4.0.0-beta.3", + "version": "4.0.0-alpha.22", "description": "LI.FI Sui SDK Provider for Any-to-Any Cross-Chain-Swap", "homepage": "https://github.com/lifinance/sdk", "bugs": { diff --git a/packages/sdk-provider-sui/src/version.ts b/packages/sdk-provider-sui/src/version.ts index 72d04e7c..eafa34ec 100644 --- a/packages/sdk-provider-sui/src/version.ts +++ b/packages/sdk-provider-sui/src/version.ts @@ -1,2 +1,2 @@ export const name = '@lifi/sdk-provider-sui' -export const version = '4.0.0-beta.3' +export const version = '4.0.0-alpha.22' diff --git a/packages/sdk-provider-tron/package.json b/packages/sdk-provider-tron/package.json index 31f4c91b..b6808a9b 100644 --- a/packages/sdk-provider-tron/package.json +++ b/packages/sdk-provider-tron/package.json @@ -1,6 +1,6 @@ { "name": "@lifi/sdk-provider-tron", - "version": "4.0.0-alpha.21", + "version": "4.0.0-alpha.22", "description": "LI.FI Tron SDK Provider for Any-to-Any Cross-Chain-Swap", "homepage": "https://github.com/lifinance/sdk", "bugs": { diff --git a/packages/sdk-provider-tron/src/version.ts b/packages/sdk-provider-tron/src/version.ts index 08d4445c..43906708 100644 --- a/packages/sdk-provider-tron/src/version.ts +++ b/packages/sdk-provider-tron/src/version.ts @@ -1,2 +1,2 @@ export const name = '@lifi/sdk-provider-tron' -export const version = '4.0.0-alpha.21' +export const version = '4.0.0-alpha.22' diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 38856841..5d9114e3 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@lifi/sdk", - "version": "4.0.0-beta.3", + "version": "4.0.0-alpha.22", "description": "LI.FI SDK for Any-to-Any Cross-Chain-Swap", "homepage": "https://github.com/lifinance/sdk", "bugs": { diff --git a/packages/sdk/src/version.ts b/packages/sdk/src/version.ts index 08d0f5ec..6ea97776 100644 --- a/packages/sdk/src/version.ts +++ b/packages/sdk/src/version.ts @@ -1,2 +1,2 @@ export const name = '@lifi/sdk' -export const version = '4.0.0-beta.3' +export const version = '4.0.0-alpha.22'