Last active
September 25, 2025 06:18
-
-
Save sedhu-orbitx/c4bd67ce95e87231f7647ccd38ee5185 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Composed MultiHop Transfer Implementation following tron-exmaple.ts pattern | |
| * Handles single-transaction multi-hop transfers: Tron β Arbitrum β Polygon | |
| * Uses composed message pattern for seamless multi-hop transfers | |
| * Uses TronWeb for Tron operations and ethers.js for EVM chains | |
| * | |
| * Based on LayerZero UI Bridge SDK pattern and USDT0 documentation | |
| */ | |
| export const TRON_OFT_ABI = [ | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '_arbitrumEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint32', | |
| name: '_celoEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint32', | |
| name: '_ethEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint32', | |
| name: '_tonEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint32', | |
| name: '_tronEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'address', | |
| name: '_token', | |
| type: 'address', | |
| }, | |
| { | |
| internalType: 'address', | |
| name: '_lzEndpoint', | |
| type: 'address', | |
| }, | |
| { | |
| internalType: 'address', | |
| name: '_delegate', | |
| type: 'address', | |
| }, | |
| ], | |
| stateMutability: 'nonpayable', | |
| type: 'constructor', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: 'target', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'AddressEmptyCode', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: 'account', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'AddressInsufficientBalance', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'ComposeNotSupported', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'FailedInnerCall', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'credits', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountWithdraw', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'InsufficientCredits', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'InsufficientFeeBalance', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'InvalidAmount', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'InvalidDelegate', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'InvalidEid', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'InvalidEndpointCall', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: 'feeBps', | |
| type: 'uint16', | |
| }, | |
| ], | |
| name: 'InvalidFeeBps', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'InvalidLocalDecimals', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: 'msgType', | |
| type: 'uint16', | |
| }, | |
| ], | |
| name: 'InvalidMsgType', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'bytes', | |
| name: 'options', | |
| type: 'bytes', | |
| }, | |
| ], | |
| name: 'InvalidOptions', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'LzTokenUnavailable', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| ], | |
| name: 'NoPeer', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'msgValue', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'NotEnoughNative', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: 'addr', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'OnlyEndpoint', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'OnlyLpAdminOrOwner', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'sender', | |
| type: 'bytes32', | |
| }, | |
| ], | |
| name: 'OnlyPeer', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'OnlyPlanner', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: 'owner', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'OwnableInvalidOwner', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: 'account', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'OwnableUnauthorizedAccount', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: 'token', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'SafeERC20FailedOperation', | |
| type: 'error', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'amountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'minAmountLD', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'SlippageExceeded', | |
| type: 'error', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'bytes32', | |
| name: 'guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint32', | |
| name: 'srcEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'bytes', | |
| name: 'message', | |
| type: 'bytes', | |
| }, | |
| ], | |
| name: 'CreditsReceived', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint64', | |
| name: 'creditsArbitrum', | |
| type: 'uint64', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint64', | |
| name: 'creditsCelo', | |
| type: 'uint64', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint64', | |
| name: 'creditsEth', | |
| type: 'uint64', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint64', | |
| name: 'creditsTon', | |
| type: 'uint64', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint64', | |
| name: 'creditsTron', | |
| type: 'uint64', | |
| }, | |
| ], | |
| name: 'CreditsSent', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint16', | |
| name: 'msgType', | |
| type: 'uint16', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'options', | |
| type: 'bytes', | |
| }, | |
| ], | |
| indexed: false, | |
| internalType: 'struct EnforcedOptionParam[]', | |
| name: '_enforcedOptions', | |
| type: 'tuple[]', | |
| }, | |
| ], | |
| name: 'EnforcedOptionSet', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'uint16', | |
| name: 'feeBps', | |
| type: 'uint16', | |
| }, | |
| ], | |
| name: 'FeeBpsSet', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'address', | |
| name: 'to', | |
| type: 'address', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'FeesWithdrawn', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'LocalDeposit', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'address', | |
| name: 'to', | |
| type: 'address', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'LocalWithdrawn', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'address', | |
| name: 'lpAdmin', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'LpAdminSet', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: true, | |
| internalType: 'bytes32', | |
| name: 'guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint32', | |
| name: 'srcEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| indexed: true, | |
| internalType: 'address', | |
| name: 'toAddress', | |
| type: 'address', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amountReceivedLD', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'OFTReceived', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: true, | |
| internalType: 'bytes32', | |
| name: 'guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| indexed: true, | |
| internalType: 'address', | |
| name: 'fromAddress', | |
| type: 'address', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amountSentLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amountReceivedLD', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'OFTSent', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: true, | |
| internalType: 'address', | |
| name: 'previousOwner', | |
| type: 'address', | |
| }, | |
| { | |
| indexed: true, | |
| internalType: 'address', | |
| name: 'newOwner', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'OwnershipTransferred', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'bytes32', | |
| name: 'peer', | |
| type: 'bytes32', | |
| }, | |
| ], | |
| name: 'PeerSet', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'address', | |
| name: 'planner', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'PlannerSet', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'bytes32', | |
| name: 'guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint32', | |
| name: 'srcEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'address', | |
| name: 'to', | |
| type: 'address', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'RemoteWithdrawReceived', | |
| type: 'event', | |
| }, | |
| { | |
| anonymous: false, | |
| inputs: [ | |
| { | |
| indexed: false, | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| indexed: false, | |
| internalType: 'uint256', | |
| name: 'amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'RemoteWithdrawn', | |
| type: 'event', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'ARBITRUM_EID', | |
| outputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '', | |
| type: 'uint32', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'BPS_DENOMINATOR', | |
| outputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: '', | |
| type: 'uint16', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'CELO_EID', | |
| outputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '', | |
| type: 'uint32', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'ETH_EID', | |
| outputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '', | |
| type: 'uint32', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'LOCAL_EID', | |
| outputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '', | |
| type: 'uint32', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'SEND_CREDITS', | |
| outputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: '', | |
| type: 'uint16', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'SEND_OFT', | |
| outputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: '', | |
| type: 'uint16', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'TON_EID', | |
| outputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '', | |
| type: 'uint32', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'TRON_EID', | |
| outputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '', | |
| type: 'uint32', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'WITHDRAW_REMOTE', | |
| outputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: '', | |
| type: 'uint16', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'srcEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'sender', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'nonce', | |
| type: 'uint64', | |
| }, | |
| ], | |
| internalType: 'struct Origin', | |
| name: 'origin', | |
| type: 'tuple', | |
| }, | |
| ], | |
| name: 'allowInitializePath', | |
| outputs: [ | |
| { | |
| internalType: 'bool', | |
| name: '', | |
| type: 'bool', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'approvalRequired', | |
| outputs: [ | |
| { | |
| internalType: 'bool', | |
| name: '', | |
| type: 'bool', | |
| }, | |
| ], | |
| stateMutability: 'pure', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '_eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint16', | |
| name: '_msgType', | |
| type: 'uint16', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: '_extraOptions', | |
| type: 'bytes', | |
| }, | |
| ], | |
| name: 'combineOptions', | |
| outputs: [ | |
| { | |
| internalType: 'bytes', | |
| name: '', | |
| type: 'bytes', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| ], | |
| name: 'credits', | |
| outputs: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'credits', | |
| type: 'uint256', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint256', | |
| name: '_amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'depositLocal', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'endpoint', | |
| outputs: [ | |
| { | |
| internalType: 'contract ILayerZeroEndpointV2', | |
| name: '', | |
| type: 'address', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint16', | |
| name: 'msgType', | |
| type: 'uint16', | |
| }, | |
| ], | |
| name: 'enforcedOptions', | |
| outputs: [ | |
| { | |
| internalType: 'bytes', | |
| name: 'enforcedOption', | |
| type: 'bytes', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'feeBalance', | |
| outputs: [ | |
| { | |
| internalType: 'uint256', | |
| name: '', | |
| type: 'uint256', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'feeBps', | |
| outputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: '', | |
| type: 'uint16', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'srcEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'sender', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'nonce', | |
| type: 'uint64', | |
| }, | |
| ], | |
| internalType: 'struct Origin', | |
| name: '', | |
| type: 'tuple', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: '', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'address', | |
| name: '_sender', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'isComposeMsgSender', | |
| outputs: [ | |
| { | |
| internalType: 'bool', | |
| name: '', | |
| type: 'bool', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'lpAdmin', | |
| outputs: [ | |
| { | |
| internalType: 'address', | |
| name: '', | |
| type: 'address', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'srcEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'sender', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'nonce', | |
| type: 'uint64', | |
| }, | |
| ], | |
| internalType: 'struct Origin', | |
| name: '_origin', | |
| type: 'tuple', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: '_guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: '_message', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'address', | |
| name: '_executor', | |
| type: 'address', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: '_extraData', | |
| type: 'bytes', | |
| }, | |
| ], | |
| name: 'lzReceive', | |
| outputs: [], | |
| stateMutability: 'payable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: '', | |
| type: 'bytes32', | |
| }, | |
| ], | |
| name: 'nextNonce', | |
| outputs: [ | |
| { | |
| internalType: 'uint64', | |
| name: 'nonce', | |
| type: 'uint64', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'oAppVersion', | |
| outputs: [ | |
| { | |
| internalType: 'uint64', | |
| name: 'senderVersion', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'receiverVersion', | |
| type: 'uint64', | |
| }, | |
| ], | |
| stateMutability: 'pure', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'oftVersion', | |
| outputs: [ | |
| { | |
| internalType: 'bytes4', | |
| name: 'interfaceId', | |
| type: 'bytes4', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'version', | |
| type: 'uint64', | |
| }, | |
| ], | |
| stateMutability: 'pure', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'owner', | |
| outputs: [ | |
| { | |
| internalType: 'address', | |
| name: '', | |
| type: 'address', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| ], | |
| name: 'peers', | |
| outputs: [ | |
| { | |
| internalType: 'bytes32', | |
| name: 'peer', | |
| type: 'bytes32', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'planner', | |
| outputs: [ | |
| { | |
| internalType: 'address', | |
| name: '', | |
| type: 'address', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'to', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'minAmountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'extraOptions', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'composeMsg', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'oftCmd', | |
| type: 'bytes', | |
| }, | |
| ], | |
| internalType: 'struct SendParam', | |
| name: '_sendParam', | |
| type: 'tuple', | |
| }, | |
| ], | |
| name: 'quoteOFT', | |
| outputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'minAmountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'maxAmountLD', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct OFTLimit', | |
| name: 'oftLimit', | |
| type: 'tuple', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'int256', | |
| name: 'feeAmountLD', | |
| type: 'int256', | |
| }, | |
| { | |
| internalType: 'string', | |
| name: 'description', | |
| type: 'string', | |
| }, | |
| ], | |
| internalType: 'struct OFTFeeDetail[]', | |
| name: 'oftFeeDetails', | |
| type: 'tuple[]', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'amountSentLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountReceivedLD', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct OFTReceipt', | |
| name: 'oftReceipt', | |
| type: 'tuple', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'to', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'minAmountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'extraOptions', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'composeMsg', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'oftCmd', | |
| type: 'bytes', | |
| }, | |
| ], | |
| internalType: 'struct SendParam', | |
| name: '_sendParam', | |
| type: 'tuple', | |
| }, | |
| { | |
| internalType: 'bool', | |
| name: '_payInLzToken', | |
| type: 'bool', | |
| }, | |
| ], | |
| name: 'quoteSend', | |
| outputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: 'msgFee', | |
| type: 'tuple', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '_dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsArbitrum', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsCelo', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsEth', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsTon', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsTron', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: '_extraOptions', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bool', | |
| name: '_payInLzToken', | |
| type: 'bool', | |
| }, | |
| ], | |
| name: 'quoteSendCredits', | |
| outputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: 'msgFee', | |
| type: 'tuple', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'to', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'minAmountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'extraOptions', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'composeMsg', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'oftCmd', | |
| type: 'bytes', | |
| }, | |
| ], | |
| internalType: 'struct SendParam', | |
| name: '_sendParam', | |
| type: 'tuple', | |
| }, | |
| { | |
| internalType: 'bool', | |
| name: '_payInLzToken', | |
| type: 'bool', | |
| }, | |
| ], | |
| name: 'quoteWithdrawRemote', | |
| outputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: 'msgFee', | |
| type: 'tuple', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'renounceOwnership', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'to', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'minAmountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'extraOptions', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'composeMsg', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'oftCmd', | |
| type: 'bytes', | |
| }, | |
| ], | |
| internalType: 'struct SendParam', | |
| name: '_sendParam', | |
| type: 'tuple', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: '_fee', | |
| type: 'tuple', | |
| }, | |
| { | |
| internalType: 'address', | |
| name: '_refundAddress', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'send', | |
| outputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'bytes32', | |
| name: 'guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'nonce', | |
| type: 'uint64', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: 'fee', | |
| type: 'tuple', | |
| }, | |
| ], | |
| internalType: 'struct MessagingReceipt', | |
| name: 'msgReceipt', | |
| type: 'tuple', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'amountSentLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountReceivedLD', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct OFTReceipt', | |
| name: 'oftReceipt', | |
| type: 'tuple', | |
| }, | |
| ], | |
| stateMutability: 'payable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '_dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsArbitrum', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsCelo', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsEth', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsTon', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: '_creditsTron', | |
| type: 'uint64', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: '_extraOptions', | |
| type: 'bytes', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: '_fee', | |
| type: 'tuple', | |
| }, | |
| ], | |
| name: 'sendCredits', | |
| outputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'bytes32', | |
| name: 'guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'nonce', | |
| type: 'uint64', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: 'fee', | |
| type: 'tuple', | |
| }, | |
| ], | |
| internalType: 'struct MessagingReceipt', | |
| name: 'msgReceipt', | |
| type: 'tuple', | |
| }, | |
| ], | |
| stateMutability: 'payable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: '_delegate', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'setDelegate', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'uint16', | |
| name: 'msgType', | |
| type: 'uint16', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'options', | |
| type: 'bytes', | |
| }, | |
| ], | |
| internalType: 'struct EnforcedOptionParam[]', | |
| name: '_enforcedOptions', | |
| type: 'tuple[]', | |
| }, | |
| ], | |
| name: 'setEnforcedOptions', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint16', | |
| name: '_feeBps', | |
| type: 'uint16', | |
| }, | |
| ], | |
| name: 'setFeeBps', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: '_lpAdmin', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'setLpAdmin', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'uint32', | |
| name: '_eid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: '_peer', | |
| type: 'bytes32', | |
| }, | |
| ], | |
| name: 'setPeer', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: '_planner', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'setPlanner', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'sharedDecimals', | |
| outputs: [ | |
| { | |
| internalType: 'uint8', | |
| name: '', | |
| type: 'uint8', | |
| }, | |
| ], | |
| stateMutability: 'pure', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'token', | |
| outputs: [ | |
| { | |
| internalType: 'address', | |
| name: '', | |
| type: 'address', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: 'newOwner', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'transferOwnership', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [], | |
| name: 'tvl', | |
| outputs: [ | |
| { | |
| internalType: 'uint256', | |
| name: '', | |
| type: 'uint256', | |
| }, | |
| ], | |
| stateMutability: 'view', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: '_to', | |
| type: 'address', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: '_amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'withdrawFees', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| internalType: 'address', | |
| name: '_to', | |
| type: 'address', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: '_amount', | |
| type: 'uint256', | |
| }, | |
| ], | |
| name: 'withdrawLocal', | |
| outputs: [], | |
| stateMutability: 'nonpayable', | |
| type: 'function', | |
| }, | |
| { | |
| inputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint32', | |
| name: 'dstEid', | |
| type: 'uint32', | |
| }, | |
| { | |
| internalType: 'bytes32', | |
| name: 'to', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'amountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'minAmountLD', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'extraOptions', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'composeMsg', | |
| type: 'bytes', | |
| }, | |
| { | |
| internalType: 'bytes', | |
| name: 'oftCmd', | |
| type: 'bytes', | |
| }, | |
| ], | |
| internalType: 'struct SendParam', | |
| name: '_sendParam', | |
| type: 'tuple', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: '_fee', | |
| type: 'tuple', | |
| }, | |
| { | |
| internalType: 'address', | |
| name: '_refundAddress', | |
| type: 'address', | |
| }, | |
| ], | |
| name: 'withdrawRemote', | |
| outputs: [ | |
| { | |
| components: [ | |
| { | |
| internalType: 'bytes32', | |
| name: 'guid', | |
| type: 'bytes32', | |
| }, | |
| { | |
| internalType: 'uint64', | |
| name: 'nonce', | |
| type: 'uint64', | |
| }, | |
| { | |
| components: [ | |
| { | |
| internalType: 'uint256', | |
| name: 'nativeFee', | |
| type: 'uint256', | |
| }, | |
| { | |
| internalType: 'uint256', | |
| name: 'lzTokenFee', | |
| type: 'uint256', | |
| }, | |
| ], | |
| internalType: 'struct MessagingFee', | |
| name: 'fee', | |
| type: 'tuple', | |
| }, | |
| ], | |
| internalType: 'struct MessagingReceipt', | |
| name: 'msgReceipt', | |
| type: 'tuple', | |
| }, | |
| ], | |
| stateMutability: 'payable', | |
| type: 'function', | |
| }, | |
| ]; | |
| import { ethers } from 'ethers'; | |
| import { TronWeb } from 'tronweb'; | |
| import { | |
| LEGACY_MESH_ABI, | |
| MessagingFee, | |
| OFTReceipt, | |
| SendParam | |
| } from './abis'; | |
| import { | |
| LAYERZERO_EIDS, | |
| RPC_URLS, | |
| USDT0_CONTRACTS, | |
| USDT_CONTRACTS, | |
| USDT_DECIMALS | |
| } from './constants'; | |
| // Types | |
| export interface TronTransactionResult { | |
| txid: string; | |
| result: boolean; | |
| energy_used: number; | |
| energy_fee: number; | |
| bandwidth_used: number; | |
| bandwidth_fee: number; | |
| net_fee: number; | |
| net_usage: number; | |
| energy_usage_total: number; | |
| bandwidth_usage: number; | |
| energy_usage: number; | |
| blockNumber: number; | |
| } | |
| export interface ComposedTransferResult { | |
| tronTx: TronTransactionResult; | |
| totalFees: { | |
| tron: bigint; | |
| layerZero: bigint; | |
| }; | |
| monitoring: { | |
| tronExplorer: string; | |
| layerZeroExplorer: string; | |
| polygonExplorer: string; | |
| }; | |
| guid: string; | |
| } | |
| export interface ComposedTransferQuote { | |
| messagingFee: MessagingFee; | |
| oftReceipt: OFTReceipt; | |
| hopChainFee: MessagingFee; | |
| totalFee: MessagingFee; | |
| } | |
| // Utility Functions | |
| export function addressToBytes32(address: string): string { | |
| return ethers.zeroPadValue(address, 32); | |
| } | |
| export function encodeComposeMessage(hopSendParams: SendParam): string { | |
| return ethers.AbiCoder.defaultAbiCoder().encode( | |
| ['tuple(uint32,bytes32,uint256,uint256,bytes,bytes,bytes)'], | |
| [[ | |
| hopSendParams.dstEid, | |
| hopSendParams.to, | |
| hopSendParams.amountLD, | |
| hopSendParams.minAmountLD, | |
| hopSendParams.extraOptions, | |
| hopSendParams.composeMsg, | |
| hopSendParams.oftCmd | |
| ]] | |
| ); | |
| } | |
| export function createLayerZeroOptions( | |
| hopChainFee: MessagingFee, | |
| dstChainKey: string | |
| ): string { | |
| // For composed transfers, we can use a simpler approach | |
| // LayerZero will handle the executor options automatically | |
| // Option 1: Use empty options (simplest) | |
| // return '0x'; | |
| // Option 2: Use basic executor options | |
| const executorLzReceiveOption = [200_000n, 0n]; // [gas, value] | |
| const executorComposeOption = [0n, 500_000n, (hopChainFee.nativeFee * 11n) / 10n]; // [index, gas, value] | |
| // Encode options as tuples in the correct order | |
| return ethers.AbiCoder.defaultAbiCoder().encode( | |
| ['tuple(tuple(uint256,uint256),tuple(uint256,uint256,uint256))'], | |
| [[executorLzReceiveOption, executorComposeOption]] | |
| ); | |
| } | |
| // TronWeb Initialization | |
| export function initializeTronWeb(privateKey: string, tronRpcUrl?: string): any { | |
| const tronWeb = new TronWeb({ | |
| fullHost: tronRpcUrl, | |
| privateKey: privateKey | |
| }); | |
| return tronWeb; | |
| } | |
| // Core Transfer Functions | |
| export async function getTronUSDTBalance( | |
| tronWeb: any, | |
| walletAddress: string | |
| ): Promise<bigint> { | |
| try { | |
| const contract = await tronWeb.contract().at(USDT_CONTRACTS.TRON); | |
| const balance = await contract.balanceOf(walletAddress).call(); | |
| return BigInt(balance.toString()); | |
| } catch (error) { | |
| throw new Error(`Failed to get USDT balance on Tron: ${error}`); | |
| } | |
| } | |
| export async function getTronUSDTInfo( | |
| tronWeb: any | |
| ): Promise<{ | |
| name: string; | |
| symbol: string; | |
| decimals: number; | |
| totalSupply: bigint; | |
| }> { | |
| try { | |
| const contract = await tronWeb.contract().at(USDT_CONTRACTS.TRON); | |
| const [name, symbol, decimals, totalSupply] = await Promise.all([ | |
| contract.name().call(), | |
| contract.symbol().call(), | |
| contract.decimals().call(), | |
| contract.totalSupply().call() | |
| ]); | |
| return { | |
| name: name.toString(), | |
| symbol: symbol.toString(), | |
| decimals: Number(decimals.toString()), | |
| totalSupply: BigInt(totalSupply.toString()) | |
| }; | |
| } catch (error) { | |
| throw new Error(`Failed to get USDT info on Tron: ${error}`); | |
| } | |
| } | |
| export async function checkTronUSDTAllowance( | |
| tronWeb: any, | |
| walletAddress: string | |
| ): Promise<bigint> { | |
| try { | |
| const contract = await tronWeb.contract().at(USDT_CONTRACTS.TRON); | |
| const allowance = await contract.allowance( | |
| walletAddress, | |
| USDT0_CONTRACTS.TRON.UsdtOFT | |
| ).call(); | |
| return BigInt(allowance.toString()); | |
| } catch (error) { | |
| throw new Error(`Failed to check USDT allowance on Tron: ${error}`); | |
| } | |
| } | |
| export async function approveTronUSDT( | |
| tronWeb: any, | |
| amount: bigint | |
| ): Promise<TronTransactionResult> { | |
| try { | |
| const contract = await tronWeb.contract().at(USDT_CONTRACTS.TRON); | |
| console.log(` Approving ${ethers.formatUnits(amount, USDT_DECIMALS)} USDT for Legacy Mesh contract...`); | |
| const tx = await contract.approve( | |
| USDT0_CONTRACTS.TRON.UsdtOFT, | |
| amount.toString() | |
| ).send({ | |
| feeLimit: 100_000_000, // 100 TRX fee limit | |
| callValue: 0, | |
| shouldPollResponse: true | |
| }); | |
| console.log(` Approval transaction hash: ${tx.txid}`); | |
| console.log(' USDT approval confirmed on Tron'); | |
| return tx; | |
| } catch (error) { | |
| throw new Error(`Failed to approve USDT on Tron: ${error}`); | |
| } | |
| } | |
| export async function getHopChainQuote( | |
| arbitrumProvider: ethers.JsonRpcProvider, | |
| hopSendParams: SendParam | |
| ): Promise<MessagingFee> { | |
| const arbitrumUsdt0Contract = new ethers.Contract( | |
| USDT0_CONTRACTS.ARBITRUM.UsdtOFT, | |
| LEGACY_MESH_ABI, | |
| arbitrumProvider | |
| ); | |
| try { | |
| const quoteData = await arbitrumUsdt0Contract.quoteSend(hopSendParams, false); | |
| return { | |
| nativeFee: quoteData.nativeFee, | |
| lzTokenFee: quoteData.lzTokenFee | |
| }; | |
| } catch (error) { | |
| // console.log('Hop chain quote error, using fallback fee:', error); | |
| // Fallback fee: 0.0001 ETH | |
| return { | |
| nativeFee: BigInt(1e14), // 0.0001 ETH | |
| lzTokenFee: 0n | |
| }; | |
| } | |
| } | |
| export function buildHopChainSendParams( | |
| recipientAddress: string, | |
| amount: bigint, | |
| dstChainKey: string = 'polygon' | |
| ): SendParam { | |
| const dstEid = LAYERZERO_EIDS.POLYGON; | |
| return { | |
| dstEid, | |
| to: addressToBytes32(recipientAddress), | |
| amountLD: amount, | |
| minAmountLD: 0n, | |
| extraOptions: '0x', | |
| composeMsg: '0x', | |
| oftCmd: '0x' | |
| }; | |
| } | |
| export async function buildComposedSendParams( | |
| tronWeb: TronWeb, | |
| arbitrumProvider: ethers.JsonRpcProvider, | |
| recipientAddress: string, | |
| amount: bigint, | |
| minAmount?: bigint | |
| ): Promise<{ | |
| sendParams: SendParam; | |
| messagingFee: MessagingFee; | |
| oftReceipt: OFTReceipt; | |
| }> { | |
| // Build hop chain parameters | |
| const hopSendParams = buildHopChainSendParams(recipientAddress, amount); | |
| // Get hop chain quote | |
| const hopChainFee = await getHopChainQuote(arbitrumProvider, hopSendParams); | |
| // Create LayerZero options with fee buffer | |
| const extraOptions = createLayerZeroOptions(hopChainFee, 'polygon'); | |
| // Build main send parameters | |
| const sendParams: SendParam = { | |
| dstEid: LAYERZERO_EIDS.ARBITRUM, | |
| to: addressToBytes32(USDT0_CONTRACTS.ARBITRUM.MultiHopComposer), // Send to MultiHopComposer | |
| amountLD: amount, | |
| minAmountLD: minAmount || amount / 2n, // Default to 50% slippage protection | |
| extraOptions, | |
| composeMsg: encodeComposeMessage(hopSendParams), // Encode hop chain params | |
| oftCmd: '0x' | |
| }; | |
| // Get quote for main transfer using TronWeb | |
| const tronUsdt0Contract = await tronWeb.contract(TRON_OFT_ABI, USDT0_CONTRACTS.TRON.UsdtOFT); | |
| // Convert to TronWeb format for contract calls - pass as tuple array | |
| const sendParamsTron = [ | |
| sendParams.dstEid, | |
| sendParams.to, | |
| sendParams.amountLD.toString(), | |
| sendParams.minAmountLD.toString(), | |
| sendParams.extraOptions, | |
| sendParams.composeMsg, | |
| sendParams.oftCmd | |
| ]; | |
| // Use quoteOFT to get the quote (not send) | |
| const [, feeDetails, oftReceipt] = await tronUsdt0Contract.quoteOFT(sendParamsTron).call(); | |
| sendParams.minAmountLD = BigInt(oftReceipt.amountReceivedLD?.toString() || '0'); | |
| sendParamsTron[3] = oftReceipt.amountReceivedLD?.toString(); | |
| const messagingFeeResult = await tronUsdt0Contract.quoteSend(sendParamsTron, false).call(); | |
| const messagingFee: MessagingFee = { | |
| nativeFee: BigInt(messagingFeeResult.nativeFee?.toString() || '0'), | |
| lzTokenFee: BigInt(messagingFeeResult.lzTokenFee?.toString() || '0') | |
| }; | |
| const oftReceiptResult: OFTReceipt = { | |
| amountReceivedLD: BigInt(oftReceipt.amountReceivedLD?.toString() || '0'), | |
| amountSentLD: BigInt(oftReceipt.amountSentLD?.toString() || '0') | |
| }; | |
| return { | |
| sendParams, | |
| messagingFee, | |
| oftReceipt: oftReceiptResult | |
| }; | |
| } | |
| export async function executeComposedTransfer( | |
| privateKey: string, | |
| recipientAddress: string, | |
| amount: string, | |
| tronRpcUrl?: string, | |
| arbitrumRpcUrl?: string | |
| ): Promise<ComposedTransferResult> { | |
| // Initialize TronWeb and EVM providers | |
| const tronWeb = initializeTronWeb(privateKey, tronRpcUrl); | |
| const arbitrumProvider = new ethers.JsonRpcProvider(arbitrumRpcUrl || RPC_URLS.ARBITRUM); | |
| const amountWei = ethers.parseUnits(amount, USDT_DECIMALS); | |
| const walletAddress = tronWeb.address.fromPrivateKey(privateKey); | |
| console.log(`π Starting Composed MultiHop transfer: ${amount} USDT from Tron to Polygon`); | |
| console.log(' Architecture: Tron (USDT) β Arbitrum (MultiHopComposer) β Polygon (USDT0)'); | |
| console.log(` Tron Address: ${walletAddress}\n`); | |
| // Check USDT balance | |
| const usdtBalance = await getTronUSDTBalance(tronWeb, walletAddress); | |
| if (usdtBalance < amountWei) { | |
| throw new Error(`Insufficient USDT balance. Required: ${amount} USDT, Available: ${ethers.formatUnits(usdtBalance, USDT_DECIMALS)} USDT`); | |
| } | |
| // Check and approve USDT if needed | |
| const allowance = await checkTronUSDTAllowance(tronWeb, walletAddress); | |
| if (allowance < amountWei) { | |
| console.log(' Insufficient USDT allowance, requesting approval...'); | |
| await approveTronUSDT(tronWeb, amountWei); | |
| } else { | |
| console.log(` Sufficient USDT allowance: ${ethers.formatUnits(allowance, USDT_DECIMALS)} USDT`); | |
| } | |
| // Build composed send parameters | |
| console.log('π Building composed transfer parameters...'); | |
| const { sendParams, messagingFee, oftReceipt } = await buildComposedSendParams( | |
| tronWeb, | |
| arbitrumProvider, | |
| recipientAddress, | |
| amountWei | |
| ); | |
| console.log(` Expected USDT0 on Arbitrum: ${ethers.formatUnits(oftReceipt.amountReceivedLD, USDT_DECIMALS)} USDT0`); | |
| console.log(` Native fee: ${ethers.formatEther(messagingFee.nativeFee)} TRX`); | |
| // Execute composed transfer using TronWeb | |
| console.log('π Executing composed transfer...'); | |
| const tronUsdt0Contract = await tronWeb.contract(TRON_OFT_ABI, USDT0_CONTRACTS.TRON.UsdtOFT); | |
| const sendParamsTron = [ | |
| sendParams.dstEid, | |
| sendParams.to, | |
| sendParams.amountLD.toString(), | |
| sendParams.minAmountLD.toString(), | |
| sendParams.extraOptions, | |
| sendParams.composeMsg, | |
| sendParams.oftCmd | |
| ]; | |
| const messagingFeeTron = [ | |
| messagingFee.nativeFee.toString(), | |
| messagingFee.lzTokenFee.toString() | |
| ]; | |
| const tronTx = await tronUsdt0Contract.send( | |
| sendParamsTron, | |
| messagingFeeTron, | |
| walletAddress | |
| ).send({ | |
| feeLimit: 1_000_000_000, // 1000 TRX fee limit | |
| callValue: messagingFee.nativeFee.toString(), | |
| shouldPollResponse: true | |
| }); | |
| console.log(` Tron transaction hash: ${tronTx.txid}`); | |
| console.log(`β Transfer completed in block ${tronTx.blockNumber}\n`); | |
| // Calculate total fees | |
| const totalFees = { | |
| tron: BigInt(tronTx.energy_fee + tronTx.bandwidth_fee + tronTx.net_fee), | |
| layerZero: messagingFee.nativeFee | |
| }; | |
| // Generate monitoring links | |
| const monitoring = { | |
| tronExplorer: `https://tronscan.org/#/transaction/${tronTx.txid}`, | |
| layerZeroExplorer: `https://layerzeroscan.com/tx/${tronTx.txid}`, | |
| polygonExplorer: `https://polygonscan.com/address/${recipientAddress}` | |
| }; | |
| console.log('π Composed MultiHop transfer completed successfully!'); | |
| console.log(` Total fees: ${ethers.formatEther(totalFees.tron)} TRX + ${ethers.formatEther(totalFees.layerZero)} TRX`); | |
| console.log(' Note: Second hop (Arbitrum β Polygon) will be executed automatically by MultiHopComposer'); | |
| return { | |
| tronTx, | |
| totalFees, | |
| monitoring, | |
| guid: tronTx.txid | |
| }; | |
| } | |
| export async function getComposedTransferQuote( | |
| privateKey: string, | |
| tronRpcUrl: string, | |
| arbitrumRpcUrl: string, | |
| recipientAddress: string, | |
| amount: string | |
| ): Promise<ComposedTransferQuote> { | |
| const tronWeb = initializeTronWeb(privateKey, tronRpcUrl); | |
| const arbitrumProvider = new ethers.JsonRpcProvider(arbitrumRpcUrl); | |
| const amountWei = ethers.parseUnits(amount, USDT_DECIMALS); | |
| console.log('π Quoting composed multi-hop transfer...'); | |
| const { sendParams, messagingFee, oftReceipt } = await buildComposedSendParams( | |
| tronWeb, | |
| arbitrumProvider, | |
| recipientAddress, | |
| amountWei | |
| ); | |
| // Get hop chain fee | |
| const hopSendParams = buildHopChainSendParams(recipientAddress, amountWei); | |
| const hopChainFee = await getHopChainQuote(arbitrumProvider, hopSendParams); | |
| const totalFee: MessagingFee = { | |
| nativeFee: messagingFee.nativeFee + hopChainFee.nativeFee, | |
| lzTokenFee: messagingFee.lzTokenFee + hopChainFee.lzTokenFee | |
| }; | |
| console.log(` Tron β Arbitrum fee: ${ethers.formatEther(messagingFee.nativeFee)} TRX`); | |
| console.log(` Arbitrum β Polygon fee: ${ethers.formatEther(hopChainFee.nativeFee)} ETH`); | |
| console.log(` Total fee: ${ethers.formatEther(totalFee.nativeFee)} (TRX + ETH)`); | |
| return { | |
| messagingFee, | |
| oftReceipt, | |
| hopChainFee, | |
| totalFee | |
| }; | |
| } | |
| // Main execution function | |
| export async function main() { | |
| try { | |
| const result = await executeComposedTransfer( | |
| process.env.TRON_PRIVATE_KEY!, | |
| process.env.RECIPIENT_ADDRESS!, | |
| process.env.TRANSFER_AMOUNT!, | |
| process.env.TRON_RPC_URL, | |
| process.env.ARBITRUM_RPC_URL | |
| ); | |
| console.log('\nπ Transfer Summary:'); | |
| console.log(` Transaction: ${result.tronTx.txid}`); | |
| console.log(` Tron Explorer: ${result.monitoring.tronExplorer}`); | |
| console.log(` LayerZero Explorer: ${result.monitoring.layerZeroExplorer}`); | |
| console.log(` Polygon Explorer: ${result.monitoring.polygonExplorer}`); | |
| } catch (error) { | |
| console.error('β Transfer failed:', error); | |
| process.exit(1); | |
| } | |
| } | |
| // Export for use in other files | |
| export default { | |
| main | |
| }; | |
| // if the file is run directly, run the main function | |
| if (require.main === module) { | |
| main(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment