@multiplatform.one/web3 7.23.1 → 7.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -11
- package/dist/cjs/clients/evm.cjs +299 -11
- package/dist/cjs/clients/evm.native.js +500 -12
- package/dist/cjs/clients/evm.native.js.map +1 -1
- package/dist/cjs/clients/index.cjs +5 -0
- package/dist/cjs/clients/index.native.js +5 -0
- package/dist/cjs/clients/index.native.js.map +1 -1
- package/dist/cjs/clients/solana.cjs +39 -21
- package/dist/cjs/clients/solana.native.js +48 -23
- package/dist/cjs/clients/solana.native.js.map +1 -1
- package/dist/cjs/connectkit/GpgProvider.cjs +44 -0
- package/dist/cjs/connectkit/GpgProvider.native.js +51 -0
- package/dist/cjs/connectkit/GpgProvider.native.js.map +1 -0
- package/dist/cjs/connectkit/adapters/BitcoinAdapter.cjs +5 -14
- package/dist/cjs/connectkit/adapters/BitcoinAdapter.native.js +5 -15
- package/dist/cjs/connectkit/adapters/BitcoinAdapter.native.js.map +1 -1
- package/dist/cjs/connectkit/adapters/EthereumAdapter.cjs +6 -15
- package/dist/cjs/connectkit/adapters/EthereumAdapter.native.js +7 -16
- package/dist/cjs/connectkit/adapters/EthereumAdapter.native.js.map +1 -1
- package/dist/cjs/connectkit/adapters/SolanaAdapter.cjs +5 -14
- package/dist/cjs/connectkit/adapters/SolanaAdapter.native.js +5 -15
- package/dist/cjs/connectkit/adapters/SolanaAdapter.native.js.map +1 -1
- package/dist/cjs/connectkit/adapters/SuiAdapter.cjs +5 -14
- package/dist/cjs/connectkit/adapters/SuiAdapter.native.js +5 -15
- package/dist/cjs/connectkit/adapters/SuiAdapter.native.js.map +1 -1
- package/dist/cjs/connectkit/connectors/createWalletMessage.cjs +2 -2
- package/dist/cjs/connectkit/connectors/createWalletMessage.native.js +2 -2
- package/dist/cjs/connectkit/connectors/createWalletMessage.native.js.map +1 -1
- package/dist/cjs/connectkit/index.cjs +4 -3
- package/dist/cjs/connectkit/index.native.js +4 -3
- package/dist/cjs/connectkit/index.native.js.map +1 -1
- package/dist/cjs/connectkit/siwe/SIWEContext.native.js.map +1 -1
- package/dist/cjs/connectkit/siwe/SIWEProvider.cjs +18 -3
- package/dist/cjs/connectkit/siwe/SIWEProvider.native.js +18 -3
- package/dist/cjs/connectkit/siwe/SIWEProvider.native.js.map +1 -1
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.native.js +1 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/keycloak/KeycloakWalletLogin.cjs +255 -0
- package/dist/cjs/keycloak/KeycloakWalletLogin.native.js +33 -0
- package/dist/cjs/keycloak/KeycloakWalletLogin.native.js.map +1 -0
- package/dist/cjs/keycloak/browserFlow.cjs +83 -0
- package/dist/cjs/keycloak/browserFlow.native.js +90 -0
- package/dist/cjs/keycloak/browserFlow.native.js.map +1 -0
- package/dist/cjs/keycloak/device.cjs +36 -0
- package/dist/cjs/keycloak/device.native.js +45 -0
- package/dist/cjs/keycloak/device.native.js.map +1 -0
- package/dist/cjs/keycloak/directGrant.cjs +189 -0
- package/dist/cjs/keycloak/directGrant.native.js +233 -0
- package/dist/cjs/keycloak/directGrant.native.js.map +1 -0
- package/dist/cjs/keycloak/iife.cjs +4 -0
- package/dist/cjs/keycloak/iife.native.js +7 -0
- package/dist/cjs/keycloak/iife.native.js.map +1 -0
- package/dist/cjs/keycloak/index.cjs +53 -0
- package/dist/cjs/keycloak/index.native.js +56 -0
- package/dist/cjs/keycloak/index.native.js.map +1 -0
- package/dist/cjs/keycloak/keycloakWallet.cjs +214 -0
- package/dist/cjs/keycloak/keycloakWallet.native.js +285 -0
- package/dist/cjs/keycloak/keycloakWallet.native.js.map +1 -0
- package/dist/cjs/keycloak/mount.cjs +53 -0
- package/dist/cjs/keycloak/mount.native.js +33 -0
- package/dist/cjs/keycloak/mount.native.js.map +1 -0
- package/dist/cjs/keycloak/registerWallet.cjs +74 -0
- package/dist/cjs/keycloak/registerWallet.native.js +81 -0
- package/dist/cjs/keycloak/registerWallet.native.js.map +1 -0
- package/dist/cjs/keycloak/types.cjs +46 -0
- package/dist/cjs/keycloak/types.native.js +179 -0
- package/dist/cjs/keycloak/types.native.js.map +1 -0
- package/dist/cjs/keycloak/useDirectLogin.cjs +57 -0
- package/dist/cjs/keycloak/useDirectLogin.native.js +77 -0
- package/dist/cjs/keycloak/useDirectLogin.native.js.map +1 -0
- package/dist/cjs/keycloak/useWalletLogin.cjs +97 -0
- package/dist/cjs/keycloak/useWalletLogin.native.js +33 -0
- package/dist/cjs/keycloak/useWalletLogin.native.js.map +1 -0
- package/dist/cjs/message/buildWalletMessage.cjs +113 -0
- package/dist/cjs/message/buildWalletMessage.native.js +121 -0
- package/dist/cjs/message/buildWalletMessage.native.js.map +1 -0
- package/dist/cjs/message/index.cjs +29 -0
- package/dist/cjs/message/index.native.js +32 -0
- package/dist/cjs/message/index.native.js.map +1 -0
- package/dist/cjs/providers/WalletProvider.cjs +8 -2
- package/dist/cjs/siws/message.cjs +5 -16
- package/dist/cjs/siws/message.native.js +6 -16
- package/dist/cjs/siws/message.native.js.map +1 -1
- package/dist/cjs/solana.native.js.map +1 -1
- package/dist/esm/clients/evm.mjs +295 -12
- package/dist/esm/clients/evm.mjs.map +1 -1
- package/dist/esm/clients/evm.native.js +496 -13
- package/dist/esm/clients/evm.native.js.map +1 -1
- package/dist/esm/clients/index.mjs +2 -2
- package/dist/esm/clients/index.mjs.map +1 -1
- package/dist/esm/clients/index.native.js +2 -2
- package/dist/esm/clients/index.native.js.map +1 -1
- package/dist/esm/clients/solana.mjs +39 -21
- package/dist/esm/clients/solana.mjs.map +1 -1
- package/dist/esm/clients/solana.native.js +48 -23
- package/dist/esm/clients/solana.native.js.map +1 -1
- package/dist/esm/connectkit/GpgProvider.mjs +19 -0
- package/dist/esm/connectkit/GpgProvider.mjs.map +1 -0
- package/dist/esm/connectkit/GpgProvider.native.js +23 -0
- package/dist/esm/connectkit/GpgProvider.native.js.map +1 -0
- package/dist/esm/connectkit/adapters/BitcoinAdapter.mjs +5 -14
- package/dist/esm/connectkit/adapters/BitcoinAdapter.mjs.map +1 -1
- package/dist/esm/connectkit/adapters/BitcoinAdapter.native.js +5 -15
- package/dist/esm/connectkit/adapters/BitcoinAdapter.native.js.map +1 -1
- package/dist/esm/connectkit/adapters/EthereumAdapter.mjs +6 -15
- package/dist/esm/connectkit/adapters/EthereumAdapter.mjs.map +1 -1
- package/dist/esm/connectkit/adapters/EthereumAdapter.native.js +7 -16
- package/dist/esm/connectkit/adapters/EthereumAdapter.native.js.map +1 -1
- package/dist/esm/connectkit/adapters/SolanaAdapter.mjs +5 -14
- package/dist/esm/connectkit/adapters/SolanaAdapter.mjs.map +1 -1
- package/dist/esm/connectkit/adapters/SolanaAdapter.native.js +5 -15
- package/dist/esm/connectkit/adapters/SolanaAdapter.native.js.map +1 -1
- package/dist/esm/connectkit/adapters/SuiAdapter.mjs +5 -14
- package/dist/esm/connectkit/adapters/SuiAdapter.mjs.map +1 -1
- package/dist/esm/connectkit/adapters/SuiAdapter.native.js +5 -15
- package/dist/esm/connectkit/adapters/SuiAdapter.native.js.map +1 -1
- package/dist/esm/connectkit/connectors/createWalletMessage.mjs +1 -1
- package/dist/esm/connectkit/connectors/createWalletMessage.native.js +1 -1
- package/dist/esm/connectkit/index.mjs +3 -2
- package/dist/esm/connectkit/index.mjs.map +1 -1
- package/dist/esm/connectkit/index.native.js +3 -2
- package/dist/esm/connectkit/index.native.js.map +1 -1
- package/dist/esm/connectkit/siwe/SIWEContext.mjs.map +1 -1
- package/dist/esm/connectkit/siwe/SIWEContext.native.js.map +1 -1
- package/dist/esm/connectkit/siwe/SIWEProvider.mjs +19 -4
- package/dist/esm/connectkit/siwe/SIWEProvider.mjs.map +1 -1
- package/dist/esm/connectkit/siwe/SIWEProvider.native.js +19 -4
- package/dist/esm/connectkit/siwe/SIWEProvider.native.js.map +1 -1
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +1 -0
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/keycloak/KeycloakWalletLogin.mjs +218 -0
- package/dist/esm/keycloak/KeycloakWalletLogin.mjs.map +1 -0
- package/dist/esm/keycloak/KeycloakWalletLogin.native.js +5 -0
- package/dist/esm/keycloak/KeycloakWalletLogin.native.js.map +1 -0
- package/dist/esm/keycloak/browserFlow.mjs +58 -0
- package/dist/esm/keycloak/browserFlow.mjs.map +1 -0
- package/dist/esm/keycloak/browserFlow.native.js +62 -0
- package/dist/esm/keycloak/browserFlow.native.js.map +1 -0
- package/dist/esm/keycloak/device.mjs +10 -0
- package/dist/esm/keycloak/device.mjs.map +1 -0
- package/dist/esm/keycloak/device.native.js +16 -0
- package/dist/esm/keycloak/device.native.js.map +1 -0
- package/dist/esm/keycloak/directGrant.mjs +164 -0
- package/dist/esm/keycloak/directGrant.mjs.map +1 -0
- package/dist/esm/keycloak/directGrant.native.js +205 -0
- package/dist/esm/keycloak/directGrant.native.js.map +1 -0
- package/dist/esm/keycloak/iife.mjs +5 -0
- package/dist/esm/keycloak/iife.mjs.map +1 -0
- package/dist/esm/keycloak/iife.native.js +5 -0
- package/dist/esm/keycloak/iife.native.js.map +1 -0
- package/dist/esm/keycloak/index.mjs +13 -0
- package/dist/esm/keycloak/index.mjs.map +1 -0
- package/dist/esm/keycloak/index.native.js +13 -0
- package/dist/esm/keycloak/index.native.js.map +1 -0
- package/dist/esm/keycloak/keycloakWallet.mjs +186 -0
- package/dist/esm/keycloak/keycloakWallet.mjs.map +1 -0
- package/dist/esm/keycloak/keycloakWallet.native.js +254 -0
- package/dist/esm/keycloak/keycloakWallet.native.js.map +1 -0
- package/dist/esm/keycloak/mount.mjs +28 -0
- package/dist/esm/keycloak/mount.mjs.map +1 -0
- package/dist/esm/keycloak/mount.native.js +5 -0
- package/dist/esm/keycloak/mount.native.js.map +1 -0
- package/dist/esm/keycloak/registerWallet.mjs +49 -0
- package/dist/esm/keycloak/registerWallet.mjs.map +1 -0
- package/dist/esm/keycloak/registerWallet.native.js +53 -0
- package/dist/esm/keycloak/registerWallet.native.js.map +1 -0
- package/dist/esm/keycloak/types.mjs +20 -0
- package/dist/esm/keycloak/types.mjs.map +1 -0
- package/dist/esm/keycloak/types.native.js +150 -0
- package/dist/esm/keycloak/types.native.js.map +1 -0
- package/dist/esm/keycloak/useDirectLogin.mjs +32 -0
- package/dist/esm/keycloak/useDirectLogin.mjs.map +1 -0
- package/dist/esm/keycloak/useDirectLogin.native.js +49 -0
- package/dist/esm/keycloak/useDirectLogin.native.js.map +1 -0
- package/dist/esm/keycloak/useWalletLogin.mjs +72 -0
- package/dist/esm/keycloak/useWalletLogin.mjs.map +1 -0
- package/dist/esm/keycloak/useWalletLogin.native.js +5 -0
- package/dist/esm/keycloak/useWalletLogin.native.js.map +1 -0
- package/dist/esm/message/buildWalletMessage.mjs +87 -0
- package/dist/esm/message/buildWalletMessage.mjs.map +1 -0
- package/dist/esm/message/buildWalletMessage.native.js +92 -0
- package/dist/esm/message/buildWalletMessage.native.js.map +1 -0
- package/dist/esm/message/index.mjs +3 -0
- package/dist/esm/message/index.mjs.map +1 -0
- package/dist/esm/message/index.native.js +3 -0
- package/dist/esm/message/index.native.js.map +1 -0
- package/dist/esm/providers/WalletProvider.mjs +9 -3
- package/dist/esm/providers/WalletProvider.mjs.map +1 -1
- package/dist/esm/siws/message.mjs +5 -16
- package/dist/esm/siws/message.mjs.map +1 -1
- package/dist/esm/siws/message.native.js +6 -16
- package/dist/esm/siws/message.native.js.map +1 -1
- package/dist/esm/solana.mjs.map +1 -1
- package/dist/esm/solana.native.js.map +1 -1
- package/dist/jsx/clients/evm.mjs +295 -12
- package/dist/jsx/clients/evm.mjs.map +1 -1
- package/dist/jsx/clients/evm.native.js +500 -12
- package/dist/jsx/clients/evm.native.js.map +1 -1
- package/dist/jsx/clients/index.mjs +2 -2
- package/dist/jsx/clients/index.mjs.map +1 -1
- package/dist/jsx/clients/index.native.js +5 -0
- package/dist/jsx/clients/index.native.js.map +1 -1
- package/dist/jsx/clients/solana.mjs +39 -21
- package/dist/jsx/clients/solana.mjs.map +1 -1
- package/dist/jsx/clients/solana.native.js +48 -23
- package/dist/jsx/clients/solana.native.js.map +1 -1
- package/dist/jsx/connectkit/GpgProvider.mjs +19 -0
- package/dist/jsx/connectkit/GpgProvider.mjs.map +1 -0
- package/dist/jsx/connectkit/GpgProvider.native.js +51 -0
- package/dist/jsx/connectkit/GpgProvider.native.js.map +1 -0
- package/dist/jsx/connectkit/adapters/BitcoinAdapter.mjs +5 -14
- package/dist/jsx/connectkit/adapters/BitcoinAdapter.mjs.map +1 -1
- package/dist/jsx/connectkit/adapters/BitcoinAdapter.native.js +5 -15
- package/dist/jsx/connectkit/adapters/BitcoinAdapter.native.js.map +1 -1
- package/dist/jsx/connectkit/adapters/EthereumAdapter.mjs +6 -15
- package/dist/jsx/connectkit/adapters/EthereumAdapter.mjs.map +1 -1
- package/dist/jsx/connectkit/adapters/EthereumAdapter.native.js +7 -16
- package/dist/jsx/connectkit/adapters/EthereumAdapter.native.js.map +1 -1
- package/dist/jsx/connectkit/adapters/SolanaAdapter.mjs +5 -14
- package/dist/jsx/connectkit/adapters/SolanaAdapter.mjs.map +1 -1
- package/dist/jsx/connectkit/adapters/SolanaAdapter.native.js +5 -15
- package/dist/jsx/connectkit/adapters/SolanaAdapter.native.js.map +1 -1
- package/dist/jsx/connectkit/adapters/SuiAdapter.mjs +5 -14
- package/dist/jsx/connectkit/adapters/SuiAdapter.mjs.map +1 -1
- package/dist/jsx/connectkit/adapters/SuiAdapter.native.js +5 -15
- package/dist/jsx/connectkit/adapters/SuiAdapter.native.js.map +1 -1
- package/dist/jsx/connectkit/connectors/createWalletMessage.mjs +1 -1
- package/dist/jsx/connectkit/connectors/createWalletMessage.native.js +2 -2
- package/dist/jsx/connectkit/index.mjs +3 -2
- package/dist/jsx/connectkit/index.mjs.map +1 -1
- package/dist/jsx/connectkit/index.native.js +4 -3
- package/dist/jsx/connectkit/index.native.js.map +1 -1
- package/dist/jsx/connectkit/siwe/SIWEContext.mjs.map +1 -1
- package/dist/jsx/connectkit/siwe/SIWEContext.native.js.map +1 -1
- package/dist/jsx/connectkit/siwe/SIWEProvider.mjs +19 -4
- package/dist/jsx/connectkit/siwe/SIWEProvider.mjs.map +1 -1
- package/dist/jsx/connectkit/siwe/SIWEProvider.native.js +18 -3
- package/dist/jsx/connectkit/siwe/SIWEProvider.native.js.map +1 -1
- package/dist/jsx/index.js +1 -0
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +1 -0
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +1 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/keycloak/KeycloakWalletLogin.mjs +218 -0
- package/dist/jsx/keycloak/KeycloakWalletLogin.mjs.map +1 -0
- package/dist/jsx/keycloak/KeycloakWalletLogin.native.js +33 -0
- package/dist/jsx/keycloak/KeycloakWalletLogin.native.js.map +1 -0
- package/dist/jsx/keycloak/browserFlow.mjs +58 -0
- package/dist/jsx/keycloak/browserFlow.mjs.map +1 -0
- package/dist/jsx/keycloak/browserFlow.native.js +90 -0
- package/dist/jsx/keycloak/browserFlow.native.js.map +1 -0
- package/dist/jsx/keycloak/device.mjs +10 -0
- package/dist/jsx/keycloak/device.mjs.map +1 -0
- package/dist/jsx/keycloak/device.native.js +45 -0
- package/dist/jsx/keycloak/device.native.js.map +1 -0
- package/dist/jsx/keycloak/directGrant.mjs +164 -0
- package/dist/jsx/keycloak/directGrant.mjs.map +1 -0
- package/dist/jsx/keycloak/directGrant.native.js +233 -0
- package/dist/jsx/keycloak/directGrant.native.js.map +1 -0
- package/dist/jsx/keycloak/iife.mjs +5 -0
- package/dist/jsx/keycloak/iife.mjs.map +1 -0
- package/dist/jsx/keycloak/iife.native.js +7 -0
- package/dist/jsx/keycloak/iife.native.js.map +1 -0
- package/dist/jsx/keycloak/index.mjs +13 -0
- package/dist/jsx/keycloak/index.mjs.map +1 -0
- package/dist/jsx/keycloak/index.native.js +56 -0
- package/dist/jsx/keycloak/index.native.js.map +1 -0
- package/dist/jsx/keycloak/keycloakWallet.mjs +186 -0
- package/dist/jsx/keycloak/keycloakWallet.mjs.map +1 -0
- package/dist/jsx/keycloak/keycloakWallet.native.js +285 -0
- package/dist/jsx/keycloak/keycloakWallet.native.js.map +1 -0
- package/dist/jsx/keycloak/mount.mjs +28 -0
- package/dist/jsx/keycloak/mount.mjs.map +1 -0
- package/dist/jsx/keycloak/mount.native.js +33 -0
- package/dist/jsx/keycloak/mount.native.js.map +1 -0
- package/dist/jsx/keycloak/registerWallet.mjs +49 -0
- package/dist/jsx/keycloak/registerWallet.mjs.map +1 -0
- package/dist/jsx/keycloak/registerWallet.native.js +81 -0
- package/dist/jsx/keycloak/registerWallet.native.js.map +1 -0
- package/dist/jsx/keycloak/types.mjs +20 -0
- package/dist/jsx/keycloak/types.mjs.map +1 -0
- package/dist/jsx/keycloak/types.native.js +179 -0
- package/dist/jsx/keycloak/types.native.js.map +1 -0
- package/dist/jsx/keycloak/useDirectLogin.mjs +32 -0
- package/dist/jsx/keycloak/useDirectLogin.mjs.map +1 -0
- package/dist/jsx/keycloak/useDirectLogin.native.js +77 -0
- package/dist/jsx/keycloak/useDirectLogin.native.js.map +1 -0
- package/dist/jsx/keycloak/useWalletLogin.mjs +72 -0
- package/dist/jsx/keycloak/useWalletLogin.mjs.map +1 -0
- package/dist/jsx/keycloak/useWalletLogin.native.js +33 -0
- package/dist/jsx/keycloak/useWalletLogin.native.js.map +1 -0
- package/dist/jsx/message/buildWalletMessage.mjs +87 -0
- package/dist/jsx/message/buildWalletMessage.mjs.map +1 -0
- package/dist/jsx/message/buildWalletMessage.native.js +121 -0
- package/dist/jsx/message/buildWalletMessage.native.js.map +1 -0
- package/dist/jsx/message/index.mjs +3 -0
- package/dist/jsx/message/index.mjs.map +1 -0
- package/dist/jsx/message/index.native.js +32 -0
- package/dist/jsx/message/index.native.js.map +1 -0
- package/dist/jsx/providers/WalletProvider.mjs +9 -3
- package/dist/jsx/providers/WalletProvider.mjs.map +1 -1
- package/dist/jsx/siws/message.mjs +5 -16
- package/dist/jsx/siws/message.mjs.map +1 -1
- package/dist/jsx/siws/message.native.js +6 -16
- package/dist/jsx/siws/message.native.js.map +1 -1
- package/dist/jsx/solana.mjs.map +1 -1
- package/dist/jsx/solana.native.js.map +1 -1
- package/dist/keycloak/login.iife.js +3604 -0
- package/package.json +27 -8
- package/src/clients/evm.spec.ts +644 -10
- package/src/clients/evm.ts +498 -10
- package/src/clients/index.ts +8 -0
- package/src/clients/solana.spec.ts +116 -0
- package/src/clients/solana.ts +51 -31
- package/src/connectkit/GpgProvider.tsx +16 -0
- package/src/connectkit/adapters/BitcoinAdapter.ts +5 -16
- package/src/connectkit/adapters/EthereumAdapter.ts +6 -17
- package/src/connectkit/adapters/SolanaAdapter.ts +5 -16
- package/src/connectkit/adapters/SuiAdapter.ts +5 -16
- package/src/connectkit/connectors/createWalletMessage.ts +1 -1
- package/src/connectkit/index.ts +2 -6
- package/src/connectkit/openConnector/modal.spec.tsx +1 -1
- package/src/connectkit/siwe/SIWEContext.tsx +6 -2
- package/src/connectkit/siwe/SIWEProvider.tsx +22 -5
- package/src/index.ts +3 -0
- package/src/keycloak/KeycloakWalletLogin.native.tsx +7 -0
- package/src/keycloak/KeycloakWalletLogin.spec.tsx +168 -0
- package/src/keycloak/KeycloakWalletLogin.tsx +251 -0
- package/src/keycloak/browserFlow.spec.ts +108 -0
- package/src/keycloak/browserFlow.ts +84 -0
- package/src/keycloak/device.ts +17 -0
- package/src/keycloak/directGrant.spec.ts +331 -0
- package/src/keycloak/directGrant.ts +214 -0
- package/src/keycloak/iife.ts +3 -0
- package/src/keycloak/index.ts +44 -0
- package/src/keycloak/keycloakWallet.spec.ts +216 -0
- package/src/keycloak/keycloakWallet.ts +275 -0
- package/src/keycloak/mount.native.ts +11 -0
- package/src/keycloak/mount.tsx +45 -0
- package/src/keycloak/nonceReset.spec.tsx +205 -0
- package/src/keycloak/registerWallet.spec.ts +88 -0
- package/src/keycloak/registerWallet.ts +59 -0
- package/src/keycloak/types.ts +66 -0
- package/src/keycloak/useDirectLogin.spec.tsx +112 -0
- package/src/keycloak/useDirectLogin.ts +74 -0
- package/src/keycloak/useWalletLogin.native.ts +7 -0
- package/src/keycloak/useWalletLogin.ts +99 -0
- package/src/message/buildWalletMessage.spec.ts +291 -0
- package/src/message/buildWalletMessage.ts +150 -0
- package/src/message/index.ts +8 -0
- package/src/providers/WalletProvider.tsx +15 -2
- package/src/siws/message.ts +3 -22
- package/src/solana.ts +1 -0
- package/types/clients/evm.d.ts +144 -2
- package/types/clients/evm.d.ts.map +1 -1
- package/types/clients/index.d.ts +1 -1
- package/types/clients/index.d.ts.map +1 -1
- package/types/clients/solana.d.ts +14 -5
- package/types/clients/solana.d.ts.map +1 -1
- package/types/connectkit/GpgProvider.d.ts +10 -0
- package/types/connectkit/GpgProvider.d.ts.map +1 -0
- package/types/connectkit/adapters/BitcoinAdapter.d.ts.map +1 -1
- package/types/connectkit/adapters/EthereumAdapter.d.ts.map +1 -1
- package/types/connectkit/adapters/SolanaAdapter.d.ts.map +1 -1
- package/types/connectkit/adapters/SuiAdapter.d.ts.map +1 -1
- package/types/connectkit/connectors/createWalletMessage.d.ts +1 -1
- package/types/connectkit/connectors/createWalletMessage.d.ts.map +1 -1
- package/types/connectkit/index.d.ts +3 -2
- package/types/connectkit/index.d.ts.map +1 -1
- package/types/connectkit/siwe/SIWEContext.d.ts +2 -1
- package/types/connectkit/siwe/SIWEContext.d.ts.map +1 -1
- package/types/connectkit/siwe/SIWEProvider.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/keycloak/KeycloakWalletLogin.d.ts +45 -0
- package/types/keycloak/KeycloakWalletLogin.d.ts.map +1 -0
- package/types/keycloak/KeycloakWalletLogin.native.d.ts +4 -0
- package/types/keycloak/KeycloakWalletLogin.native.d.ts.map +1 -0
- package/types/keycloak/browserFlow.d.ts +27 -0
- package/types/keycloak/browserFlow.d.ts.map +1 -0
- package/types/keycloak/device.d.ts +14 -0
- package/types/keycloak/device.d.ts.map +1 -0
- package/types/keycloak/directGrant.d.ts +43 -0
- package/types/keycloak/directGrant.d.ts.map +1 -0
- package/types/keycloak/iife.d.ts +2 -0
- package/types/keycloak/iife.d.ts.map +1 -0
- package/types/keycloak/index.d.ts +12 -0
- package/types/keycloak/index.d.ts.map +1 -0
- package/types/keycloak/keycloakWallet.d.ts +120 -0
- package/types/keycloak/keycloakWallet.d.ts.map +1 -0
- package/types/keycloak/mount.d.ts +16 -0
- package/types/keycloak/mount.d.ts.map +1 -0
- package/types/keycloak/mount.native.d.ts +5 -0
- package/types/keycloak/mount.native.d.ts.map +1 -0
- package/types/keycloak/registerWallet.d.ts +22 -0
- package/types/keycloak/registerWallet.d.ts.map +1 -0
- package/types/keycloak/types.d.ts +50 -0
- package/types/keycloak/types.d.ts.map +1 -0
- package/types/keycloak/useDirectLogin.d.ts +29 -0
- package/types/keycloak/useDirectLogin.d.ts.map +1 -0
- package/types/keycloak/useWalletLogin.d.ts +26 -0
- package/types/keycloak/useWalletLogin.d.ts.map +1 -0
- package/types/keycloak/useWalletLogin.native.d.ts +4 -0
- package/types/keycloak/useWalletLogin.native.d.ts.map +1 -0
- package/types/message/buildWalletMessage.d.ts +46 -0
- package/types/message/buildWalletMessage.d.ts.map +1 -0
- package/types/message/index.d.ts +2 -0
- package/types/message/index.d.ts.map +1 -0
- package/types/providers/WalletProvider.d.ts +8 -1
- package/types/providers/WalletProvider.d.ts.map +1 -1
- package/types/siws/message.d.ts.map +1 -1
- package/types/solana.d.ts +1 -1
- package/types/solana.d.ts.map +1 -1
- package/dist/cjs/connectkit/adapters/messages.cjs +0 -73
- package/dist/cjs/connectkit/adapters/messages.native.js +0 -79
- package/dist/cjs/connectkit/adapters/messages.native.js.map +0 -1
- package/dist/esm/connectkit/adapters/messages.mjs +0 -48
- package/dist/esm/connectkit/adapters/messages.mjs.map +0 -1
- package/dist/esm/connectkit/adapters/messages.native.js +0 -51
- package/dist/esm/connectkit/adapters/messages.native.js.map +0 -1
- package/dist/jsx/connectkit/adapters/messages.mjs +0 -48
- package/dist/jsx/connectkit/adapters/messages.mjs.map +0 -1
- package/dist/jsx/connectkit/adapters/messages.native.js +0 -79
- package/dist/jsx/connectkit/adapters/messages.native.js.map +0 -1
- package/src/connectkit/adapters/messages.ts +0 -84
- package/types/connectkit/adapters/messages.d.ts +0 -16
- package/types/connectkit/adapters/messages.d.ts.map +0 -1
package/src/clients/evm.spec.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
createPublicClient,
|
|
4
4
|
custom,
|
|
@@ -6,11 +6,19 @@ import {
|
|
|
6
6
|
encodeAbiParameters,
|
|
7
7
|
erc20Abi,
|
|
8
8
|
toHex,
|
|
9
|
+
WaitForTransactionReceiptTimeoutError,
|
|
9
10
|
type Address,
|
|
10
11
|
type Hex,
|
|
11
12
|
} from "viem";
|
|
12
13
|
import { mainnet } from "viem/chains";
|
|
13
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
classifyTxError,
|
|
16
|
+
evmClient,
|
|
17
|
+
ReceiptPendingError,
|
|
18
|
+
ReceiptWaitAbortedError,
|
|
19
|
+
TransactionReplacedError,
|
|
20
|
+
TransactionRevertedError,
|
|
21
|
+
} from "./evm";
|
|
14
22
|
|
|
15
23
|
const account = "0x1111111111111111111111111111111111111111" as Address;
|
|
16
24
|
const token = "0x2222222222222222222222222222222222222222" as Address;
|
|
@@ -30,10 +38,49 @@ interface ChainState {
|
|
|
30
38
|
usdt?: boolean;
|
|
31
39
|
/** Hashes whose receipt comes back reverted. */
|
|
32
40
|
reverted?: Set<Hex>;
|
|
41
|
+
/** Hashes still in the mempool: no receipt yet. */
|
|
42
|
+
pending?: Set<Hex>;
|
|
43
|
+
/** Mined transactions this client did not send, by hash. */
|
|
44
|
+
mined?: Map<Hex, { to: Address; value: Hex; nonce: Hex }>;
|
|
45
|
+
/** What eth_getBlockByNumber lists for block `takenAt`; other blocks are empty. */
|
|
46
|
+
blockTransactions?: Hex[];
|
|
47
|
+
/** eth_getTransactionCount from block `takenAt` on, one less before it; sent minus pending by default. */
|
|
48
|
+
nonceUsed?: number;
|
|
49
|
+
/** The block that took the nonce, the head by default. */
|
|
50
|
+
takenAt?: bigint;
|
|
51
|
+
/** Sent hashes the node no longer knows, as after a replacement it did not see. */
|
|
52
|
+
forgotten?: Set<Hex>;
|
|
53
|
+
block?: bigint;
|
|
54
|
+
/** The wallet answers eth_sendTransaction with EIP-1193 4001. */
|
|
55
|
+
userRejects?: boolean;
|
|
56
|
+
/** eth_getTransactionReceipt fails with an RPC error. */
|
|
57
|
+
receiptRpcDown?: boolean;
|
|
58
|
+
/** eth_getTransactionByHash answers once this settles. */
|
|
59
|
+
txLookupGate?: Promise<void>;
|
|
33
60
|
}
|
|
34
61
|
|
|
35
62
|
const revert = () => Object.assign(new Error("execution reverted"), { code: 3, data: "0x" as Hex });
|
|
36
63
|
|
|
64
|
+
const rpcTransaction = (hash: Hex, tx: { to: Address; value: Hex; nonce: Hex; input?: Hex }) => ({
|
|
65
|
+
hash,
|
|
66
|
+
from: account,
|
|
67
|
+
to: tx.to,
|
|
68
|
+
value: tx.value,
|
|
69
|
+
input: tx.input ?? "0x",
|
|
70
|
+
nonce: tx.nonce,
|
|
71
|
+
gas: "0x5208",
|
|
72
|
+
maxFeePerGas: "0x2",
|
|
73
|
+
maxPriorityFeePerGas: "0x1",
|
|
74
|
+
type: "0x2",
|
|
75
|
+
chainId: "0x1",
|
|
76
|
+
blockHash: null,
|
|
77
|
+
blockNumber: null,
|
|
78
|
+
transactionIndex: null,
|
|
79
|
+
v: "0x0",
|
|
80
|
+
r: "0x1",
|
|
81
|
+
s: "0x1",
|
|
82
|
+
});
|
|
83
|
+
|
|
37
84
|
function mockProvider(state: ChainState) {
|
|
38
85
|
const calls: Call[] = [];
|
|
39
86
|
const sent: Hex[] = [];
|
|
@@ -46,6 +93,9 @@ function mockProvider(state: ChainState) {
|
|
|
46
93
|
case "personal_sign":
|
|
47
94
|
return "0xsigned";
|
|
48
95
|
case "eth_sendTransaction": {
|
|
96
|
+
if (state.userRejects) {
|
|
97
|
+
throw Object.assign(new Error("User rejected the request."), { code: 4001 });
|
|
98
|
+
}
|
|
49
99
|
const [{ data }] = params as [{ data?: Hex }];
|
|
50
100
|
const hash = sent.length === 0 ? txHash : hashFor(sent.length + 1);
|
|
51
101
|
sent.push(hash);
|
|
@@ -59,7 +109,16 @@ function mockProvider(state: ChainState) {
|
|
|
59
109
|
}
|
|
60
110
|
case "eth_getTransactionReceipt": {
|
|
61
111
|
const [hash] = params as [Hex];
|
|
62
|
-
if (
|
|
112
|
+
if (state.receiptRpcDown) {
|
|
113
|
+
throw Object.assign(new Error("upstream unavailable"), { code: -32002 });
|
|
114
|
+
}
|
|
115
|
+
if (
|
|
116
|
+
!(sent.includes(hash) || state.mined?.has(hash)) ||
|
|
117
|
+
state.pending?.has(hash) ||
|
|
118
|
+
state.forgotten?.has(hash)
|
|
119
|
+
) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
63
122
|
return {
|
|
64
123
|
transactionHash: hash,
|
|
65
124
|
transactionIndex: "0x0",
|
|
@@ -80,7 +139,47 @@ function mockProvider(state: ChainState) {
|
|
|
80
139
|
case "eth_estimateGas":
|
|
81
140
|
return "0x5208";
|
|
82
141
|
case "eth_blockNumber":
|
|
83
|
-
return
|
|
142
|
+
return toHex(head());
|
|
143
|
+
case "eth_getTransactionCount": {
|
|
144
|
+
if (state.nonceUsed === undefined) return toHex(sent.length - (state.pending?.size ?? 0));
|
|
145
|
+
return toHex(
|
|
146
|
+
blockOf((params as [Address, string])[1]) < (state.takenAt ?? head())
|
|
147
|
+
? state.nonceUsed - 1
|
|
148
|
+
: state.nonceUsed,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
case "eth_getTransactionByHash": {
|
|
152
|
+
await state.txLookupGate;
|
|
153
|
+
const [hash] = params as [Hex];
|
|
154
|
+
if (state.forgotten?.has(hash)) return null;
|
|
155
|
+
if (state.mined?.has(hash)) return rpcTransaction(hash, state.mined.get(hash)!);
|
|
156
|
+
const call = calls.find(
|
|
157
|
+
(c) => c.method === "eth_sendTransaction" && sent[sendCalls().indexOf(c)] === hash,
|
|
158
|
+
);
|
|
159
|
+
if (!call) return null;
|
|
160
|
+
const tx = (call.params as [{ to: Address; value?: Hex; data?: Hex }])[0];
|
|
161
|
+
return rpcTransaction(hash, {
|
|
162
|
+
to: tx.to,
|
|
163
|
+
value: tx.value ?? "0x0",
|
|
164
|
+
input: tx.data,
|
|
165
|
+
nonce: toHex(sent.indexOf(hash)),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
case "eth_getBlockByNumber": {
|
|
169
|
+
const number = blockOf((params as [string])[0]);
|
|
170
|
+
return {
|
|
171
|
+
number: toHex(number),
|
|
172
|
+
hash: `0x${"cd".repeat(32)}`,
|
|
173
|
+
parentHash: `0x${"ce".repeat(32)}`,
|
|
174
|
+
timestamp: "0x1",
|
|
175
|
+
transactions:
|
|
176
|
+
number === (state.takenAt ?? head())
|
|
177
|
+
? (state.blockTransactions ?? []).map((hash) =>
|
|
178
|
+
rpcTransaction(hash, state.mined!.get(hash)!),
|
|
179
|
+
)
|
|
180
|
+
: [],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
84
183
|
case "eth_call": {
|
|
85
184
|
const [{ data }] = params as [{ data: Hex }];
|
|
86
185
|
const { functionName, args } = decodeFunctionData({ abi: erc20Abi, data });
|
|
@@ -104,6 +203,15 @@ function mockProvider(state: ChainState) {
|
|
|
104
203
|
}
|
|
105
204
|
},
|
|
106
205
|
};
|
|
206
|
+
function sendCalls() {
|
|
207
|
+
return calls.filter((c) => c.method === "eth_sendTransaction");
|
|
208
|
+
}
|
|
209
|
+
function head() {
|
|
210
|
+
return state.block ?? 16n;
|
|
211
|
+
}
|
|
212
|
+
function blockOf(tag: string) {
|
|
213
|
+
return tag.startsWith("0x") ? BigInt(tag) : head();
|
|
214
|
+
}
|
|
107
215
|
const sentTransaction = <T>() => {
|
|
108
216
|
const call = calls.find((c) => c.method === "eth_sendTransaction");
|
|
109
217
|
if (!call) throw new Error("no eth_sendTransaction");
|
|
@@ -118,7 +226,13 @@ function mockProvider(state: ChainState) {
|
|
|
118
226
|
)
|
|
119
227
|
.filter((d) => d.functionName === "approve")
|
|
120
228
|
.map((d) => (d.args as [Address, bigint])[1]);
|
|
121
|
-
|
|
229
|
+
const count = (method: string) => calls.filter((c) => c.method === method).length;
|
|
230
|
+
/** The block numbers eth_getBlockByNumber was asked for. */
|
|
231
|
+
const blocksFetched = () =>
|
|
232
|
+
calls
|
|
233
|
+
.filter((c) => c.method === "eth_getBlockByNumber")
|
|
234
|
+
.map((c) => BigInt((c.params as [Hex])[0]));
|
|
235
|
+
return { provider, calls, sent, sentTransaction, approvals, count, blocksFetched };
|
|
122
236
|
}
|
|
123
237
|
|
|
124
238
|
describe("evmClient", () => {
|
|
@@ -126,19 +240,22 @@ describe("evmClient", () => {
|
|
|
126
240
|
let mock: ReturnType<typeof mockProvider>;
|
|
127
241
|
let client: ReturnType<typeof evmClient>;
|
|
128
242
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
mock = mockProvider(state);
|
|
132
|
-
client = evmClient({
|
|
243
|
+
const makeClient = (pollingInterval: number) =>
|
|
244
|
+
evmClient({
|
|
133
245
|
provider: mock.provider as never,
|
|
134
246
|
account,
|
|
135
247
|
chain: mainnet,
|
|
136
248
|
publicClient: createPublicClient({
|
|
137
249
|
chain: mainnet,
|
|
138
|
-
pollingInterval
|
|
250
|
+
pollingInterval,
|
|
139
251
|
transport: custom(mock.provider),
|
|
140
252
|
}),
|
|
141
253
|
});
|
|
254
|
+
|
|
255
|
+
beforeEach(() => {
|
|
256
|
+
state = { allowance: 0n, balance: 5n * 10n ** 18n };
|
|
257
|
+
mock = mockProvider(state);
|
|
258
|
+
client = makeClient(1);
|
|
142
259
|
});
|
|
143
260
|
|
|
144
261
|
it("shares the common client shape", () => {
|
|
@@ -262,4 +379,521 @@ describe("evmClient", () => {
|
|
|
262
379
|
expect(wrapped.address).toBe(account);
|
|
263
380
|
expect(wrapped.chain.id).toBe(1);
|
|
264
381
|
});
|
|
382
|
+
|
|
383
|
+
it("links a transaction to the chain's explorer", () => {
|
|
384
|
+
expect(client.explorerTxUrl(txHash)).toBe(`https://etherscan.io/tx/${txHash}`);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
describe("receipts", () => {
|
|
388
|
+
afterEach(() => {
|
|
389
|
+
vi.useRealTimers();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("confirms a mined transaction", async () => {
|
|
393
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
394
|
+
const receipt = await client.confirmTransaction(hash);
|
|
395
|
+
expect(receipt.status).toBe("success");
|
|
396
|
+
expect(receipt.transactionHash).toBe(hash);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it("gives up on a pending transaction as ReceiptPendingError, never a failure", async () => {
|
|
400
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
401
|
+
state.pending = new Set([hash]);
|
|
402
|
+
const error = await client.waitForTransactionReceipt(hash, { timeout: 50 }).catch((e) => e);
|
|
403
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
404
|
+
expect(error).toMatchObject({
|
|
405
|
+
hash,
|
|
406
|
+
chainId: 1,
|
|
407
|
+
mayStillLand: true,
|
|
408
|
+
explorerUrl: `https://etherscan.io/tx/${hash}`,
|
|
409
|
+
nonce: 0,
|
|
410
|
+
});
|
|
411
|
+
expect(error.message).toMatch(/may still land/);
|
|
412
|
+
expect(classifyTxError(error)).toBe("pending");
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it("waits past viem's 180 s default when no timeout is set", async () => {
|
|
416
|
+
vi.useFakeTimers();
|
|
417
|
+
const slow = makeClient(5_000);
|
|
418
|
+
const hash = await slow.sendTransaction({ to: spender, value: 1n });
|
|
419
|
+
state.pending = new Set([hash]);
|
|
420
|
+
let settled: string | undefined;
|
|
421
|
+
const wait = slow.confirmTransaction(hash).then(
|
|
422
|
+
(receipt) => (settled = receipt.status),
|
|
423
|
+
(error: Error) => (settled = error.name),
|
|
424
|
+
);
|
|
425
|
+
await vi.advanceTimersByTimeAsync(300_000);
|
|
426
|
+
expect(settled).toBeUndefined();
|
|
427
|
+
state.pending.clear();
|
|
428
|
+
state.block = 17n;
|
|
429
|
+
await vi.advanceTimersByTimeAsync(10_000);
|
|
430
|
+
await wait;
|
|
431
|
+
expect(settled).toBe("success");
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it("rides out an RPC outage with no timeout, backing off up to 30 s between polls", async () => {
|
|
435
|
+
vi.useFakeTimers();
|
|
436
|
+
const polled = makeClient(500);
|
|
437
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
438
|
+
state.receiptRpcDown = true;
|
|
439
|
+
let settled: string | undefined;
|
|
440
|
+
const wait = polled.confirmTransaction(hash).then(
|
|
441
|
+
(receipt) => (settled = receipt.status),
|
|
442
|
+
(error: Error) => (settled = error.name),
|
|
443
|
+
);
|
|
444
|
+
await vi.advanceTimersByTimeAsync(10 * 60_000);
|
|
445
|
+
expect(settled).toBeUndefined();
|
|
446
|
+
// 1200 polls at 500 ms without backoff; doubling to the 30 s cap is 20 at most, 40 at least.
|
|
447
|
+
const polls = mock.count("eth_getTransactionReceipt");
|
|
448
|
+
expect(polls).toBeGreaterThan(15);
|
|
449
|
+
expect(polls).toBeLessThan(50);
|
|
450
|
+
state.receiptRpcDown = false;
|
|
451
|
+
await vi.advanceTimersByTimeAsync(30_000);
|
|
452
|
+
await wait;
|
|
453
|
+
expect(settled).toBe("success");
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it("gives up on an RPC outage only at the timeout, with the RPC's error as the cause", async () => {
|
|
457
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
458
|
+
state.receiptRpcDown = true;
|
|
459
|
+
const error = await client.waitForTransactionReceipt(hash, { timeout: 50 }).catch((e) => e);
|
|
460
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
461
|
+
expect(error.hash).toBe(hash);
|
|
462
|
+
expect(error.cause).toBeDefined();
|
|
463
|
+
expect(classifyTxError(error)).toBe("pending");
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it("resolves a reverted receipt from waitForTransactionReceipt, as before", async () => {
|
|
467
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
468
|
+
state.reverted = new Set([hash]);
|
|
469
|
+
await expect(client.waitForTransactionReceipt(hash)).resolves.toMatchObject({
|
|
470
|
+
status: "reverted",
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it("rejects a reverted receipt from confirmTransaction as TransactionRevertedError", async () => {
|
|
475
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
476
|
+
state.reverted = new Set([hash]);
|
|
477
|
+
const error = await client.confirmTransaction(hash).catch((e) => e);
|
|
478
|
+
expect(error).toBeInstanceOf(TransactionRevertedError);
|
|
479
|
+
expect(error).toMatchObject({ hash, chainId: 1, mayStillLand: false });
|
|
480
|
+
expect(error.receipt.status).toBe("reverted");
|
|
481
|
+
expect(classifyTxError(error)).toBe("reverted");
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it("rejects a transaction the wallet cancelled instead of resolving the cancel's receipt", async () => {
|
|
485
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
486
|
+
const cancel = hashFor(99);
|
|
487
|
+
state.pending = new Set([hash]);
|
|
488
|
+
state.mined = new Map([[cancel, { to: account, value: "0x0", nonce: "0x0" }]]);
|
|
489
|
+
state.blockTransactions = [cancel];
|
|
490
|
+
state.nonceUsed = 1;
|
|
491
|
+
const error = await client.waitForTransactionReceipt(hash).catch((e) => e);
|
|
492
|
+
expect(error).toBeInstanceOf(TransactionReplacedError);
|
|
493
|
+
expect(error).toMatchObject({ hash, reason: "cancelled", mayStillLand: false });
|
|
494
|
+
expect(error.replacement.transactionHash).toBe(cancel);
|
|
495
|
+
expect(classifyTxError(error)).toBe("user-rejected");
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it("settles concurrent waits, and a later one, on the same hash", async () => {
|
|
499
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
500
|
+
state.pending = new Set([hash]);
|
|
501
|
+
const hasty = client.waitForTransactionReceipt(hash, { timeout: 20 }).catch((e) => e);
|
|
502
|
+
const patient = client.confirmTransaction(hash);
|
|
503
|
+
expect(await hasty).toBeInstanceOf(ReceiptPendingError);
|
|
504
|
+
state.pending.clear();
|
|
505
|
+
state.block = 17n;
|
|
506
|
+
await expect(patient).resolves.toMatchObject({ status: "success" });
|
|
507
|
+
await expect(client.confirmTransaction(hash, { timeout: 1_000 })).resolves.toMatchObject({
|
|
508
|
+
transactionHash: hash,
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it("sees a cancel the node saw before this wait began, given the nonce", async () => {
|
|
513
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
514
|
+
const cancel = hashFor(97);
|
|
515
|
+
state.forgotten = new Set([hash]);
|
|
516
|
+
state.mined = new Map([[cancel, { to: account, value: "0x0", nonce: "0x0" }]]);
|
|
517
|
+
state.blockTransactions = [cancel];
|
|
518
|
+
state.nonceUsed = 1;
|
|
519
|
+
const error = await client.confirmTransaction(hash, { nonce: 0 }).catch((e) => e);
|
|
520
|
+
expect(error).toBeInstanceOf(TransactionReplacedError);
|
|
521
|
+
expect(error).toMatchObject({ reason: "cancelled", mayStillLand: false });
|
|
522
|
+
expect(error.replacement.transactionHash).toBe(cancel);
|
|
523
|
+
expect(classifyTxError(error)).toBe("user-rejected");
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it("calls a taken nonce it cannot compare pending, since it may be a speed-up", async () => {
|
|
527
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
528
|
+
const taker = hashFor(96);
|
|
529
|
+
state.forgotten = new Set([hash]);
|
|
530
|
+
state.mined = new Map([[taker, { to: spender, value: "0x1", nonce: "0x0" }]]);
|
|
531
|
+
state.blockTransactions = [taker];
|
|
532
|
+
state.nonceUsed = 1;
|
|
533
|
+
const error = await client.confirmTransaction(hash, { nonce: 0 }).catch((e) => e);
|
|
534
|
+
expect(error).toBeInstanceOf(TransactionReplacedError);
|
|
535
|
+
expect(error.reason).toBe("unmatched");
|
|
536
|
+
expect(error.replacement.transactionHash).toBe(taker);
|
|
537
|
+
expect(classifyTxError(error)).toBe("pending");
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
it("keeps waiting when the block that took the nonce does not list it, as after a reorg", async () => {
|
|
541
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
542
|
+
state.forgotten = new Set([hash]);
|
|
543
|
+
state.nonceUsed = 1;
|
|
544
|
+
const error = await client
|
|
545
|
+
.confirmTransaction(hash, { nonce: 0, timeout: 50 })
|
|
546
|
+
.catch((e) => e);
|
|
547
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
548
|
+
expect(classifyTxError(error)).toBe("pending");
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it("finds a cancel 5000 blocks before a reload by binary search, fetching one block", async () => {
|
|
552
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
553
|
+
const cancel = hashFor(95);
|
|
554
|
+
state.forgotten = new Set([hash]);
|
|
555
|
+
state.mined = new Map([[cancel, { to: account, value: "0x0", nonce: "0x0" }]]);
|
|
556
|
+
state.blockTransactions = [cancel];
|
|
557
|
+
state.nonceUsed = 1;
|
|
558
|
+
state.block = 20_000n;
|
|
559
|
+
state.takenAt = 15_000n;
|
|
560
|
+
const error = await client.confirmTransaction(hash, { nonce: 0 }).catch((e) => e);
|
|
561
|
+
expect(error).toBeInstanceOf(TransactionReplacedError);
|
|
562
|
+
expect(error.reason).toBe("cancelled");
|
|
563
|
+
expect(error.replacement.transactionHash).toBe(cancel);
|
|
564
|
+
expect(classifyTxError(error)).toBe("user-rejected");
|
|
565
|
+
expect(mock.blocksFetched()).toEqual([15_000n]);
|
|
566
|
+
expect(mock.count("eth_getTransactionCount")).toBeLessThan(40);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
it("resolves a speed-up mined while the tab slept 2000 blocks with the faster copy's receipt", async () => {
|
|
570
|
+
vi.useFakeTimers();
|
|
571
|
+
const polled = makeClient(4_000);
|
|
572
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
573
|
+
const faster = hashFor(94);
|
|
574
|
+
state.pending = new Set([hash]);
|
|
575
|
+
state.nonceUsed = 0;
|
|
576
|
+
state.block = 1_000n;
|
|
577
|
+
let settled: string | undefined;
|
|
578
|
+
const wait = polled.confirmTransaction(hash).then(
|
|
579
|
+
(receipt) => (settled = receipt.transactionHash),
|
|
580
|
+
(error: Error) => (settled = error.name),
|
|
581
|
+
);
|
|
582
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
583
|
+
expect(mock.count("eth_getTransactionCount")).toBe(1);
|
|
584
|
+
state.mined = new Map([[faster, { to: spender, value: "0x1", nonce: "0x0" }]]);
|
|
585
|
+
state.blockTransactions = [faster];
|
|
586
|
+
state.nonceUsed = 1;
|
|
587
|
+
state.block = 3_000n;
|
|
588
|
+
state.takenAt = 1_001n;
|
|
589
|
+
await vi.advanceTimersByTimeAsync(10_000);
|
|
590
|
+
await wait;
|
|
591
|
+
expect(settled).toBe(faster);
|
|
592
|
+
expect(mock.blocksFetched()).toEqual([1_001n]);
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it("sleeps between polls while a speed-up it switched to has no receipt yet", async () => {
|
|
596
|
+
const polled = makeClient(20);
|
|
597
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
598
|
+
const faster = hashFor(93);
|
|
599
|
+
state.pending = new Set([hash, faster]);
|
|
600
|
+
state.mined = new Map([[faster, { to: spender, value: "0x1", nonce: "0x0" }]]);
|
|
601
|
+
state.blockTransactions = [faster];
|
|
602
|
+
state.nonceUsed = 1;
|
|
603
|
+
const error = await polled.confirmTransaction(hash, { timeout: 200 }).catch((e) => e);
|
|
604
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
605
|
+
expect(mock.count("eth_blockNumber")).toBeLessThan(20);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it("rejects at once with an AbortError when the signal is already aborted", async () => {
|
|
609
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
610
|
+
const before = mock.calls.length;
|
|
611
|
+
const error = await client
|
|
612
|
+
.confirmTransaction(hash, { signal: AbortSignal.abort("unmounted") })
|
|
613
|
+
.catch((e) => e);
|
|
614
|
+
expect(error).toBeInstanceOf(ReceiptWaitAbortedError);
|
|
615
|
+
expect(error).toMatchObject({ name: "AbortError", hash, chainId: 1, cause: "unmounted" });
|
|
616
|
+
expect(classifyTxError(error)).toBe("aborted");
|
|
617
|
+
expect(mock.calls.length).toBe(before);
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
it("stops polling when the signal aborts mid-wait", async () => {
|
|
621
|
+
const polled = makeClient(10);
|
|
622
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
623
|
+
state.pending = new Set([hash]);
|
|
624
|
+
const controller = new AbortController();
|
|
625
|
+
const wait = polled.confirmTransaction(hash, { signal: controller.signal }).catch((e) => e);
|
|
626
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
627
|
+
expect(mock.count("eth_getTransactionReceipt")).toBeGreaterThan(1);
|
|
628
|
+
controller.abort();
|
|
629
|
+
const error = await wait;
|
|
630
|
+
expect(error).toBeInstanceOf(ReceiptWaitAbortedError);
|
|
631
|
+
expect(error.nonce).toBe(0);
|
|
632
|
+
expect(classifyTxError(error)).toBe("aborted");
|
|
633
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
634
|
+
const polls = mock.count("eth_getTransactionReceipt");
|
|
635
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
636
|
+
expect(mock.count("eth_getTransactionReceipt")).toBe(polls);
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it("holds no abort listener past the poll or sleep it guards", async () => {
|
|
640
|
+
const polled = makeClient(1);
|
|
641
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
642
|
+
state.pending = new Set([hash]);
|
|
643
|
+
const controller = new AbortController();
|
|
644
|
+
const add = vi.spyOn(controller.signal, "addEventListener");
|
|
645
|
+
const remove = vi.spyOn(controller.signal, "removeEventListener");
|
|
646
|
+
const wait = polled.confirmTransaction(hash, { signal: controller.signal }).catch((e) => e);
|
|
647
|
+
while (mock.count("eth_getTransactionReceipt") < 50) {
|
|
648
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
649
|
+
}
|
|
650
|
+
expect(add.mock.calls.length).toBeGreaterThan(50);
|
|
651
|
+
expect(add.mock.calls.length - remove.mock.calls.length).toBeLessThanOrEqual(1);
|
|
652
|
+
controller.abort();
|
|
653
|
+
expect(await wait).toBeInstanceOf(ReceiptWaitAbortedError);
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it("leaves no abort listener when the deadline lands mid-sleep", async () => {
|
|
657
|
+
const polled = makeClient(1_000);
|
|
658
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
659
|
+
state.pending = new Set([hash]);
|
|
660
|
+
const controller = new AbortController();
|
|
661
|
+
const add = vi.spyOn(controller.signal, "addEventListener");
|
|
662
|
+
const remove = vi.spyOn(controller.signal, "removeEventListener");
|
|
663
|
+
const error = await polled
|
|
664
|
+
.confirmTransaction(hash, { signal: controller.signal, timeout: 50 })
|
|
665
|
+
.catch((e) => e);
|
|
666
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
667
|
+
expect(add.mock.calls.length).toBe(remove.mock.calls.length);
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
it("leaves no timer when the signal aborts mid-sleep under a long timeout", async () => {
|
|
671
|
+
vi.useFakeTimers();
|
|
672
|
+
const polled = makeClient(1_000);
|
|
673
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
674
|
+
state.pending = new Set([hash]);
|
|
675
|
+
const controller = new AbortController();
|
|
676
|
+
const wait = polled
|
|
677
|
+
.confirmTransaction(hash, { signal: controller.signal, timeout: 600_000 })
|
|
678
|
+
.catch((e) => e);
|
|
679
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
680
|
+
controller.abort();
|
|
681
|
+
expect(await wait).toBeInstanceOf(ReceiptWaitAbortedError);
|
|
682
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
it("keeps waiting under a timeout of Infinity or past 2^31 ms", async () => {
|
|
686
|
+
const polled = makeClient(10);
|
|
687
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
688
|
+
state.pending = new Set([hash]);
|
|
689
|
+
const controller = new AbortController();
|
|
690
|
+
const settled: string[] = [];
|
|
691
|
+
const waits = [Infinity, 2 ** 31, 2 ** 32 + 5].map((timeout) =>
|
|
692
|
+
polled
|
|
693
|
+
.confirmTransaction(hash, { timeout, signal: controller.signal })
|
|
694
|
+
.catch((e: Error) => settled.push(`${timeout}: ${e.name}`)),
|
|
695
|
+
);
|
|
696
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
697
|
+
expect(settled).toEqual([]);
|
|
698
|
+
controller.abort();
|
|
699
|
+
await Promise.all(waits);
|
|
700
|
+
expect(settled).toHaveLength(3);
|
|
701
|
+
expect(settled.every((line) => line.endsWith("AbortError"))).toBe(true);
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
it("hands onTrack nothing once the wait has been aborted", async () => {
|
|
705
|
+
const polled = makeClient(10);
|
|
706
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
707
|
+
state.pending = new Set([hash]);
|
|
708
|
+
let release = () => {};
|
|
709
|
+
state.txLookupGate = new Promise<void>((resolve) => {
|
|
710
|
+
release = resolve;
|
|
711
|
+
});
|
|
712
|
+
const onTrack = vi.fn();
|
|
713
|
+
const controller = new AbortController();
|
|
714
|
+
const wait = polled
|
|
715
|
+
.confirmTransaction(hash, { signal: controller.signal, onTrack })
|
|
716
|
+
.catch((e) => e);
|
|
717
|
+
while (mock.count("eth_getTransactionByHash") < 1) {
|
|
718
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
719
|
+
}
|
|
720
|
+
controller.abort();
|
|
721
|
+
expect(await wait).toBeInstanceOf(ReceiptWaitAbortedError);
|
|
722
|
+
release();
|
|
723
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
724
|
+
expect(onTrack).not.toHaveBeenCalled();
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
it("gives up at the timeout while an RPC call hangs", async () => {
|
|
728
|
+
const hung = evmClient({
|
|
729
|
+
provider: mock.provider as never,
|
|
730
|
+
account,
|
|
731
|
+
chain: mainnet,
|
|
732
|
+
publicClient: createPublicClient({
|
|
733
|
+
chain: mainnet,
|
|
734
|
+
pollingInterval: 10,
|
|
735
|
+
transport: custom({ request: () => new Promise(() => {}) }),
|
|
736
|
+
}),
|
|
737
|
+
});
|
|
738
|
+
const started = Date.now();
|
|
739
|
+
const error = await hung.waitForTransactionReceipt(txHash, { timeout: 100 }).catch((e) => e);
|
|
740
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
741
|
+
expect(Date.now() - started).toBeLessThan(1_000);
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
it("hands onTrack the nonce once, then a speed-up's hash", async () => {
|
|
745
|
+
const polled = makeClient(10);
|
|
746
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
747
|
+
const faster = hashFor(92);
|
|
748
|
+
state.pending = new Set([hash]);
|
|
749
|
+
const tracked: { hash: Hex; nonce: number }[] = [];
|
|
750
|
+
const wait = polled.confirmTransaction(hash, {
|
|
751
|
+
onTrack: (t) => {
|
|
752
|
+
tracked.push(t);
|
|
753
|
+
throw new Error("the app's bookkeeping broke");
|
|
754
|
+
},
|
|
755
|
+
});
|
|
756
|
+
while (mock.count("eth_getTransactionCount") < 3) {
|
|
757
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
758
|
+
}
|
|
759
|
+
expect(tracked).toEqual([{ hash, nonce: 0 }]);
|
|
760
|
+
state.mined = new Map([[faster, { to: spender, value: "0x1", nonce: "0x0" }]]);
|
|
761
|
+
state.blockTransactions = [faster];
|
|
762
|
+
state.nonceUsed = 1;
|
|
763
|
+
await expect(wait).resolves.toMatchObject({ transactionHash: faster });
|
|
764
|
+
expect(tracked).toEqual([
|
|
765
|
+
{ hash, nonce: 0 },
|
|
766
|
+
{ hash: faster, nonce: 0 },
|
|
767
|
+
]);
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
it("aborts a wait backing off from an RPC outage without waiting out the backoff", async () => {
|
|
771
|
+
const polled = makeClient(5_000);
|
|
772
|
+
const hash = await polled.sendTransaction({ to: spender, value: 1n });
|
|
773
|
+
state.receiptRpcDown = true;
|
|
774
|
+
const controller = new AbortController();
|
|
775
|
+
const wait = polled.confirmTransaction(hash, { signal: controller.signal }).catch((e) => e);
|
|
776
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
777
|
+
const started = Date.now();
|
|
778
|
+
controller.abort();
|
|
779
|
+
expect(await wait).toBeInstanceOf(ReceiptWaitAbortedError);
|
|
780
|
+
expect(Date.now() - started).toBeLessThan(100);
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
it("keeps waiting on a hash the node forgot while its nonce is still free", async () => {
|
|
784
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
785
|
+
state.forgotten = new Set([hash]);
|
|
786
|
+
state.nonceUsed = 0;
|
|
787
|
+
const error = await client
|
|
788
|
+
.confirmTransaction(hash, { nonce: 0, timeout: 50 })
|
|
789
|
+
.catch((e) => e);
|
|
790
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
791
|
+
expect(classifyTxError(error)).toBe("pending");
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
it("resolves a sped-up transaction with the faster copy's receipt", async () => {
|
|
795
|
+
const hash = await client.sendTransaction({ to: spender, value: 1n });
|
|
796
|
+
const faster = hashFor(98);
|
|
797
|
+
state.pending = new Set([hash]);
|
|
798
|
+
state.mined = new Map([[faster, { to: spender, value: "0x1", nonce: "0x0" }]]);
|
|
799
|
+
state.blockTransactions = [faster];
|
|
800
|
+
state.nonceUsed = 1;
|
|
801
|
+
const receipt = await client.confirmTransaction(hash);
|
|
802
|
+
expect(receipt.transactionHash).toBe(faster);
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
describe("classifyTxError", () => {
|
|
807
|
+
it("classifies a wallet rejection of a send as user-rejected", async () => {
|
|
808
|
+
state.userRejects = true;
|
|
809
|
+
const error = await client.sendTransaction({ to: spender, value: 1n }).catch((e) => e);
|
|
810
|
+
expect(classifyTxError(error)).toBe("user-rejected");
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
it("classifies a wallet rejection of an ERC-20 transfer as user-rejected", async () => {
|
|
814
|
+
state.userRejects = true;
|
|
815
|
+
const error = await client.erc20.transfer({ token, to: spender, amount: 3n }).catch((e) => e);
|
|
816
|
+
expect(classifyTxError(error)).toBe("user-rejected");
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
it("classifies a raw EIP-1193 4001 as user-rejected", () => {
|
|
820
|
+
expect(classifyTxError({ code: 4001, message: "User rejected the request." })).toBe(
|
|
821
|
+
"user-rejected",
|
|
822
|
+
);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
it("classifies a transfer the simulation reverts as reverted, before any send", async () => {
|
|
826
|
+
state.usdt = true;
|
|
827
|
+
state.allowance = 5n;
|
|
828
|
+
const error = await client.erc20.approve({ token, spender, amount: 9n }).catch((e) => e);
|
|
829
|
+
expect(classifyTxError(error)).toBe("reverted");
|
|
830
|
+
expect(mock.sent).toEqual([]);
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
it("classifies viem's own receipt timeout as pending", () => {
|
|
834
|
+
expect(classifyTxError(new WaitForTransactionReceiptTimeoutError({ hash: txHash }))).toBe(
|
|
835
|
+
"pending",
|
|
836
|
+
);
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
it("classifies only this module's aborts as aborted", () => {
|
|
840
|
+
const wait = new ReceiptWaitAbortedError(txHash, 1, 0, "unmounted");
|
|
841
|
+
expect(classifyTxError(wait)).toBe("aborted");
|
|
842
|
+
expect(classifyTxError(new Error("buy", { cause: wait }))).toBe("aborted");
|
|
843
|
+
const foreign = Object.assign(new Error("The operation was aborted."), {
|
|
844
|
+
name: "AbortError",
|
|
845
|
+
});
|
|
846
|
+
expect(classifyTxError(foreign)).toBe("failed");
|
|
847
|
+
expect(
|
|
848
|
+
classifyTxError(
|
|
849
|
+
new ReceiptPendingError(txHash, 1, { detail: "has no receipt", cause: foreign }),
|
|
850
|
+
),
|
|
851
|
+
).toBe("pending");
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
it("classifies anything else as failed", () => {
|
|
855
|
+
expect(classifyTxError(new Error("insufficient funds for gas"))).toBe("failed");
|
|
856
|
+
expect(classifyTxError(undefined)).toBe("failed");
|
|
857
|
+
});
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
describe("ensureAllowance", () => {
|
|
861
|
+
it("throws TransactionRevertedError when the approval reverts", async () => {
|
|
862
|
+
state.reverted = new Set([txHash]);
|
|
863
|
+
const error = await client.erc20
|
|
864
|
+
.ensureAllowance({ token, spender, amount: 50n })
|
|
865
|
+
.catch((e) => e);
|
|
866
|
+
expect(error).toBeInstanceOf(TransactionRevertedError);
|
|
867
|
+
expect(error.hash).toBe(txHash);
|
|
868
|
+
expect(classifyTxError(error)).toBe("reverted");
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
it("throws ReceiptPendingError with the approval hash when it outlasts the timeout", async () => {
|
|
872
|
+
state.pending = new Set([txHash]);
|
|
873
|
+
const error = await client.erc20
|
|
874
|
+
.ensureAllowance({ token, spender, amount: 50n, timeout: 50 })
|
|
875
|
+
.catch((e) => e);
|
|
876
|
+
expect(error).toBeInstanceOf(ReceiptPendingError);
|
|
877
|
+
expect(error.hash).toBe(txHash);
|
|
878
|
+
expect(error.message).toMatch(new RegExp(`^approve ${txHash}`));
|
|
879
|
+
expect(classifyTxError(error)).toBe("pending");
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
it("sends no approval once its signal has aborted", async () => {
|
|
883
|
+
const error = await client.erc20
|
|
884
|
+
.ensureAllowance({ token, spender, amount: 50n, signal: AbortSignal.abort() })
|
|
885
|
+
.catch((e) => e);
|
|
886
|
+
expect(error).toMatchObject({ name: "AbortError", mayStillLand: false });
|
|
887
|
+
expect(classifyTxError(error)).toBe("aborted");
|
|
888
|
+
expect(mock.sent).toEqual([]);
|
|
889
|
+
});
|
|
890
|
+
|
|
891
|
+
it("passes a wallet rejection of the approval through as user-rejected", async () => {
|
|
892
|
+
state.userRejects = true;
|
|
893
|
+
const error = await client.erc20
|
|
894
|
+
.ensureAllowance({ token, spender, amount: 50n })
|
|
895
|
+
.catch((e) => e);
|
|
896
|
+
expect(classifyTxError(error)).toBe("user-rejected");
|
|
897
|
+
});
|
|
898
|
+
});
|
|
265
899
|
});
|