From 3cf6e7b4bcb449c78a50cfd85d2fcdcbe451ab2e Mon Sep 17 00:00:00 2001 From: Korbinian Date: Mon, 13 May 2024 16:09:03 +0200 Subject: [PATCH] feat(bridge-ui): quota manager check (#17024) --- .../config/sample/configuredBridges.example | 8 +- .../schemas/configuredBridges.schema.json | 6 +- packages/bridge-ui/src/abi/index.ts | 731 ++++++++++++------ .../Dialogs/ClaimDialog/ClaimDialog.svelte | 6 +- .../Dialogs/RetryDialog/RetryDialog.svelte | 13 +- .../components/Dialogs/RetryDialog/types.ts | 3 +- .../ClaimPreCheck.svelte | 91 ++- .../src/components/Tooltip/Tooltip.svelte | 4 +- packages/bridge-ui/src/i18n/en.json | 17 +- .../bridge-ui/src/libs/bridge/ETHBridge.ts | 10 +- .../src/libs/bridge/checkBridgeQuota.ts | 63 ++ .../libs/bridge/getContractAddressByType.ts | 6 + packages/bridge-ui/src/libs/bridge/types.ts | 5 +- .../src/libs/relayer/RelayerAPIService.ts | 1 + packages/bridge-ui/wagmi.config.ts | 5 + 15 files changed, 704 insertions(+), 265 deletions(-) rename packages/bridge-ui/src/components/Dialogs/{ClaimDialog/ClaimSteps => Shared}/ClaimPreCheck.svelte (50%) create mode 100644 packages/bridge-ui/src/libs/bridge/checkBridgeQuota.ts diff --git a/packages/bridge-ui/config/sample/configuredBridges.example b/packages/bridge-ui/config/sample/configuredBridges.example index d465d53fbdd..f48f9a2db07 100644 --- a/packages/bridge-ui/config/sample/configuredBridges.example +++ b/packages/bridge-ui/config/sample/configuredBridges.example @@ -9,7 +9,8 @@ "erc721VaultAddress": "", "erc1155VaultAddress": "", "crossChainSyncAddress": "", - "signalServiceAddress": "" + "signalServiceAddress": "", + "quotaManagerAddress: "" } }, { @@ -21,7 +22,8 @@ "erc721VaultAddress": "", "erc1155VaultAddress": "", "crossChainSyncAddress": "", - "signalServiceAddress": "" + "signalServiceAddress": "", + "quotaManagerAddress: "" } }, { @@ -34,6 +36,7 @@ "erc1155VaultAddress": "", "crossChainSyncAddress": "", "signalServiceAddress": "", + "quotaManagerAddress: "" "hops": [ { "chainId": , @@ -53,6 +56,7 @@ "erc1155VaultAddress": "", "crossChainSyncAddress": "", "signalServiceAddress": "", + "quotaManagerAddress: "" "hops": [ { "chainId": , diff --git a/packages/bridge-ui/config/schemas/configuredBridges.schema.json b/packages/bridge-ui/config/schemas/configuredBridges.schema.json index fa63413d2d0..daf9501e2be 100644 --- a/packages/bridge-ui/config/schemas/configuredBridges.schema.json +++ b/packages/bridge-ui/config/schemas/configuredBridges.schema.json @@ -22,9 +22,6 @@ "erc20VaultAddress": { "type": "string" }, - "etherVaultAddress": { - "type": "string" - }, "erc721VaultAddress": { "type": "string" }, @@ -37,6 +34,9 @@ "signalServiceAddress": { "type": "string" }, + "quotaManagerAddress": { + "type": "string" + }, "hops": { "type": "array", "default": [], diff --git a/packages/bridge-ui/src/abi/index.ts b/packages/bridge-ui/src/abi/index.ts index 8006ad93051..c6e6f291b3a 100644 --- a/packages/bridge-ui/src/abi/index.ts +++ b/packages/bridge-ui/src/abi/index.ts @@ -109,6 +109,13 @@ export const bridgeAbi = [ outputs: [{ name: '', internalType: 'bytes32', type: 'bytes32' }], stateMutability: 'pure', }, + { + type: 'function', + inputs: [], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, { type: 'function', inputs: [ @@ -693,6 +700,7 @@ export const bridgeAbi = [ { type: 'error', inputs: [], name: 'B_RETRY_FAILED' }, { type: 'error', inputs: [], name: 'B_SIGNAL_NOT_RECEIVED' }, { type: 'error', inputs: [], name: 'ETH_TRANSFER_FAILED' }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, @@ -814,6 +822,13 @@ export const erc1155VaultAbi = [ outputs: [{ name: 'btoken', internalType: 'address', type: 'address' }], stateMutability: 'view', }, + { + type: 'function', + inputs: [], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, { type: 'function', inputs: [ @@ -1005,10 +1020,10 @@ export const erc1155VaultAbi = [ }, { type: 'function', - inputs: [{ name: 'interfaceId', internalType: 'bytes4', type: 'bytes4' }], + inputs: [{ name: '_interfaceId', internalType: 'bytes4', type: 'bytes4' }], name: 'supportsInterface', outputs: [{ name: '', internalType: 'bool', type: 'bool' }], - stateMutability: 'pure', + stateMutability: 'view', }, { type: 'function', @@ -1326,6 +1341,7 @@ export const erc1155VaultAbi = [ name: 'Upgraded', }, { type: 'error', inputs: [], name: 'ETH_TRANSFER_FAILED' }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, @@ -1341,8 +1357,8 @@ export const erc1155VaultAbi = [ }, { type: 'error', inputs: [], name: 'VAULT_INTERFACE_NOT_SUPPORTED' }, { type: 'error', inputs: [], name: 'VAULT_INVALID_AMOUNT' }, - { type: 'error', inputs: [], name: 'VAULT_INVALID_TO' }, { type: 'error', inputs: [], name: 'VAULT_INVALID_TOKEN' }, + { type: 'error', inputs: [], name: 'VAULT_INVALID_TO_ADDR' }, { type: 'error', inputs: [], name: 'VAULT_MAX_TOKEN_PER_TXN_EXCEEDED' }, { type: 'error', inputs: [], name: 'VAULT_PERMISSION_DENIED' }, { type: 'error', inputs: [], name: 'VAULT_TOKEN_ARRAY_MISMATCH' }, @@ -1354,6 +1370,13 @@ export const erc1155VaultAbi = [ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// export const erc20VaultAbi = [ + { + type: 'function', + inputs: [], + name: 'MIN_MIGRATION_DELAY', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, { type: 'function', inputs: [], @@ -1419,6 +1442,13 @@ export const erc20VaultAbi = [ outputs: [{ name: 'btokenOld_', internalType: 'address', type: 'address' }], stateMutability: 'nonpayable', }, + { + type: 'function', + inputs: [], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, { type: 'function', inputs: [ @@ -1429,6 +1459,16 @@ export const erc20VaultAbi = [ outputs: [], stateMutability: 'nonpayable', }, + { + type: 'function', + inputs: [ + { name: 'chainId', internalType: 'uint256', type: 'uint256' }, + { name: 'ctoken', internalType: 'address', type: 'address' }, + ], + name: 'lastMigrationStart', + outputs: [{ name: 'timestamp', internalType: 'uint256', type: 'uint256' }], + stateMutability: 'view', + }, { type: 'function', inputs: [], @@ -1586,7 +1626,7 @@ export const erc20VaultAbi = [ inputs: [{ name: '_interfaceId', internalType: 'bytes4', type: 'bytes4' }], name: 'supportsInterface', outputs: [{ name: '', internalType: 'bool', type: 'bool' }], - stateMutability: 'pure', + stateMutability: 'view', }, { type: 'function', @@ -1941,6 +1981,7 @@ export const erc20VaultAbi = [ name: 'Upgraded', }, { type: 'error', inputs: [], name: 'ETH_TRANSFER_FAILED' }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, @@ -1958,9 +1999,9 @@ export const erc20VaultAbi = [ { type: 'error', inputs: [], name: 'VAULT_CTOKEN_MISMATCH' }, { type: 'error', inputs: [], name: 'VAULT_INVALID_AMOUNT' }, { type: 'error', inputs: [], name: 'VAULT_INVALID_NEW_BTOKEN' }, - { type: 'error', inputs: [], name: 'VAULT_INVALID_TO' }, { type: 'error', inputs: [], name: 'VAULT_INVALID_TOKEN' }, - { type: 'error', inputs: [], name: 'VAULT_NOT_SAME_OWNER' }, + { type: 'error', inputs: [], name: 'VAULT_INVALID_TO_ADDR' }, + { type: 'error', inputs: [], name: 'VAULT_LAST_MIGRATION_TOO_CLOSE' }, { type: 'error', inputs: [], name: 'VAULT_PERMISSION_DENIED' }, { type: 'error', inputs: [], name: 'ZERO_ADDR_MANAGER' }, ] as const @@ -2013,6 +2054,13 @@ export const erc721VaultAbi = [ outputs: [{ name: 'btoken', internalType: 'address', type: 'address' }], stateMutability: 'view', }, + { + type: 'function', + inputs: [], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, { type: 'function', inputs: [ @@ -2193,7 +2241,7 @@ export const erc721VaultAbi = [ inputs: [{ name: '_interfaceId', internalType: 'bytes4', type: 'bytes4' }], name: 'supportsInterface', outputs: [{ name: '', internalType: 'bool', type: 'bool' }], - stateMutability: 'pure', + stateMutability: 'view', }, { type: 'function', @@ -2511,6 +2559,7 @@ export const erc721VaultAbi = [ name: 'Upgraded', }, { type: 'error', inputs: [], name: 'ETH_TRANSFER_FAILED' }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, @@ -2526,8 +2575,8 @@ export const erc721VaultAbi = [ }, { type: 'error', inputs: [], name: 'VAULT_INTERFACE_NOT_SUPPORTED' }, { type: 'error', inputs: [], name: 'VAULT_INVALID_AMOUNT' }, - { type: 'error', inputs: [], name: 'VAULT_INVALID_TO' }, { type: 'error', inputs: [], name: 'VAULT_INVALID_TOKEN' }, + { type: 'error', inputs: [], name: 'VAULT_INVALID_TO_ADDR' }, { type: 'error', inputs: [], name: 'VAULT_MAX_TOKEN_PER_TXN_EXCEEDED' }, { type: 'error', inputs: [], name: 'VAULT_PERMISSION_DENIED' }, { type: 'error', inputs: [], name: 'VAULT_TOKEN_ARRAY_MISMATCH' }, @@ -2577,10 +2626,10 @@ export const erc1155Abi = [ type: 'function', inputs: [ { name: '_account', internalType: 'address', type: 'address' }, - { name: '_tokenId', internalType: 'uint256', type: 'uint256' }, - { name: '_amount', internalType: 'uint256', type: 'uint256' }, + { name: '_ids', internalType: 'uint256[]', type: 'uint256[]' }, + { name: '_amounts', internalType: 'uint256[]', type: 'uint256[]' }, ], - name: 'burn', + name: 'burnBatch', outputs: [], stateMutability: 'nonpayable', }, @@ -2594,6 +2643,13 @@ export const erc1155Abi = [ ], stateMutability: 'view', }, + { + type: 'function', + inputs: [], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, { type: 'function', inputs: [ @@ -2625,17 +2681,6 @@ export const erc1155Abi = [ outputs: [{ name: '', internalType: 'uint64', type: 'uint64' }], stateMutability: 'view', }, - { - type: 'function', - inputs: [ - { name: '_to', internalType: 'address', type: 'address' }, - { name: '_tokenId', internalType: 'uint256', type: 'uint256' }, - { name: '_amount', internalType: 'uint256', type: 'uint256' }, - ], - name: 'mint', - outputs: [], - stateMutability: 'nonpayable', - }, { type: 'function', inputs: [ @@ -3016,8 +3061,11 @@ export const erc1155Abi = [ ], name: 'Upgraded', }, - { type: 'error', inputs: [], name: 'BTOKEN_CANNOT_RECEIVE' }, { type: 'error', inputs: [], name: 'BTOKEN_INVALID_PARAMS' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_PARAMS' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_TO_ADDR' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_TO_ADDR' }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, @@ -3042,15 +3090,8 @@ export const erc20Abi = [ { type: 'function', inputs: [], - name: 'CLOCK_MODE', - outputs: [{ name: '', internalType: 'string', type: 'string' }], - stateMutability: 'view', - }, - { - type: 'function', - inputs: [], - name: 'DOMAIN_SEPARATOR', - outputs: [{ name: '', internalType: 'bytes32', type: 'bytes32' }], + name: '__srcDecimals', + outputs: [{ name: '', internalType: 'uint8', type: 'uint8' }], stateMutability: 'view', }, { @@ -3121,33 +3162,6 @@ export const erc20Abi = [ outputs: [], stateMutability: 'nonpayable', }, - { - type: 'function', - inputs: [ - { name: 'account', internalType: 'address', type: 'address' }, - { name: 'pos', internalType: 'uint32', type: 'uint32' }, - ], - name: 'checkpoints', - outputs: [ - { - name: '', - internalType: 'struct ERC20VotesUpgradeable.Checkpoint', - type: 'tuple', - components: [ - { name: 'fromBlock', internalType: 'uint32', type: 'uint32' }, - { name: 'votes', internalType: 'uint224', type: 'uint224' }, - ], - }, - ], - stateMutability: 'view', - }, - { - type: 'function', - inputs: [], - name: 'clock', - outputs: [{ name: '', internalType: 'uint48', type: 'uint48' }], - stateMutability: 'view', - }, { type: 'function', inputs: [], @@ -3165,71 +3179,11 @@ export const erc20Abi = [ outputs: [{ name: '', internalType: 'bool', type: 'bool' }], stateMutability: 'nonpayable', }, - { - type: 'function', - inputs: [{ name: 'delegatee', internalType: 'address', type: 'address' }], - name: 'delegate', - outputs: [], - stateMutability: 'nonpayable', - }, - { - type: 'function', - inputs: [ - { name: 'delegatee', internalType: 'address', type: 'address' }, - { name: 'nonce', internalType: 'uint256', type: 'uint256' }, - { name: 'expiry', internalType: 'uint256', type: 'uint256' }, - { name: 'v', internalType: 'uint8', type: 'uint8' }, - { name: 'r', internalType: 'bytes32', type: 'bytes32' }, - { name: 's', internalType: 'bytes32', type: 'bytes32' }, - ], - name: 'delegateBySig', - outputs: [], - stateMutability: 'nonpayable', - }, - { - type: 'function', - inputs: [{ name: 'account', internalType: 'address', type: 'address' }], - name: 'delegates', - outputs: [{ name: '', internalType: 'address', type: 'address' }], - stateMutability: 'view', - }, { type: 'function', inputs: [], - name: 'eip712Domain', - outputs: [ - { name: 'fields', internalType: 'bytes1', type: 'bytes1' }, - { name: 'name', internalType: 'string', type: 'string' }, - { name: 'version', internalType: 'string', type: 'string' }, - { name: 'chainId', internalType: 'uint256', type: 'uint256' }, - { name: 'verifyingContract', internalType: 'address', type: 'address' }, - { name: 'salt', internalType: 'bytes32', type: 'bytes32' }, - { name: 'extensions', internalType: 'uint256[]', type: 'uint256[]' }, - ], - stateMutability: 'view', - }, - { - type: 'function', - inputs: [{ name: 'timepoint', internalType: 'uint256', type: 'uint256' }], - name: 'getPastTotalSupply', - outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], - stateMutability: 'view', - }, - { - type: 'function', - inputs: [ - { name: 'account', internalType: 'address', type: 'address' }, - { name: 'timepoint', internalType: 'uint256', type: 'uint256' }, - ], - name: 'getPastVotes', - outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], - stateMutability: 'view', - }, - { - type: 'function', - inputs: [{ name: 'account', internalType: 'address', type: 'address' }], - name: 'getVotes', - outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], stateMutability: 'view', }, { @@ -3257,6 +3211,13 @@ export const erc20Abi = [ outputs: [], stateMutability: 'nonpayable', }, + { + type: 'function', + inputs: [], + name: 'isMigratingOut', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, { type: 'function', inputs: [], @@ -3295,20 +3256,6 @@ export const erc20Abi = [ outputs: [{ name: '', internalType: 'string', type: 'string' }], stateMutability: 'view', }, - { - type: 'function', - inputs: [{ name: 'owner', internalType: 'address', type: 'address' }], - name: 'nonces', - outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], - stateMutability: 'view', - }, - { - type: 'function', - inputs: [{ name: 'account', internalType: 'address', type: 'address' }], - name: 'numCheckpoints', - outputs: [{ name: '', internalType: 'uint32', type: 'uint32' }], - stateMutability: 'view', - }, { type: 'function', inputs: [], @@ -3337,21 +3284,6 @@ export const erc20Abi = [ outputs: [{ name: '', internalType: 'address', type: 'address' }], stateMutability: 'view', }, - { - type: 'function', - inputs: [ - { name: 'owner', internalType: 'address', type: 'address' }, - { name: 'spender', internalType: 'address', type: 'address' }, - { name: 'value', internalType: 'uint256', type: 'uint256' }, - { name: 'deadline', internalType: 'uint256', type: 'uint256' }, - { name: 'v', internalType: 'uint8', type: 'uint8' }, - { name: 'r', internalType: 'bytes32', type: 'bytes32' }, - { name: 's', internalType: 'bytes32', type: 'bytes32' }, - ], - name: 'permit', - outputs: [], - stateMutability: 'nonpayable', - }, { type: 'function', inputs: [], @@ -3530,67 +3462,41 @@ export const erc20Abi = [ type: 'event', anonymous: false, inputs: [ - { - name: 'delegator', - internalType: 'address', - type: 'address', - indexed: true, - }, - { - name: 'fromDelegate', - internalType: 'address', - type: 'address', - indexed: true, - }, - { - name: 'toDelegate', - internalType: 'address', - type: 'address', - indexed: true, - }, + { name: 'version', internalType: 'uint8', type: 'uint8', indexed: false }, ], - name: 'DelegateChanged', + name: 'Initialized', }, { type: 'event', anonymous: false, inputs: [ { - name: 'delegate', + name: 'migratedFrom', internalType: 'address', type: 'address', indexed: true, }, { - name: 'previousBalance', - internalType: 'uint256', - type: 'uint256', - indexed: false, + name: 'account', + internalType: 'address', + type: 'address', + indexed: true, }, { - name: 'newBalance', + name: 'amount', internalType: 'uint256', type: 'uint256', indexed: false, }, ], - name: 'DelegateVotesChanged', - }, - { type: 'event', anonymous: false, inputs: [], name: 'EIP712DomainChanged' }, - { - type: 'event', - anonymous: false, - inputs: [ - { name: 'version', internalType: 'uint8', type: 'uint8', indexed: false }, - ], - name: 'Initialized', + name: 'MigratedFrom', }, { type: 'event', anonymous: false, inputs: [ { - name: 'fromToken', + name: 'migratedTo', internalType: 'address', type: 'address', indexed: true, @@ -3716,11 +3622,12 @@ export const erc20Abi = [ ], name: 'Upgraded', }, - { type: 'error', inputs: [], name: 'BB_INVALID_PARAMS' }, - { type: 'error', inputs: [], name: 'BB_MINT_DISALLOWED' }, - { type: 'error', inputs: [], name: 'BB_PERMISSION_DENIED' }, - { type: 'error', inputs: [], name: 'BTOKEN_CANNOT_RECEIVE' }, { type: 'error', inputs: [], name: 'BTOKEN_INVALID_PARAMS' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_PARAMS' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_TO_ADDR' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_TO_ADDR' }, + { type: 'error', inputs: [], name: 'BTOKEN_MINT_DISALLOWED' }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, @@ -3800,6 +3707,13 @@ export const erc721Abi = [ outputs: [{ name: '', internalType: 'address', type: 'address' }], stateMutability: 'view', }, + { + type: 'function', + inputs: [], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, { type: 'function', inputs: [ @@ -4217,9 +4131,12 @@ export const erc721Abi = [ ], name: 'Upgraded', }, - { type: 'error', inputs: [], name: 'BTOKEN_CANNOT_RECEIVE' }, { type: 'error', inputs: [], name: 'BTOKEN_INVALID_BURN' }, { type: 'error', inputs: [], name: 'BTOKEN_INVALID_PARAMS' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_PARAMS' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_TO_ADDR' }, + { type: 'error', inputs: [], name: 'BTOKEN_INVALID_TO_ADDR' }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, @@ -4403,71 +4320,420 @@ export const freeMintErc20Abi = [ ] as const ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// SignalService +// QuotaManager ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -export const signalServiceAbi = [ +export const quotaManagerAbi = [ { type: 'function', - inputs: [ - { name: '_chainId', internalType: 'uint64', type: 'uint64' }, - { name: '_kind', internalType: 'bytes32', type: 'bytes32' }, - { name: '_blockId', internalType: 'uint64', type: 'uint64' }, - ], - name: 'getSyncedChainData', - outputs: [ - { name: 'blockId_', internalType: 'uint64', type: 'uint64' }, - { name: 'chainData_', internalType: 'bytes32', type: 'bytes32' }, - ], - stateMutability: 'view', + inputs: [], + name: 'acceptOwnership', + outputs: [], + stateMutability: 'nonpayable', }, { type: 'function', - inputs: [ - { name: '_chainId', internalType: 'uint64', type: 'uint64' }, - { name: '_kind', internalType: 'bytes32', type: 'bytes32' }, - { name: '_blockId', internalType: 'uint64', type: 'uint64' }, - { name: '_chainData', internalType: 'bytes32', type: 'bytes32' }, - ], - name: 'isChainDataSynced', - outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + inputs: [], + name: 'addressManager', + outputs: [{ name: '', internalType: 'address', type: 'address' }], stateMutability: 'view', }, { type: 'function', inputs: [ - { name: '_app', internalType: 'address', type: 'address' }, - { name: '_signal', internalType: 'bytes32', type: 'bytes32' }, + { name: '_token', internalType: 'address', type: 'address' }, + { name: '_leap', internalType: 'uint256', type: 'uint256' }, ], - name: 'isSignalSent', - outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + name: 'availableQuota', + outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }], stateMutability: 'view', }, { type: 'function', inputs: [ - { name: '_chainId', internalType: 'uint64', type: 'uint64' }, - { name: '_app', internalType: 'address', type: 'address' }, - { name: '_signal', internalType: 'bytes32', type: 'bytes32' }, - { name: '_proof', internalType: 'bytes', type: 'bytes' }, - ], - name: 'proveSignalReceived', - outputs: [ - { name: 'numCacheOps_', internalType: 'uint256', type: 'uint256' }, + { name: '_token', internalType: 'address', type: 'address' }, + { name: '_amount', internalType: 'uint256', type: 'uint256' }, ], + name: 'consumeQuota', + outputs: [], stateMutability: 'nonpayable', }, { type: 'function', - inputs: [{ name: '_signal', internalType: 'bytes32', type: 'bytes32' }], - name: 'sendSignal', - outputs: [{ name: 'slot_', internalType: 'bytes32', type: 'bytes32' }], - stateMutability: 'nonpayable', + inputs: [], + name: 'inNonReentrant', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', }, { type: 'function', inputs: [ - { name: '_chainId', internalType: 'uint64', type: 'uint64' }, + { name: '_owner', internalType: 'address', type: 'address' }, + { name: '_addressManager', internalType: 'address', type: 'address' }, + { name: '_quotaPeriod', internalType: 'uint24', type: 'uint24' }, + ], + name: 'init', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'lastUnpausedAt', + outputs: [{ name: '', internalType: 'uint64', type: 'uint64' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'owner', + outputs: [{ name: '', internalType: 'address', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'pause', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'paused', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'pendingOwner', + outputs: [{ name: '', internalType: 'address', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'proxiableUUID', + outputs: [{ name: '', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'quotaPeriod', + outputs: [{ name: '', internalType: 'uint24', type: 'uint24' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_chainId', internalType: 'uint64', type: 'uint64' }, + { name: '_name', internalType: 'bytes32', type: 'bytes32' }, + { name: '_allowZeroAddress', internalType: 'bool', type: 'bool' }, + ], + name: 'resolve', + outputs: [{ name: '', internalType: 'address payable', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: '_name', internalType: 'bytes32', type: 'bytes32' }, + { name: '_allowZeroAddress', internalType: 'bool', type: 'bool' }, + ], + name: 'resolve', + outputs: [{ name: '', internalType: 'address payable', type: 'address' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'token', internalType: 'address', type: 'address' }], + name: 'tokenQuota', + outputs: [ + { name: 'updatedAt', internalType: 'uint48', type: 'uint48' }, + { name: 'quota', internalType: 'uint104', type: 'uint104' }, + { name: 'available', internalType: 'uint104', type: 'uint104' }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [{ name: 'newOwner', internalType: 'address', type: 'address' }], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [], + name: 'unpause', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_token', internalType: 'address', type: 'address' }, + { name: '_quota', internalType: 'uint104', type: 'uint104' }, + ], + name: 'updateQuota', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'newImplementation', internalType: 'address', type: 'address' }, + ], + name: 'upgradeTo', + outputs: [], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: 'newImplementation', internalType: 'address', type: 'address' }, + { name: 'data', internalType: 'bytes', type: 'bytes' }, + ], + name: 'upgradeToAndCall', + outputs: [], + stateMutability: 'payable', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'previousAdmin', + internalType: 'address', + type: 'address', + indexed: false, + }, + { + name: 'newAdmin', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'AdminChanged', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'beacon', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'BeaconUpgraded', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { name: 'version', internalType: 'uint8', type: 'uint8', indexed: false }, + ], + name: 'Initialized', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'previousOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'newOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'OwnershipTransferStarted', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'previousOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'newOwner', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'OwnershipTransferred', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'Paused', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'token', + internalType: 'address', + type: 'address', + indexed: true, + }, + { + name: 'oldQuota', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + { + name: 'newQuota', + internalType: 'uint256', + type: 'uint256', + indexed: false, + }, + ], + name: 'QuotaUpdated', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'account', + internalType: 'address', + type: 'address', + indexed: false, + }, + ], + name: 'Unpaused', + }, + { + type: 'event', + anonymous: false, + inputs: [ + { + name: 'implementation', + internalType: 'address', + type: 'address', + indexed: true, + }, + ], + name: 'Upgraded', + }, + { type: 'error', inputs: [], name: 'FUNC_NOT_IMPLEMENTED' }, + { type: 'error', inputs: [], name: 'INVALID_PAUSE_STATUS' }, + { type: 'error', inputs: [], name: 'QM_INVALID_PARAM' }, + { type: 'error', inputs: [], name: 'QM_OUT_OF_QUOTA' }, + { type: 'error', inputs: [], name: 'REENTRANT_CALL' }, + { type: 'error', inputs: [], name: 'RESOLVER_DENIED' }, + { type: 'error', inputs: [], name: 'RESOLVER_INVALID_MANAGER' }, + { type: 'error', inputs: [], name: 'RESOLVER_UNEXPECTED_CHAINID' }, + { + type: 'error', + inputs: [ + { name: 'chainId', internalType: 'uint64', type: 'uint64' }, + { name: 'name', internalType: 'bytes32', type: 'bytes32' }, + ], + name: 'RESOLVER_ZERO_ADDR', + }, + { type: 'error', inputs: [], name: 'ZERO_ADDR_MANAGER' }, +] as const + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SignalService +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +export const signalServiceAbi = [ + { + type: 'function', + inputs: [ + { name: '_chainId', internalType: 'uint64', type: 'uint64' }, + { name: '_kind', internalType: 'bytes32', type: 'bytes32' }, + { name: '_blockId', internalType: 'uint64', type: 'uint64' }, + ], + name: 'getSyncedChainData', + outputs: [ + { name: 'blockId_', internalType: 'uint64', type: 'uint64' }, + { name: 'chainData_', internalType: 'bytes32', type: 'bytes32' }, + ], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: '_chainId', internalType: 'uint64', type: 'uint64' }, + { name: '_kind', internalType: 'bytes32', type: 'bytes32' }, + { name: '_blockId', internalType: 'uint64', type: 'uint64' }, + { name: '_chainData', internalType: 'bytes32', type: 'bytes32' }, + ], + name: 'isChainDataSynced', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: '_app', internalType: 'address', type: 'address' }, + { name: '_signal', internalType: 'bytes32', type: 'bytes32' }, + ], + name: 'isSignalSent', + outputs: [{ name: '', internalType: 'bool', type: 'bool' }], + stateMutability: 'view', + }, + { + type: 'function', + inputs: [ + { name: '_chainId', internalType: 'uint64', type: 'uint64' }, + { name: '_app', internalType: 'address', type: 'address' }, + { name: '_signal', internalType: 'bytes32', type: 'bytes32' }, + { name: '_proof', internalType: 'bytes', type: 'bytes' }, + ], + name: 'proveSignalReceived', + outputs: [ + { name: 'numCacheOps_', internalType: 'uint256', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [{ name: '_signal', internalType: 'bytes32', type: 'bytes32' }], + name: 'sendSignal', + outputs: [{ name: 'slot_', internalType: 'bytes32', type: 'bytes32' }], + stateMutability: 'nonpayable', + }, + { + type: 'function', + inputs: [ + { name: '_chainId', internalType: 'uint64', type: 'uint64' }, { name: '_kind', internalType: 'bytes32', type: 'bytes32' }, { name: '_blockId', internalType: 'uint64', type: 'uint64' }, ], @@ -4504,7 +4770,12 @@ export const signalServiceAbi = [ anonymous: false, inputs: [ { name: 'addr', internalType: 'address', type: 'address', indexed: true }, - { name: 'authrized', internalType: 'bool', type: 'bool', indexed: false }, + { + name: 'authorized', + internalType: 'bool', + type: 'bool', + indexed: false, + }, ], name: 'Authorized', }, diff --git a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte b/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte index 608af1b1732..20c6731de63 100644 --- a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte +++ b/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimDialog.svelte @@ -29,10 +29,10 @@ import { pendingTransactions } from '$stores/pendingTransactions'; import { ClaimConfirmStep, ReviewStep } from '../Shared'; + import ClaimPreCheck from '../Shared/ClaimPreCheck.svelte'; import { ClaimAction } from '../Shared/types'; import { DialogStep, DialogStepper } from '../Stepper'; import ClaimStepNavigation from './ClaimStepNavigation.svelte'; - import ClaimPreCheck from './ClaimSteps/ClaimPreCheck.svelte'; import { ClaimSteps, INITIAL_STEP } from './types'; const log = getLogger('ClaimDialog'); @@ -171,8 +171,6 @@ claimingDone = false; }; - let checkingPrerequisites: boolean; - let previousStep: ClaimSteps; $: if (activeStep !== previousStep) { previousStep = activeStep; @@ -202,7 +200,7 @@ isActive={activeStep === ClaimSteps.CONFIRM}>{$t('bridge.step.confirm.title')} {#if activeStep === ClaimSteps.CHECK} - + {:else if activeStep === ClaimSteps.REVIEW} {:else if activeStep === ClaimSteps.CONFIRM} diff --git a/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte b/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte index 664846463b4..afe32b1f25f 100644 --- a/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte +++ b/packages/bridge-ui/src/components/Dialogs/RetryDialog/RetryDialog.svelte @@ -17,6 +17,7 @@ import Claim from '../Claim.svelte'; import { ClaimConfirmStep, ReviewStep } from '../Shared'; + import ClaimPreCheck from '../Shared/ClaimPreCheck.svelte'; import { ClaimAction } from '../Shared/types'; import RetryStepNavigation from './RetryStepNavigation.svelte'; import RetryOptionStep from './RetrySteps/RetryOptionStep.svelte'; @@ -34,7 +35,7 @@ const dialogId = `dialog-${uid()}`; - export let activeStep: RetrySteps = RetrySteps.SELECT; + export let activeStep: RetrySteps = INITIAL_STEP; let canContinue = false; let retrying: boolean; @@ -42,6 +43,8 @@ let ClaimComponent: Claim; let isDesktopOrLarger = false; + let hideContinueButton = false; + let txHash: Hash; const handleRetryError = () => { @@ -116,6 +119,10 @@
+ {$t('transactions.claim.steps.pre_check.title')} {$t('common.confirm')} - {#if activeStep === RetrySteps.SELECT} + {#if activeStep === RetrySteps.CHECK} + + {:else if activeStep === RetrySteps.SELECT} {:else if activeStep === RetrySteps.REVIEW} diff --git a/packages/bridge-ui/src/components/Dialogs/RetryDialog/types.ts b/packages/bridge-ui/src/components/Dialogs/RetryDialog/types.ts index 5d2562bc92d..182804cd24d 100644 --- a/packages/bridge-ui/src/components/Dialogs/RetryDialog/types.ts +++ b/packages/bridge-ui/src/components/Dialogs/RetryDialog/types.ts @@ -1,10 +1,11 @@ export const enum RetrySteps { + CHECK, SELECT, REVIEW, CONFIRM, } -export const INITIAL_STEP = RetrySteps.SELECT; +export const INITIAL_STEP = RetrySteps.CHECK; export const enum RetryStatus { PENDING, diff --git a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimSteps/ClaimPreCheck.svelte b/packages/bridge-ui/src/components/Dialogs/Shared/ClaimPreCheck.svelte similarity index 50% rename from packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimSteps/ClaimPreCheck.svelte rename to packages/bridge-ui/src/components/Dialogs/Shared/ClaimPreCheck.svelte index e6fc289fe35..94e66690b83 100644 --- a/packages/bridge-ui/src/components/Dialogs/ClaimDialog/ClaimSteps/ClaimPreCheck.svelte +++ b/packages/bridge-ui/src/components/Dialogs/Shared/ClaimPreCheck.svelte @@ -1,23 +1,27 @@
@@ -76,7 +105,15 @@
- {$t('transactions.claim.steps.pre_check.chain_check')} +
+ {$t('transactions.claim.steps.pre_check.chain_check')} + +

{$t('transactions.claim.steps.pre_check.tooltip.chain.title')}

+ + {$t('transactions.claim.steps.pre_check.tooltip.chain.description')} +
+
+ {#if checkingPrerequisites} {:else if correctChain} @@ -86,7 +123,13 @@ {/if}
- {$t('transactions.claim.steps.pre_check.funds_check')} +
+ {$t('transactions.claim.steps.pre_check.funds_check')} + +

{$t('transactions.claim.steps.pre_check.tooltip.funds.title')}

+ {$t('transactions.claim.steps.pre_check.tooltip.funds.description')} +
+
{#if checkingPrerequisites} {:else if hasEnoughEth} @@ -95,6 +138,24 @@ {/if}
+ {#if isL2Chain(Number(tx.srcChainId))} +
+
+ {$t('transactions.claim.steps.pre_check.quota_check')} + +

{$t('transactions.claim.steps.pre_check.tooltip.quota.title')}

+ {$t('transactions.claim.steps.pre_check.tooltip.quota.description')} +
+
+ {#if checkingPrerequisites} + + {:else if hasEnoughQuota} + + {:else} + + {/if} +
+ {/if}
{#if !canContinue && !correctChain} diff --git a/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte b/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte index 644ce3e0a70..cf779ef53af 100644 --- a/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte +++ b/packages/bridge-ui/src/components/Tooltip/Tooltip.svelte @@ -7,11 +7,11 @@ import { uid } from '$libs/util/uid'; export let position: Position = 'top'; + export let tooltipOpen = false; let tooltipId = `tooltip-${uid()}`; let tooltipClass = `block dialog-tooltip`; - export let tooltipOpen = false; - let classes = classNames('flex', $$props.class || 'relative'); + let classes = classNames('flex z-10 ', $$props.class || 'relative'); const GAP = 10; // distance between trigger element and tooltip let triggerElem: HTMLButtonElement; diff --git a/packages/bridge-ui/src/i18n/en.json b/packages/bridge-ui/src/i18n/en.json index 0a32cdb4acf..9479addf465 100644 --- a/packages/bridge-ui/src/i18n/en.json +++ b/packages/bridge-ui/src/i18n/en.json @@ -472,10 +472,25 @@ "pre_check": { "chain_check": "Connected to the correct chain", "funds_check": "Sufficient funds to claim", + "quota_check": "Sufficient daily quota", "ready": "You can continue with the claim process!", "step": "Claim step", "switch_chain": "This transaction is bridging to {chain} You need to be connected to this chain", - "title": "Requirements" + "title": "Requirements", + "tooltip": { + "chain": { + "description": "You need to be connected to the chain you want to bridge your funds to.", + "title": "What is \"Connected to the correct chain\"?" + }, + "funds": { + "description": "In order to claim the transaction yourself, you need enough funds on the destination chain. If you've kept the default processing fee, the relayer will likely claim for you soon.", + "title": "What is \"Sufficient funds to claim\"?" + }, + "quota": { + "description": "Currently there is a daily limit of how much ETH can be bridged to L1. If the quota is reached, please try again the next day.", + "title": "What is \"Sufficient daily quota\"?" + } + } }, "review": { "name": "Review", diff --git a/packages/bridge-ui/src/libs/bridge/ETHBridge.ts b/packages/bridge-ui/src/libs/bridge/ETHBridge.ts index 881b2883646..625db1d1511 100644 --- a/packages/bridge-ui/src/libs/bridge/ETHBridge.ts +++ b/packages/bridge-ui/src/libs/bridge/ETHBridge.ts @@ -56,11 +56,13 @@ export class ETHBridge extends Bridge { id: BigInt(0), // will be set in contract }; - const minGasLimit = await bridgeContract.read.getMessageMinGasLimit([0n]); - log('Min gas limit for message', minGasLimit); + if (processingFee !== 0n) { + const minGasLimit = await bridgeContract.read.getMessageMinGasLimit([0n]); + log('Min gas limit for message', minGasLimit); - const gasLimit = minGasLimit + 1; - message.gasLimit = gasLimit; + const gasLimit = minGasLimit + 1; + message.gasLimit = gasLimit; + } log('Preparing transaction with message', message); diff --git a/packages/bridge-ui/src/libs/bridge/checkBridgeQuota.ts b/packages/bridge-ui/src/libs/bridge/checkBridgeQuota.ts new file mode 100644 index 00000000000..5224d0957cd --- /dev/null +++ b/packages/bridge-ui/src/libs/bridge/checkBridgeQuota.ts @@ -0,0 +1,63 @@ +import { readContract } from '@wagmi/core'; +import { type Address, zeroAddress } from 'viem'; + +import { quotaManagerAbi } from '$abi'; +import { isL2Chain } from '$libs/chain'; +import { getLogger } from '$libs/util/logger'; +import { config } from '$libs/wagmi'; + +import { type BridgeTransaction, ContractType } from '.'; +import { getContractAddressByType } from './getContractAddressByType'; + +const log = getLogger('bridge:checkBridgeQuota'); + +export const checkBridgeQuota = async ({ + transaction, + amount, +}: { + transaction: BridgeTransaction; + tokenAddress?: Address; + amount: bigint; +}) => { + log( + 'Checking bridge quota', + transaction.canonicalTokenAddress, + amount, + isL2Chain(Number(transaction.destChainId)), + transaction.destChainId, + transaction.srcChainId, + ); + + const tokenAddress = + transaction.canonicalTokenAddress && (transaction.canonicalTokenAddress as string) !== '' + ? transaction.canonicalTokenAddress + : zeroAddress; + + if (isL2Chain(Number(transaction.destChainId))) { + // Quota only applies for transactions from L2-L1. + // So if the destination chain is an L2 chain, we can skip this check. + log('Skipping quota check for L2 chain'); + return true; + } + + const quotaManagerAddress = getContractAddressByType({ + srcChainId: Number(transaction.destChainId), + destChainId: Number(transaction.srcChainId), + contractType: ContractType.QUOTAMANAGER, + }); + + const quota = await readContract(config, { + address: quotaManagerAddress, + abi: quotaManagerAbi, + chainId: Number(transaction.destChainId), + functionName: 'availableQuota', + args: [tokenAddress, 0n], + }); + + if (amount > quota) { + log('Not enough quota', quota, amount); + return false; + } + log('Quota:', quota, 'Amount:', amount, 'Has enough quota:', amount <= quota); + return true; +}; diff --git a/packages/bridge-ui/src/libs/bridge/getContractAddressByType.ts b/packages/bridge-ui/src/libs/bridge/getContractAddressByType.ts index 6ca431f2340..c39a835e67c 100644 --- a/packages/bridge-ui/src/libs/bridge/getContractAddressByType.ts +++ b/packages/bridge-ui/src/libs/bridge/getContractAddressByType.ts @@ -36,6 +36,12 @@ export const getContractAddressByType = (args: GetContractAddressType): Address return addressConfig.signalServiceAddress; case ContractType.CROSSCHAINSYNC: return addressConfig.crossChainSyncAddress; + case ContractType.QUOTAMANAGER: + if (addressConfig.quotaManagerAddress) { + return addressConfig.quotaManagerAddress; + } else { + throw new Error('QuotaManager not configured for this chain pair'); + } default: throw new Error('Invalid contract type'); } diff --git a/packages/bridge-ui/src/libs/bridge/types.ts b/packages/bridge-ui/src/libs/bridge/types.ts index cc3e656ac36..8a23cb4879a 100644 --- a/packages/bridge-ui/src/libs/bridge/types.ts +++ b/packages/bridge-ui/src/libs/bridge/types.ts @@ -108,6 +108,7 @@ export type BridgeTransaction = { status?: MessageStatus; receipt?: TransactionReceipt; + canonicalTokenAddress?: Address; }; interface BaseBridgeTransferOp { @@ -242,6 +243,7 @@ export type AddressConfig = { erc1155VaultAddress: Address; crossChainSyncAddress: Address; signalServiceAddress: Address; + quotaManagerAddress?: Address; hops?: Array; }; @@ -256,12 +258,13 @@ export enum ContractType { VAULT, SIGNALSERVICE, CROSSCHAINSYNC, + QUOTAMANAGER, } export type GetContractAddressType = { srcChainId: number; destChainId: number; - tokenType: TokenType; + tokenType?: TokenType; contractType: ContractType; }; diff --git a/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts b/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts index c4e7fb8fe9e..02db6974cab 100644 --- a/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts +++ b/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts @@ -189,6 +189,7 @@ export class RelayerAPIService { msgHash: tx.msgHash, tokenType: _eventToTokenType(tx.eventType), blockNumber: tx.data.Raw.blockNumber, + canonicalTokenAddress: tx.canonicalTokenAddress, message: { id: tx.data.Message.Id, to: tx.data.Message.To, diff --git a/packages/bridge-ui/wagmi.config.ts b/packages/bridge-ui/wagmi.config.ts index cfbdfdcb209..f16bbd2c232 100644 --- a/packages/bridge-ui/wagmi.config.ts +++ b/packages/bridge-ui/wagmi.config.ts @@ -13,6 +13,7 @@ import ERC1155Vault from '../protocol/out/ERC1155Vault.sol/ERC1155Vault.json'; import FreeMintERC20 from '../protocol/out/FreeMintERC20.sol/FreeMintERC20.json'; import ICrossChainSync from '../protocol/out/ICrossChainSync.sol/ICrossChainSync.json'; import ISignalService from '../protocol/out/ISignalService.sol/ISignalService.json'; +import QuotaManager from '../protocol/out/QuotaManager.sol/QuotaManager.json'; export default defineConfig({ out: 'src/abi/index.ts', @@ -57,5 +58,9 @@ export default defineConfig({ name: 'Erc1155', abi: ERC1155.abi as Abi, }, + { + name: 'QuotaManager', + abi: QuotaManager.abi as Abi, + }, ], });