diff --git a/packages/rest-api/src/constants/abis/fastBridge.json b/packages/rest-api/src/constants/abis/fastBridge.json new file mode 100644 index 0000000000..2efeb97a4b --- /dev/null +++ b/packages/rest-api/src/constants/abis/fastBridge.json @@ -0,0 +1,851 @@ +[ + { + "type": "constructor", + "inputs": [ + { "name": "_owner", "type": "address", "internalType": "address" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "DISPUTE_PERIOD", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "FEE_BPS", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "FEE_RATE_MAX", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "GOVERNOR_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "GUARD_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "MIN_DEADLINE_PERIOD", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "REFUNDER_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "REFUND_DELAY", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "RELAYER_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "bridge", + "inputs": [ + { + "name": "params", + "type": "tuple", + "internalType": "struct IFastBridge.BridgeParams", + "components": [ + { + "name": "dstChainId", + "type": "uint32", + "internalType": "uint32" + }, + { "name": "sender", "type": "address", "internalType": "address" }, + { "name": "to", "type": "address", "internalType": "address" }, + { + "name": "originToken", + "type": "address", + "internalType": "address" + }, + { + "name": "destToken", + "type": "address", + "internalType": "address" + }, + { + "name": "originAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "destAmount", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "sendChainGas", "type": "bool", "internalType": "bool" }, + { "name": "deadline", "type": "uint256", "internalType": "uint256" } + ] + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "bridgeProofs", + "inputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "outputs": [ + { "name": "timestamp", "type": "uint96", "internalType": "uint96" }, + { "name": "relayer", "type": "address", "internalType": "address" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "bridgeRelays", + "inputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "bridgeStatuses", + "inputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "outputs": [ + { + "name": "", + "type": "uint8", + "internalType": "enum FastBridge.BridgeStatus" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "canClaim", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "internalType": "bytes32" + }, + { "name": "relayer", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "chainGasAmount", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "claim", + "inputs": [ + { "name": "request", "type": "bytes", "internalType": "bytes" }, + { "name": "to", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "deployBlock", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "dispute", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getBridgeTransaction", + "inputs": [ + { "name": "request", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct IFastBridge.BridgeTransaction", + "components": [ + { + "name": "originChainId", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "destChainId", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "originSender", + "type": "address", + "internalType": "address" + }, + { + "name": "destRecipient", + "type": "address", + "internalType": "address" + }, + { + "name": "originToken", + "type": "address", + "internalType": "address" + }, + { + "name": "destToken", + "type": "address", + "internalType": "address" + }, + { + "name": "originAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "destAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "originFeeAmount", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "sendChainGas", "type": "bool", "internalType": "bool" }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "nonce", "type": "uint256", "internalType": "uint256" } + ] + } + ], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleMember", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "index", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleMemberCount", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonce", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "protocolFeeRate", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "protocolFees", + "inputs": [{ "name": "", "type": "address", "internalType": "address" }], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "prove", + "inputs": [ + { "name": "request", "type": "bytes", "internalType": "bytes" }, + { "name": "destTxHash", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "refund", + "inputs": [ + { "name": "request", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "relay", + "inputs": [ + { "name": "request", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setChainGasAmount", + "inputs": [ + { + "name": "newChainGasAmount", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setProtocolFeeRate", + "inputs": [ + { "name": "newFeeRate", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { "name": "interfaceId", "type": "bytes4", "internalType": "bytes4" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "sweepProtocolFees", + "inputs": [ + { "name": "token", "type": "address", "internalType": "address" }, + { "name": "recipient", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "BridgeDepositClaimed", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "relayer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BridgeDepositRefunded", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BridgeProofDisputed", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "relayer", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BridgeProofProvided", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "relayer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "transactionHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BridgeRelayed", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "relayer", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "originChainId", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + }, + { + "name": "originToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "destToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "originAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "destAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "chainGasAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "BridgeRequested", + "inputs": [ + { + "name": "transactionId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "request", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + }, + { + "name": "destChainId", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + }, + { + "name": "originToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "destToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "originAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "destAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "sendChainGas", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ChainGasAmountUpdated", + "inputs": [ + { + "name": "oldChainGasAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newChainGasAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FeeRateUpdated", + "inputs": [ + { + "name": "oldFeeRate", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "newFeeRate", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FeesSwept", + "inputs": [ + { + "name": "token", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "recipient", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { "type": "error", "name": "AccessControlBadConfirmation", "inputs": [] }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" }, + { "name": "neededRole", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { "name": "target", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "AddressInsufficientBalance", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ] + }, + { "type": "error", "name": "AmountIncorrect", "inputs": [] }, + { "type": "error", "name": "ChainIncorrect", "inputs": [] }, + { "type": "error", "name": "DeadlineExceeded", "inputs": [] }, + { "type": "error", "name": "DeadlineNotExceeded", "inputs": [] }, + { "type": "error", "name": "DeadlineTooShort", "inputs": [] }, + { "type": "error", "name": "DisputePeriodNotPassed", "inputs": [] }, + { "type": "error", "name": "DisputePeriodPassed", "inputs": [] }, + { "type": "error", "name": "FailedInnerCall", "inputs": [] }, + { "type": "error", "name": "MsgValueIncorrect", "inputs": [] }, + { + "type": "error", + "name": "SafeERC20FailedOperation", + "inputs": [ + { "name": "token", "type": "address", "internalType": "address" } + ] + }, + { "type": "error", "name": "SenderIncorrect", "inputs": [] }, + { "type": "error", "name": "StatusIncorrect", "inputs": [] }, + { "type": "error", "name": "TokenNotContract", "inputs": [] }, + { "type": "error", "name": "TransactionRelayed", "inputs": [] }, + { "type": "error", "name": "ZeroAddress", "inputs": [] } +] diff --git a/packages/rest-api/src/constants/abis/fastBridgeRouter.json b/packages/rest-api/src/constants/abis/fastBridgeRouter.json new file mode 100644 index 0000000000..c5617fe1cf --- /dev/null +++ b/packages/rest-api/src/constants/abis/fastBridgeRouter.json @@ -0,0 +1,387 @@ +[ + { + "type": "constructor", + "inputs": [ + { + "name": "owner_", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "receive", + "stateMutability": "payable" + }, + { + "type": "function", + "name": "GAS_REBATE_FLAG", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes1", + "internalType": "bytes1" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "adapterSwap", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenIn", + "type": "address", + "internalType": "address" + }, + { + "name": "amountIn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "address" + }, + { + "name": "rawParams", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [ + { + "name": "amountOut", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "bridge", + "inputs": [ + { + "name": "recipient", + "type": "address", + "internalType": "address" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "originQuery", + "type": "tuple", + "internalType": "struct SwapQuery", + "components": [ + { + "name": "routerAdapter", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "address" + }, + { + "name": "minAmountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rawParams", + "type": "bytes", + "internalType": "bytes" + } + ] + }, + { + "name": "destQuery", + "type": "tuple", + "internalType": "struct SwapQuery", + "components": [ + { + "name": "routerAdapter", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "address" + }, + { + "name": "minAmountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rawParams", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "fastBridge", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getOriginAmountOut", + "inputs": [ + { + "name": "tokenIn", + "type": "address", + "internalType": "address" + }, + { + "name": "rfqTokens", + "type": "address[]", + "internalType": "address[]" + }, + { + "name": "amountIn", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "originQueries", + "type": "tuple[]", + "internalType": "struct SwapQuery[]", + "components": [ + { + "name": "routerAdapter", + "type": "address", + "internalType": "address" + }, + { + "name": "tokenOut", + "type": "address", + "internalType": "address" + }, + { + "name": "minAmountOut", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "deadline", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "rawParams", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setFastBridge", + "inputs": [ + { + "name": "fastBridge_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setSwapQuoter", + "inputs": [ + { + "name": "swapQuoter_", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "swapQuoter", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "FastBridgeSet", + "inputs": [ + { + "name": "newFastBridge", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SwapQuoterSet", + "inputs": [ + { + "name": "newSwapQuoter", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "DeadlineExceeded", + "inputs": [] + }, + { + "type": "error", + "name": "InsufficientOutputAmount", + "inputs": [] + }, + { + "type": "error", + "name": "MsgValueIncorrect", + "inputs": [] + }, + { + "type": "error", + "name": "PoolNotFound", + "inputs": [] + }, + { + "type": "error", + "name": "TokenAddressMismatch", + "inputs": [] + }, + { + "type": "error", + "name": "TokenNotContract", + "inputs": [] + }, + { + "type": "error", + "name": "TokenNotETH", + "inputs": [] + }, + { + "type": "error", + "name": "TokensIdentical", + "inputs": [] + } +] diff --git a/packages/rest-api/src/constants/enums.ts b/packages/rest-api/src/constants/enums.ts new file mode 100644 index 0000000000..a0abf0f327 --- /dev/null +++ b/packages/rest-api/src/constants/enums.ts @@ -0,0 +1,7 @@ +export enum BridgeStatus { + NULL, + REQUESTED, + RELAYER_PROVED, + RELAYER_CLAIMED, + REFUNDED, +} diff --git a/packages/rest-api/src/constants/index.ts b/packages/rest-api/src/constants/index.ts index 12a3cb05a3..73d263d60d 100644 --- a/packages/rest-api/src/constants/index.ts +++ b/packages/rest-api/src/constants/index.ts @@ -27,3 +27,15 @@ export const SUPPORTED_SWAP_CHAIN_IDS = [ CHAINS.OPTIMISM.id, CHAINS.POLYGON.id, ] + +export const FAST_BRIDGE_ROUTER_ADDRESS_MAP = { + '1': '0x00cD000000003f7F682BE4813200893d4e690000', + '10': '0x00cD000000003f7F682BE4813200893d4e690000', + '56': '0x00cD000000003f7F682BE4813200893d4e690000', + '480': '0x00cD000000003f7F682BE4813200893d4e690000', + '8453': '0x00cD000000003f7F682BE4813200893d4e690000', + '42161': '0x00cD000000003f7F682BE4813200893d4e690000', + '59144': '0x00cD000000003f7F682BE4813200893d4e690000', + '81457': '0x00cD000000003f7F682BE4813200893d4e690000', + '534352': '0x00cD000000003f7F682BE4813200893d4e690000', +} diff --git a/packages/rest-api/src/controllers/destinationTxController.ts b/packages/rest-api/src/controllers/destinationTxController.ts index abc3b9e1e9..048a5a47c6 100644 --- a/packages/rest-api/src/controllers/destinationTxController.ts +++ b/packages/rest-api/src/controllers/destinationTxController.ts @@ -1,9 +1,10 @@ import { validationResult } from 'express-validator' -import { ethers } from 'ethers' -import { getTokenDecimals } from '../utils/getTokenDecimals' -import { tokenAddressToToken } from '../utils/tokenAddressToToken' import { logger } from '../middleware/logger' +import { getBridgeStatus } from '../utils/getBridgeStatus' +import { BridgeStatus } from '../constants/enums' +import { fetchBridgeTransaction } from '../utils/fetchBridgeTransaction' +import { serializeBridgeInfo } from '../serializers/serializeBridgeInfo' export const destinationTxController = async (req, res) => { const errors = validationResult(req) @@ -11,84 +12,72 @@ export const destinationTxController = async (req, res) => { return res.status(400).json({ errors: errors.array() }) } + let payload = {} + try { const { originChainId, txHash } = req.query - const graphqlEndpoint = 'https://explorer.omnirpc.io/graphql' - const graphqlQuery = ` - { - bridgeTransactions( - useMv: true - chainIDFrom: ${originChainId} - txnHash: "${txHash}" - ) { - toInfo { - chainID - address - txnHash - value - USDValue - tokenSymbol - tokenAddress - blockNumber - formattedTime - } - } - } - ` - - const graphqlResponse = await fetch(graphqlEndpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ query: graphqlQuery }), - }) - - const graphqlData = await graphqlResponse.json() - const toInfo = graphqlData.data.bridgeTransactions?.[0]?.toInfo || null + const graphqlData = await fetchBridgeTransaction(originChainId, txHash) - if (toInfo) { - const { tokenAddress, value, chainID, ...restToInfo } = toInfo + const { + fromInfo = null, + toInfo = null, + kappa = null, + } = graphqlData?.data?.bridgeTransactions?.[0] || {} - const tokenInfo = tokenAddressToToken(chainID.toString(), tokenAddress) - const tokenDecimals = getTokenDecimals(chainID, tokenAddress) - const formattedValue = ethers.utils.formatUnits(value, tokenDecimals) - - const payload = { - status: 'completed', - toInfo: { - chainID, - ...restToInfo, - tokenSymbol: tokenInfo ? tokenInfo?.symbol : null, - formattedValue: `${formattedValue}`, - }, + if (!fromInfo && !toInfo) { + payload = { + status: 'not found', + fromInfo, + toInfo, } logger.info(`Successful destinationTxController response`, { query: req.query, payload, }) - res.json(payload) - } else { - const payload = { - status: 'pending', - toInfo: null, + return res.status(404).json(payload) + } + + if (fromInfo && !toInfo) { + const status = await getBridgeStatus(originChainId, kappa) + + if (status === BridgeStatus.REFUNDED) { + payload = { + status: 'refunded', + fromInfo: serializeBridgeInfo(fromInfo), + toInfo, + } + } else { + payload = { + status: 'pending', + fromInfo: serializeBridgeInfo(fromInfo), + toInfo, + } } + } - logger.info(`Successful destinationTxController response`, { - query: req.query, - payload, - }) - res.json(payload) + if (fromInfo && toInfo) { + payload = { + status: 'completed', + fromInfo: serializeBridgeInfo(fromInfo), + toInfo: serializeBridgeInfo(toInfo), + } } + + logger.info(`Successful destinationTxController response`, { + query: req.query, + payload, + }) + + return res.json(payload) } catch (err) { logger.error(`Error in destinationTxController`, { query: req.query, error: err.message, stack: err.stack, }) - res.status(500).json({ + return res.status(500).json({ error: 'An unexpected error occurred in /destinationTx. Please try again later.', details: err.message, diff --git a/packages/rest-api/src/serializers/serializeBridgeInfo.ts b/packages/rest-api/src/serializers/serializeBridgeInfo.ts new file mode 100644 index 0000000000..889d731a63 --- /dev/null +++ b/packages/rest-api/src/serializers/serializeBridgeInfo.ts @@ -0,0 +1,19 @@ +import { ethers } from 'ethers' + +import { tokenAddressToToken } from '../utils/tokenAddressToToken' +import { getTokenDecimals } from '../utils/getTokenDecimals' + +export const serializeBridgeInfo = (info) => { + const { tokenAddress, value, chainID, ...restInfo } = info + + const tokenInfo = tokenAddressToToken(chainID.toString(), tokenAddress) + const tokenDecimals = getTokenDecimals(chainID, tokenAddress) + const formattedValue = ethers.utils.formatUnits(value, tokenDecimals) + + return { + chainID, + ...restInfo, + tokenSymbol: tokenInfo ? tokenInfo?.symbol : null, + formattedValue: `${formattedValue}`, + } +} diff --git a/packages/rest-api/src/tests/destinationTxRoute.test.ts b/packages/rest-api/src/tests/destinationTxRoute.test.ts index 064e857f97..a0715865d6 100644 --- a/packages/rest-api/src/tests/destinationTxRoute.test.ts +++ b/packages/rest-api/src/tests/destinationTxRoute.test.ts @@ -16,6 +16,7 @@ describe('Get Destination TX Route', () => { expect(response.status).toBe(200) expect(response.body).toHaveProperty('status') + expect(response.body.status).toBe('completed') expect(response.body).toHaveProperty('toInfo') if (response.body.toInfo) { expect(response.body.toInfo).toHaveProperty('chainID') @@ -29,6 +30,42 @@ describe('Get Destination TX Route', () => { } }, 10000) + it('should return a refunded response for refunded transaction', async () => { + const response = await request(app).get('/destinationTx').query({ + originChainId: '8453', + txHash: + '0x019f84bbb9999e3d34f8c636ddb6b4852bfeeaed423fd70607047f393cbfd070', + }) + + expect(response.status).toBe(200) + expect(response.body).toHaveProperty('status') + expect(response.body.status).toBe('refunded') + expect(response.body).toHaveProperty('fromInfo') + if (response.body.fromInfo) { + expect(response.body.fromInfo).toHaveProperty('chainID') + expect(response.body.fromInfo).toHaveProperty('address') + expect(response.body.fromInfo).toHaveProperty('txnHash') + expect(response.body.fromInfo).toHaveProperty('formattedValue') + expect(response.body.fromInfo).toHaveProperty('USDValue') + expect(response.body.fromInfo).toHaveProperty('tokenSymbol') + expect(response.body.fromInfo).toHaveProperty('blockNumber') + expect(response.body.fromInfo).toHaveProperty('formattedTime') + } + expect(response.body).toHaveProperty('toInfo') + expect(response.body.toInfo).toBeNull() + }, 10000) + + it('should return 404 for non-existent txHash', async () => { + const response = await request(app).get('/destinationTx').query({ + originChainId: '8453', + txHash: + '0x12411d1beafd68de6a20b704d70deb8436effbac1f77fddfc0c7ef14f08e96c3', + }) + + expect(response.status).toBe(404) + expect(response.body.status).toBe('not found') + }, 10000) + it('should return 400 for missing originChainId', async () => { const response = await request(app).get('/destinationTx').query({ txHash: diff --git a/packages/rest-api/src/utils/fetchBridgeTransaction.ts b/packages/rest-api/src/utils/fetchBridgeTransaction.ts new file mode 100644 index 0000000000..d5e9473b41 --- /dev/null +++ b/packages/rest-api/src/utils/fetchBridgeTransaction.ts @@ -0,0 +1,51 @@ +export const fetchBridgeTransaction = async ( + originChainId: number | string, + txHash: string +) => { + const graphqlEndpoint = 'https://explorer.omnirpc.io/graphql' + const graphqlQuery = ` + { + bridgeTransactions( + useMv: true + chainIDFrom: ${originChainId} + txnHash: "${txHash}" + ) { + kappa + fromInfo { + chainID + address + txnHash + value + USDValue + tokenSymbol + tokenAddress + blockNumber + formattedTime + } + toInfo { + chainID + address + txnHash + value + USDValue + tokenSymbol + tokenAddress + blockNumber + formattedTime + } + } + } + ` + + const graphqlResponse = await fetch(graphqlEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ query: graphqlQuery }), + }) + + const graphqlData = await graphqlResponse.json() + + return graphqlData +} diff --git a/packages/rest-api/src/utils/getBridgeStatus.ts b/packages/rest-api/src/utils/getBridgeStatus.ts new file mode 100644 index 0000000000..ea249c201e --- /dev/null +++ b/packages/rest-api/src/utils/getBridgeStatus.ts @@ -0,0 +1,37 @@ +import { ethers } from 'ethers' + +import fastBridgeAbi from '../constants/abis/fastBridge.json' +import fastBridgeRouterAbi from '../constants/abis/fastBridgeRouter.json' +import { FAST_BRIDGE_ROUTER_ADDRESS_MAP } from '../constants' +import { CHAINS_BY_ID } from '../constants/chains' + +export const getBridgeStatus = async ( + originChainId: string | number, + kappa: string +) => { + const chainInfo = CHAINS_BY_ID[originChainId] + const rpcUrl = chainInfo.rpcUrls.primary || chainInfo.rpcUrls.fallback + const provider = new ethers.providers.JsonRpcProvider(rpcUrl) + + const routerAddress = FAST_BRIDGE_ROUTER_ADDRESS_MAP[originChainId] + + const fastBridgeRouterContract = new ethers.Contract( + routerAddress, + fastBridgeRouterAbi, + provider + ) + + const fastBridgeAddress = await fastBridgeRouterContract.fastBridge() + + const fastBridgeContract = new ethers.Contract( + fastBridgeAddress, + fastBridgeAbi, + provider + ) + + const status = await fastBridgeContract.bridgeStatuses( + kappa.startsWith('0x') ? kappa : `0x${kappa}` + ) + + return status +}