From 9268817ba334446822eb0c3e6ecc2a4025f9595c Mon Sep 17 00:00:00 2001 From: Korbinian Date: Mon, 2 Oct 2023 16:40:55 +0200 Subject: [PATCH 1/8] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 350e93544eb45eaa3ee7c67241a19e7e4ff5bc31 Author: Kenk Date: Mon Oct 2 20:27:24 2023 +0700 feat(website): add AIT Protocol to ecosystem (#14868) commit 70e3034ca6642f06d900da349e396e9e73674839 Author: Vitalik <95872804+Vitek7373@users.noreply.github.com> Date: Sat Sep 30 21:21:47 2023 +0400 Update prover-market-page.mdx (#14854) commit d9f4f438bab8e82556cfc4e0a3f6c1d088692b36 Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Fri Sep 29 21:40:08 2023 -0400 docs(website): proposer + prover private key format and status log command to find errors (#14862) Co-authored-by: Roger <50648015+RogerLamTd@users.noreply.github.com> commit f2ba2217876fd75e5ce8a5520e7101297fe35575 Author: Razafindrabe Michaël Maminiaina Date: Fri Sep 29 02:57:01 2023 +0300 chore(docs): add RZF Node to prover list (#14847) commit 7f4fe71ca70141932f4e8de9a581aa609054a311 Author: Ravil Ayupov <35985944+RexCloud@users.noreply.github.com> Date: Thu Sep 28 08:14:01 2023 +0500 docs(website): add prover endpoint to prover market page (#14841) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit b3cd84a3e47918bcf317c72d7b18f3eee8406f14 Author: 0xCryptic <145868409+0xCryptic1@users.noreply.github.com> Date: Thu Sep 28 08:32:57 2023 +0530 docs(website): Update enable-a-proposer.mdx with command to check Proposer logs (#14844) commit db7c31d6781a6018502a24c103446c086371d9ef Author: broccoin <58350903+broccoin-jp@users.noreply.github.com> Date: Thu Sep 28 00:26:00 2023 +0900 fix(website): Correcting broken link (#14840) commit 4cfcc427e2b3a8026510bd644e82d7cf71686c92 Author: Kenk Date: Wed Sep 27 09:35:38 2023 +0700 feat(website): add izar and omnisea to ecosystem page (#14825) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit f4b06db3afa2ef9cbf71a60250526f8052545337 Author: Kenk Date: Tue Sep 26 21:00:19 2023 +0700 feat(website): add gourds to ecosystem (#14818) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit e704fc415fafc702d5306510bdc3d8cd4bc6c030 Author: moenorman <138952058+moenorman@users.noreply.github.com> Date: Tue Sep 26 01:23:32 2023 -0400 feat(website): add `ZK Nodes` to prover fee market (#14817) commit 72e0431170247d4e295b50db41a8c3de82f2d4e8 Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Mon Sep 25 22:38:12 2023 -0400 docs(website): node troubleshooting info: `Skip an invlaid proposed transaction reason="nonce too low` (#14814) Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com> Co-authored-by: Roger <50648015+RogerLamTd@users.noreply.github.com> commit 73b294447add5565ce9f39296801fc57738bb5ce Author: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> Date: Mon Sep 25 22:14:51 2023 +0900 docs(website): add windows guidance and remove sudo (#14806) commit 1bc2ea79be88dc29da4969bbe31ef2eb20a7001d Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Mon Sep 25 09:14:39 2023 -0400 feat(website): add Alphamint and Xverse to ecosystem (#14807) commit bf92399fd6667baab194741a0a36809764b38dca Author: Kenk Date: Mon Oct 2 20:27:24 2023 +0700 feat(website): add AIT Protocol to ecosystem (#14868) commit a64ae4eab841c7d0ddf94083e7d9039e6ed822e8 Author: dave <13951458+d1onys1us@users.noreply.github.com> Date: Mon Oct 2 19:28:56 2023 +0900 feat(website): add link to swap v3 (#14883) commit 62719e774ed520d90f35b2229241f23a4312aaeb Author: Kenk Date: Mon Oct 2 15:09:45 2023 +0700 feat(website): update TaikoL1 impl address (#14879) commit d8f40c150a124912d00cd8c73a5ded3c88d901a7 Author: xiaodino Date: Sun Oct 1 21:56:48 2023 -0700 chore(bridge-ui-v2): Update right top buttons to same UI styles (#14872) commit 067c86a7e908ca6462a4f13473ad161398390d18 Author: pessori55 <108002555+pessori55@users.noreply.github.com> Date: Mon Oct 2 00:30:42 2023 +0900 docs(website): add Sepolia faucet (#14865) commit ff375f4fa74d25036b788b5cbdc0a567754e2b4e Author: Vitalik <95872804+Vitek7373@users.noreply.github.com> Date: Sat Sep 30 21:21:47 2023 +0400 Update prover-market-page.mdx (#14854) commit 26adcd3030a885603fb9f6657aff904428a2685f Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Fri Sep 29 21:40:08 2023 -0400 docs(website): proposer + prover private key format and status log command to find errors (#14862) Co-authored-by: Roger <50648015+RogerLamTd@users.noreply.github.com> commit e900dd937b98e8636ef2bf37b55a2e7f04844112 Author: Korbinian Date: Fri Sep 29 23:14:11 2023 +0200 chore(bridge-ui-v2): pre-select destination chain (#14850) Co-authored-by: David commit 745c196b936e686f5600abe9e863ce8b1c078e58 Author: Kenk Date: Fri Sep 29 22:30:17 2023 +0700 feat(website): update Bitget on ecosystem page (#14855) commit 9aec36466c2a09e58e82f131b2bb6982108fe138 Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Fri Sep 29 00:11:17 2023 -0400 docs(website): prover proposer danger private key with nextra callout type error + generate isolated burner wallet (#14853) commit eae3927ae3c44aa6de3ccfb615b009c70ac0c122 Author: Razafindrabe Michaël Maminiaina Date: Fri Sep 29 02:57:01 2023 +0300 chore(docs): add RZF Node to prover list (#14847) commit 8dd8b611eec26720d550838177c7947a4a5a7a26 Author: Korbinian Date: Thu Sep 28 05:53:32 2023 +0200 feat(bridge-ui-v2): NFT bridge stepper (#14811) commit a61fd728b1c2ab6f2a31fbbe613cbd9bcea92e18 Author: Ravil Ayupov <35985944+RexCloud@users.noreply.github.com> Date: Thu Sep 28 08:14:01 2023 +0500 docs(website): add prover endpoint to prover market page (#14841) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit fac8f7296e267768d9e3e96eac3f56e77c8e6607 Author: 0xCryptic <145868409+0xCryptic1@users.noreply.github.com> Date: Thu Sep 28 08:32:57 2023 +0530 docs(website): Update enable-a-proposer.mdx with command to check Proposer logs (#14844) commit 7900d8e0a575e34374cbd2c0ccdd7772e4877cb1 Author: broccoin <58350903+broccoin-jp@users.noreply.github.com> Date: Thu Sep 28 00:26:00 2023 +0900 fix(website): Correcting broken link (#14840) commit 3bc0a456e9aaa24af174268ae8009e6232422fdf Author: broccoin <58350903+broccoin-jp@users.noreply.github.com> Date: Wed Sep 27 21:36:55 2023 +0900 fix(website): broken link (#14839) Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com> commit cf4ebdd664eb88a1ec08e829f970f4efbae4bf5c Author: David Cardenas <47157243+davidcardenasus@users.noreply.github.com> Date: Wed Sep 27 05:35:01 2023 -0700 docs(repo): Add YouTube to README (#14833) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit c00a216dab2193b2e4b43ad62d18d7b7db3e234b Author: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> Date: Wed Sep 27 21:33:26 2023 +0900 docs(website): use remix by default (#14836) commit 5942326256b799c640e06f89c614d07e6abc598e Author: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> Date: Wed Sep 27 15:12:20 2023 +0900 docs(protocol): add taiko deployment docs and remove bll (#14834) commit df2e8b9e9266c9969a4b5f59870529d42509c1b4 Author: broccoin <58350903+broccoin-jp@users.noreply.github.com> Date: Wed Sep 27 11:39:28 2023 +0900 docs(website): update node-runner-manual "how to compare .env and .env.sample" (#14831) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit e7c66a3071ecac7c1418eb660aa804d671b699f5 Author: Kenk Date: Wed Sep 27 09:36:05 2023 +0700 feat(website): add proof market video (#14824) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit be216d069ddfedb471fb76bcca0241a85cdef866 Author: Kenk Date: Wed Sep 27 09:35:38 2023 +0700 feat(website): add izar and omnisea to ecosystem page (#14825) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit cb9c779f6096d24e8eeb4c67dc83547610da2a09 Author: Kenk Date: Tue Sep 26 21:00:19 2023 +0700 feat(website): add gourds to ecosystem (#14818) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit 1405121b4dce1a0f4bba0a33870e24ee3a270629 Author: moenorman <138952058+moenorman@users.noreply.github.com> Date: Tue Sep 26 01:23:32 2023 -0400 feat(website): add `ZK Nodes` to prover fee market (#14817) commit 23f5bf6a513a7ba0d86c5014178b5a161e38022f Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Mon Sep 25 22:38:12 2023 -0400 docs(website): node troubleshooting info: `Skip an invlaid proposed transaction reason="nonce too low` (#14814) Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com> Co-authored-by: Roger <50648015+RogerLamTd@users.noreply.github.com> commit cde533ca6bd6d13e557a68dc4f9e4fc7abcd14f4 Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Mon Sep 25 22:13:06 2023 -0400 docs(website): update FAQ `Does Taiko have a sequencer?` (#14812) commit a67c495aa371b97dc30edb6be452b4e689b6d6be Author: D <51912515+adaki2004@users.noreply.github.com> Date: Tue Sep 26 04:00:13 2023 +0200 fix(protocol): Fix genesis tests (#14813) commit 833b4f5277823509d29b9ad163f68d8d0392b748 Author: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> Date: Mon Sep 25 22:15:22 2023 +0900 chore(repo): update add_project issue template (#14805) commit df7be214fc17324468ae713f2fcc0f67a7e14946 Author: Kenk Date: Mon Sep 25 20:15:12 2023 +0700 feat(website): add uniswap v3 addresses (#14804) Co-authored-by: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> commit 7367f016ce652e66200bde331e3daee622c8cef5 Author: dave | d1onys1us <13951458+d1onys1us@users.noreply.github.com> Date: Mon Sep 25 22:14:51 2023 +0900 docs(website): add windows guidance and remove sudo (#14806) commit e23c267694289ee4bb46b2b25b7b4796504350c0 Author: Marcus Wentz <52706599+MarcusWentz@users.noreply.github.com> Date: Mon Sep 25 09:14:39 2023 -0400 feat(website): add Alphamint and Xverse to ecosystem (#14807) commit 23636c7a3be2b8410f30b72442fae00e31bfaa1b Author: Korbinian Date: Mon Oct 2 16:09:49 2023 +0200 bridgetabs sizes commit 7fa506cfa279fe0642250379a9370c4b31e9e783 Author: Korbinian Date: Wed Sep 27 17:01:06 2023 +0200 import steps, validating ownership etc commit 0bf4d7898d8010b3c85b52cd7771b3564918e4d0 Author: Korbinian Date: Wed Sep 27 16:57:33 2023 +0200 i18n commit 02fac48508fb2c44c78af2aefa5ec843d62d1738 Author: Korbinian Kasberger Date: Wed Sep 27 09:20:32 2023 +0200 basic layout commit e56a890e155ce6cf685805e6feaa12482a1ea4c0 Author: Korbinian Kasberger Date: Mon Sep 25 17:04:05 2023 +0200 fix button size commit 76160480b9ba77f4f453b32f743d57b58caf5c1e Author: Korbinian Kasberger Date: Mon Sep 25 16:55:17 2023 +0200 basic dynamic stepper commit b9281d7e690540dbe66c311e19a567b23dc2400b Author: Korbinian Kasberger Date: Mon Sep 25 16:54:39 2023 +0200 add bridgetypes, tabs to store --- .../{ => AddressInput}/AddressInput.svelte | 46 ++-- .../components/Bridge/AddressInput/state.ts | 7 + .../src/components/Bridge/Bridge.svelte | 230 +++++++++++++++--- .../src/components/Bridge/IDInput.svelte | 67 +++++ .../src/components/Bridge/Recipient.svelte | 2 +- .../ChainSelector/ChainSelectorWrapper.svelte | 9 +- .../TokenDropdown/AddCustomERC20.svelte | 2 +- packages/bridge-ui-v2/src/i18n/en.json | 19 +- .../src/libs/token/detectContractType.ts | 67 ++--- 9 files changed, 336 insertions(+), 113 deletions(-) rename packages/bridge-ui-v2/src/components/Bridge/{ => AddressInput}/AddressInput.svelte (64%) create mode 100644 packages/bridge-ui-v2/src/components/Bridge/AddressInput/state.ts create mode 100644 packages/bridge-ui-v2/src/components/Bridge/IDInput.svelte diff --git a/packages/bridge-ui-v2/src/components/Bridge/AddressInput.svelte b/packages/bridge-ui-v2/src/components/Bridge/AddressInput/AddressInput.svelte similarity index 64% rename from packages/bridge-ui-v2/src/components/Bridge/AddressInput.svelte rename to packages/bridge-ui-v2/src/components/Bridge/AddressInput/AddressInput.svelte index be417f388d..7827858b1a 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/AddressInput.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/AddressInput/AddressInput.svelte @@ -8,17 +8,16 @@ import { Icon } from '$components/Icon'; import { uid } from '$libs/util/uid'; - enum State { - Valid = 'valid', - Invalid = 'invalid', - TooShort = 'too_short', - } + import { AddressInputState as State } from './state'; + + export let ethereumAddress: Address | string = ''; + export let labelText = $t('inputs.address_input.label.default'); + export let isDisabled = false; + export let quiet = false; + export let state: State = State.Default; let input: HTMLInputElement; let inputId = `input-${uid()}`; - let state: State; - - export let ethereumAddress: Address | string = ''; const dispatch = createEventDispatcher(); @@ -51,7 +50,7 @@ $: validateEthereumAddress(ethereumAddress); export const clear = () => { - input.value = ''; + if (input) input.value = ''; validateEthereumAddress(''); }; @@ -60,30 +59,33 @@
- +
validateEthereumAddress(e.target)} - class="w-full input-box withValdiation py-6 pr-16 px-[26px] title-subsection-bold placeholder:text-tertiary-content - {state === State.Valid ? 'success' : ethereumAddress ? 'error' : ''} + class="w-full input-box withValdiation py-6 pr-16 px-[26px] title-subsection-bold placeholder:text-tertiary-content {$$props.class} + {state === State.Valid ? 'success' : ethereumAddress && state !== State.Validating ? 'error' : ''} " />
-
- {#if state === State.Invalid && ethereumAddress} - - {:else if state === State.TooShort && ethereumAddress} - - {:else if state === State.Valid} - - {/if} -
+ +{#if !quiet} +
+ {#if state === State.Invalid && ethereumAddress} + + {:else if state === State.TooShort && ethereumAddress} + + {:else if state === State.Valid} + + {/if} +
+{/if} diff --git a/packages/bridge-ui-v2/src/components/Bridge/AddressInput/state.ts b/packages/bridge-ui-v2/src/components/Bridge/AddressInput/state.ts new file mode 100644 index 0000000000..5ba71e8ea8 --- /dev/null +++ b/packages/bridge-ui-v2/src/components/Bridge/AddressInput/state.ts @@ -0,0 +1,7 @@ +export enum AddressInputState { + Default = 'default', + Valid = 'valid', + Invalid = 'invalid', + TooShort = 'too_short', + Validating = 'validating', +} diff --git a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte index 8bae4c9b84..4d240bce9d 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte @@ -1,7 +1,10 @@ {#if $activeBridge === BridgeTypes.FUNGIBLE} @@ -361,13 +461,65 @@ -
- - -
-
+
+ {#if activeStep === NFTSteps.IMPORT} +
+ +
+ + +
+ {#if detectedTokenType === TokenType.ERC721 && contractAddress} + + {:else if detectedTokenType === TokenType.ERC1155 && contractAddress} + + {/if} + + +
+ {#if !isOwnerOfAllToken && nftIdArray?.length > 0 && !validating} + + {/if} +
+
+ {:else if activeStep === NFTSteps.REVIEW} +
+
+

Contract: {contractAddress}

+

IDs: {nftIdArray.join(', ')}

+
+
+ {:else if activeStep === NFTSteps.CONFIRM} +
+ +
+ {/if} +
+
+ {#if activeStep !== NFTSteps.IMPORT} + + {/if} + +
+
{/if} diff --git a/packages/bridge-ui-v2/src/components/Bridge/IDInput.svelte b/packages/bridge-ui-v2/src/components/Bridge/IDInput.svelte new file mode 100644 index 0000000000..ecb121b781 --- /dev/null +++ b/packages/bridge-ui-v2/src/components/Bridge/IDInput.svelte @@ -0,0 +1,67 @@ + + +
+
+ +
+
+ + + +
+
diff --git a/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte b/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte index f406f92e1b..e4ea75a149 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte @@ -10,7 +10,7 @@ import { uid } from '$libs/util/uid'; import { account } from '$stores/account'; - import AddressInput from './AddressInput.svelte'; + import AddressInput from './AddressInput/AddressInput.svelte'; import { recipientAddress } from './state'; // Public API diff --git a/packages/bridge-ui-v2/src/components/ChainSelector/ChainSelectorWrapper.svelte b/packages/bridge-ui-v2/src/components/ChainSelector/ChainSelectorWrapper.svelte index 422c28de32..4f851492f0 100644 --- a/packages/bridge-ui-v2/src/components/ChainSelector/ChainSelectorWrapper.svelte +++ b/packages/bridge-ui-v2/src/components/ChainSelector/ChainSelectorWrapper.svelte @@ -10,6 +10,8 @@ import { chainIdToChain, chains } from '$libs/chain'; import { network } from '$stores/network'; + let destChainElement: ChainSelector; + function handleSourceChange(): void { updateDestOptions(); } @@ -62,6 +64,11 @@ - + diff --git a/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte b/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte index 7ff2946702..398027c474 100644 --- a/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte +++ b/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte @@ -7,7 +7,7 @@ import { formatUnits } from 'viem'; import { FlatAlert } from '$components/Alert'; - import AddressInput from '$components/Bridge/AddressInput.svelte'; + import AddressInput from '$components/Bridge/AddressInput/AddressInput.svelte'; import { Button } from '$components/Button'; import { Icon } from '$components/Icon'; import Erc20 from '$components/Icon/ERC20.svelte'; diff --git a/packages/bridge-ui-v2/src/i18n/en.json b/packages/bridge-ui-v2/src/i18n/en.json index 30a43e0760..407594b0f8 100644 --- a/packages/bridge-ui-v2/src/i18n/en.json +++ b/packages/bridge-ui-v2/src/i18n/en.json @@ -206,18 +206,23 @@ } }, "inputs": { - "nft": { - "token_id": { - "label": "Token ID(s)", - "placeholder": "1 or 5,14,733" + "token_id_input": { + "label": "Token ID(s)", + "placeholder": "1 or 5,14,733", + "errors": { + "invalid": "Not a valid numeric value" } }, "address_input": { - "label": "Address", - "placeholder": "Enter an address", + "label": { + "default": "Address", + "contract": "Contract address", + "recipient": "Recipient address" + }, + "placeholder": "Enter a valid ethereum address", "errors": { "invalid": "Invalid address format", - "too_short": "Address length is too short" + "too_short": "Address is too short" }, "success": "Valid address format" }, diff --git a/packages/bridge-ui-v2/src/libs/token/detectContractType.ts b/packages/bridge-ui-v2/src/libs/token/detectContractType.ts index c12e225a60..308426a7ab 100644 --- a/packages/bridge-ui-v2/src/libs/token/detectContractType.ts +++ b/packages/bridge-ui-v2/src/libs/token/detectContractType.ts @@ -1,65 +1,48 @@ import { readContract } from '@wagmi/core'; +import { ContractFunctionExecutionError, UnknownTypeError } from 'viem'; -export async function detectContractType(contractAddress: string, tokenId: number) { - // eslint-disable-next-line no-console - console.info('detectContractType', contractAddress); +import { erc721ABI, erc1155ABI } from '$abi'; +import { getLogger } from '$libs/util/logger'; - // Use abi from @wagmi/core, and get it setup in wagmi.config.ts - const ERC721_ABI = [ - { - constant: true, - inputs: [{ name: 'tokenId', type: 'uint256' }], - name: 'ownerOf', - outputs: [{ name: '', type: 'address' }], - payable: false, - stateMutability: 'view', - type: 'function', - }, - ]; +import { TokenType } from './types'; - const ERC1155_ABI = [ - { - constant: true, - inputs: [ - { name: 'owner', type: 'address' }, - { name: 'operator', type: 'address' }, - ], - name: 'isApprovedForAll', - outputs: [{ name: '', type: 'bool' }], - payable: false, - stateMutability: 'view', - type: 'function', - }, - ]; +const log = getLogger('detectContractType'); + +export async function detectContractType(contractAddress: string) { + log('detectContractType', { contractAddress }); try { await readContract({ address: contractAddress as `0x${string}`, // TODO: type Address - abi: ERC721_ABI, + abi: erc721ABI, functionName: 'ownerOf', - args: [tokenId], + args: [0n], }); - // TODO: please use getLogger from util/logger - // eslint-disable-next-line no-console - console.info('ERC721'); - return 'ERC721'; // TODO: use TokenType + log('is ERC721'); + return TokenType.ERC721; } catch (err) { - // eslint-disable-next-line no-console - console.log(err); + if (err instanceof ContractFunctionExecutionError) { + if (err.cause.message.includes('ERC721: invalid token ID')) { + // valid erc721 contract, but invalid token id + log('is ERC721'); + return TokenType.ERC721; + } + } + + log('is not ERC721', err); try { await readContract({ address: contractAddress as `0x${string}`, - abi: ERC1155_ABI, + abi: erc1155ABI, functionName: 'isApprovedForAll', args: ['0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000'], }); - // eslint-disable-next-line no-console - console.info('ERC1155'); - return 'ERC1155'; // TODO: use TokenType + log('is ERC1155'); + return TokenType.ERC1155; } catch (err) { // eslint-disable-next-line no-console console.log(err); - return 'UNKNOWN'; // TODO: throw UnknownTypeError and handle in the UI? + throw new UnknownTypeError({ type: 'Unknown tokentype' }); } } } From f9842455e162d33aab9603bc80c98c2f41f21daa Mon Sep 17 00:00:00 2001 From: Korbinian Date: Tue, 3 Oct 2023 00:15:24 +0200 Subject: [PATCH 2/8] detectContract update and test --- .../bridge-ui-v2/__mocks__/@wagmi/core.ts | 2 + .../src/libs/token/detectContractType.test.ts | 85 ++++++++++++++++++ .../src/libs/token/detectContractType.ts | 90 ++++++++++++------- 3 files changed, 147 insertions(+), 30 deletions(-) create mode 100644 packages/bridge-ui-v2/src/libs/token/detectContractType.test.ts diff --git a/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts b/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts index 88658482f1..234ad3cccd 100644 --- a/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts +++ b/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts @@ -10,6 +10,8 @@ export const getContract = vi.fn(); export const fetchBalance = vi.fn(); +export const readContract = vi.fn(); + export const configureChains = vi.fn(() => { return { publicClient: 'mockPublicClient' }; }); diff --git a/packages/bridge-ui-v2/src/libs/token/detectContractType.test.ts b/packages/bridge-ui-v2/src/libs/token/detectContractType.test.ts new file mode 100644 index 0000000000..8912b92418 --- /dev/null +++ b/packages/bridge-ui-v2/src/libs/token/detectContractType.test.ts @@ -0,0 +1,85 @@ +import { readContract } from '@wagmi/core'; +import { UnknownTypeError, zeroAddress } from 'viem'; + +import { detectContractType } from './detectContractType'; +import { TokenType } from './types'; + +vi.mock('@wagmi/core'); + +describe('detectContractType', () => { + it('should return ERC721 for a valid ERC721 contract', async () => { + // Given + const contractAddress = zeroAddress; + vi.mocked(readContract).mockImplementationOnce(() => Promise.resolve()); + + // When + const result = await detectContractType(contractAddress); + + // Then + expect(result).toBe(TokenType.ERC721); + }); + + it('should return ERC721 for a valid ERC721 contract with invalid Token ID', async () => { + // Given + const contractAddress = zeroAddress; + vi.mocked(readContract).mockImplementationOnce(() => Promise.reject(new Error('ERC721: invalid token ID'))); + + // When + const result = await detectContractType(contractAddress); + + // Then + expect(result).toBe(TokenType.ERC721); + }); + + it('should return ERC1155 for a valid ERC1155 contract', async () => { + // Given + const contractAddress = zeroAddress; + vi.mocked(readContract) + .mockImplementationOnce(() => Promise.reject()) + .mockImplementationOnce(() => Promise.resolve()); + + // When + const result = await detectContractType(contractAddress); + + // Then + expect(result).toBe(TokenType.ERC1155); + }); + + it('should return ERC20 for a valid ERC20 contract', async () => { + // Given + const contractAddress = zeroAddress; + vi.mocked(readContract) + .mockImplementationOnce(() => Promise.reject()) + .mockImplementationOnce(() => Promise.reject()) + .mockImplementationOnce(() => Promise.resolve()); + + // When + const result = await detectContractType(contractAddress); + + // Then + expect(result).toBe(TokenType.ERC20); + }); + + it('should throw an error for an unknown contract type', async () => { + // Given + const contractAddress = zeroAddress; + vi.mocked(readContract).mockImplementation(() => + Promise.reject(new UnknownTypeError({ type: 'Unknown tokentype' })), + ); + + // When & Then + await expect(detectContractType(contractAddress)).rejects.toThrow('Unknown tokentype'); + }); + + it('should throw an error for if none of the checks passed', async () => { + // Given + const contractAddress = '0x1234567890abcdef1234567890abcdef12345678'; + vi.mocked(readContract) + .mockImplementation(() => Promise.reject()) + .mockImplementation(() => Promise.reject()) + .mockImplementation(() => Promise.reject()); + + // When & Then + await expect(detectContractType(contractAddress)).rejects.toThrow('Unknown tokentype'); + }); +}); diff --git a/packages/bridge-ui-v2/src/libs/token/detectContractType.ts b/packages/bridge-ui-v2/src/libs/token/detectContractType.ts index 308426a7ab..690f1a35af 100644 --- a/packages/bridge-ui-v2/src/libs/token/detectContractType.ts +++ b/packages/bridge-ui-v2/src/libs/token/detectContractType.ts @@ -1,48 +1,78 @@ import { readContract } from '@wagmi/core'; -import { ContractFunctionExecutionError, UnknownTypeError } from 'viem'; +import { UnknownTypeError } from 'viem'; -import { erc721ABI, erc1155ABI } from '$abi'; +import { erc20ABI, erc721ABI, erc1155ABI } from '$abi'; import { getLogger } from '$libs/util/logger'; import { TokenType } from './types'; -const log = getLogger('detectContractType'); +type Address = `0x${string}`; -export async function detectContractType(contractAddress: string) { - log('detectContractType', { contractAddress }); +const log = getLogger('detectContractType'); +async function isERC721(address: Address): Promise { try { await readContract({ - address: contractAddress as `0x${string}`, // TODO: type Address + address, abi: erc721ABI, functionName: 'ownerOf', args: [0n], }); + return true; + } catch (err) { + // we expect this error to be thrown if the token is a ERC721 and the tokenId is invalid + return (err as Error)?.message?.includes('ERC721: invalid token ID') ?? false; + } +} +// return err instanceof ContractFunctionExecutionError && +// err.cause.message.includes('ERC721: invalid token ID'); +async function isERC1155(address: Address): Promise { + try { + await readContract({ + address, + abi: erc1155ABI, + functionName: 'isApprovedForAll', + args: ['0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000'], + }); + return true; + } catch { + return false; + } +} + +async function isERC20(address: Address): Promise { + try { + await readContract({ + address, + abi: erc20ABI, + functionName: 'balanceOf', + args: ['0x0000000000000000000000000000000000000000'], + }); + return true; + } catch { + return false; + } +} + +export async function detectContractType(contractAddress: Address): Promise { + log('detectContractType', { contractAddress }); + + if (await isERC721(contractAddress)) { log('is ERC721'); return TokenType.ERC721; - } catch (err) { - if (err instanceof ContractFunctionExecutionError) { - if (err.cause.message.includes('ERC721: invalid token ID')) { - // valid erc721 contract, but invalid token id - log('is ERC721'); - return TokenType.ERC721; - } - } - - log('is not ERC721', err); - try { - await readContract({ - address: contractAddress as `0x${string}`, - abi: erc1155ABI, - functionName: 'isApprovedForAll', - args: ['0x0000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000'], - }); - log('is ERC1155'); - return TokenType.ERC1155; - } catch (err) { - // eslint-disable-next-line no-console - console.log(err); - throw new UnknownTypeError({ type: 'Unknown tokentype' }); - } } + + if (await isERC1155(contractAddress)) { + log('is ERC1155'); + return TokenType.ERC1155; + } + + if (await isERC20(contractAddress)) { + log('is ERC20'); + return TokenType.ERC20; + } + + log('Unknown token type'); + console.error('Unable to determine token type'); + throw new UnknownTypeError({ type: 'Unknown tokentype' }); } From d83bc54023a3afb1f914969fe584aa01f7284067 Mon Sep 17 00:00:00 2001 From: Korbinian Date: Tue, 3 Oct 2023 00:52:00 +0200 Subject: [PATCH 3/8] tokenInfo --- .../TokenDropdown/AddCustomERC20.svelte | 4 +- .../src/libs/token/getTokenInfo.ts | 41 +++++++++++++++++++ packages/bridge-ui-v2/src/libs/token/types.ts | 3 +- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts diff --git a/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte b/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte index 398027c474..6532ccab49 100644 --- a/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte +++ b/packages/bridge-ui-v2/src/components/TokenDropdown/AddCustomERC20.svelte @@ -13,7 +13,7 @@ import Erc20 from '$components/Icon/ERC20.svelte'; import { Spinner } from '$components/Spinner'; import { tokenService } from '$libs/storage/services'; - import { type GetCrossChainAddressArgs, type Token, type TokenEnv, TokenType } from '$libs/token'; + import { type GetCrossChainAddressArgs, type Token, type TokenDetails, TokenType } from '$libs/token'; import { getCrossChainAddress } from '$libs/token/getCrossChainAddress'; import { getLogger } from '$libs/util/logger'; import { uid } from '$libs/util/uid'; @@ -30,7 +30,7 @@ export let loading = false; export let loadingTokenDetails = false; - let tokenDetails: (TokenEnv & { balance: bigint; decimals: number }) | null; + let tokenDetails: TokenDetails | null; let tokenError = ''; let tokenAddress: Address | string = ''; let customTokens: Token[] = []; diff --git a/packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts b/packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts new file mode 100644 index 0000000000..385a63a82e --- /dev/null +++ b/packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts @@ -0,0 +1,41 @@ +import { erc721ABI, fetchToken, readContract } from '@wagmi/core'; +import type { Address } from 'viem'; + +import { detectContractType } from './detectContractType'; +import { type TokenDetails, TokenType } from './types'; + +export const getTokenInfoFromAddress = async (address: Address) => { + const tokenType = await detectContractType(address); + const details: TokenDetails = {} as TokenDetails; + if (tokenType === TokenType.ERC20) { + const token = await fetchToken({ + address, + }); + details.address = address; + details.name = token.name; + details.symbol = token.symbol; + details.decimals = token.decimals; + return details; + } else if (tokenType === TokenType.ERC1155) { + // todo: via URI? + return details; + } else if (tokenType === TokenType.ERC721) { + const name = await readContract({ + address, + abi: erc721ABI, + functionName: 'name', + }); + + const symbol = await readContract({ + address, + abi: erc721ABI, + functionName: 'symbol', + }); + details.address = address; + details.name = name; + details.symbol = symbol; + details.decimals = 0; + return details; + } + return null; +}; diff --git a/packages/bridge-ui-v2/src/libs/token/types.ts b/packages/bridge-ui-v2/src/libs/token/types.ts index 8b281d41cd..426b4ded39 100644 --- a/packages/bridge-ui-v2/src/libs/token/types.ts +++ b/packages/bridge-ui-v2/src/libs/token/types.ts @@ -24,11 +24,12 @@ export type Token = { mintable?: boolean; }; -export type TokenEnv = { +export type TokenDetails = { name: string; address: Address; symbol: string; balance: bigint; + decimals: number; }; export type GetCrossChainAddressArgs = { From 3f60b879295c15755a06651abdb6ae5d77d56e15 Mon Sep 17 00:00:00 2001 From: Korbinian Date: Wed, 4 Oct 2023 14:35:57 +0200 Subject: [PATCH 4/8] check ownership --- .../bridge-ui-v2/__mocks__/@wagmi/core.ts | 2 + .../src/components/Bridge/Bridge.svelte | 57 +++-------- .../src/components/Bridge/BridgeTabs.svelte | 4 +- .../TokenDropdown/AddCustomERC20.svelte | 5 +- .../bridge-ui-v2/src/libs/error/errors.ts | 4 + .../src/libs/token/checkOwnership.test.ts | 94 +++++++++++++++++++ .../src/libs/token/checkOwnership.ts | 70 ++++++++++++++ 7 files changed, 190 insertions(+), 46 deletions(-) create mode 100644 packages/bridge-ui-v2/src/libs/token/checkOwnership.test.ts create mode 100644 packages/bridge-ui-v2/src/libs/token/checkOwnership.ts diff --git a/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts b/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts index 234ad3cccd..0700d6c0cd 100644 --- a/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts +++ b/packages/bridge-ui-v2/__mocks__/@wagmi/core.ts @@ -10,6 +10,8 @@ export const getContract = vi.fn(); export const fetchBalance = vi.fn(); +export const fetchToken = vi.fn(); + export const readContract = vi.fn(); export const configureChains = vi.fn(() => { diff --git a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte index 4d240bce9d..527fde9931 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte @@ -1,10 +1,8 @@
@@ -72,7 +77,7 @@ class="w-full input-box withValdiation py-6 pr-16 px-[26px] title-subsection-bold placeholder:text-tertiary-content {$$props.class} {state === State.Valid ? 'success' : ethereumAddress && state !== State.Validating ? 'error' : ''} " /> -
diff --git a/packages/bridge-ui-v2/src/components/Bridge/Amount.svelte b/packages/bridge-ui-v2/src/components/Bridge/Amount.svelte index 355321307f..b979f82a4c 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/Amount.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/Amount.svelte @@ -43,7 +43,7 @@ // Public API export function clearAmount() { - inputBox.clear(); + inputBox?.clear(); $enteredAmount = BigInt(0); } diff --git a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte index 527fde9931..44b1be9f37 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/Bridge.svelte @@ -1,5 +1,5 @@
@@ -60,7 +51,7 @@ on:input={validateInput} class="w-full input-box withValdiation py-6 pr-16 px-[26px] title-subsection-bold placeholder:text-tertiary-content {$$props.class}" /> -
diff --git a/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte b/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte index e4ea75a149..83e186b6f7 100644 --- a/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte +++ b/packages/bridge-ui-v2/src/components/Bridge/Recipient.svelte @@ -15,7 +15,7 @@ // Public API export const clearRecipient = () => { - addressInput.clear(); // update UI + addressInput.clearAddress(); // update UI $recipientAddress = null; // update state }; diff --git a/packages/bridge-ui-v2/src/libs/token/getTokenInfo.test.ts b/packages/bridge-ui-v2/src/libs/token/getTokenInfo.test.ts index 07f78fddb7..1773555188 100644 --- a/packages/bridge-ui-v2/src/libs/token/getTokenInfo.test.ts +++ b/packages/bridge-ui-v2/src/libs/token/getTokenInfo.test.ts @@ -1,4 +1,4 @@ -import { fetchToken, type FetchTokenResult } from '@wagmi/core'; +import { fetchToken, type FetchTokenResult, readContract } from '@wagmi/core'; import { type Address, zeroAddress } from 'viem'; import { UnknownTokenTypeError } from '$libs/error'; @@ -49,10 +49,28 @@ describe('getTokenInfoFromAddress', () => { name: 'MockToken', symbol: 'MTK', decimals: 18, + type: TokenType.ERC20, }); }); - // ...repeat similar structure for ERC1155 and ERC721 token types + it('should return correct token details for ERC721 tokens', async () => { + // Given + const address: Address = zeroAddress; + vi.mocked(detectContractType).mockResolvedValue(TokenType.ERC721); + vi.mocked(readContract).mockResolvedValueOnce('MockNFT').mockResolvedValueOnce('MNFT'); + + // When + const result = await getTokenInfoFromAddress(address); + + // Then + expect(result).toEqual({ + address, + name: 'MockNFT', + symbol: 'MNFT', + decimals: 0, + type: TokenType.ERC721, + }); + }); it('should return null for unknown token types', async () => { // Given diff --git a/packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts b/packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts index 4452e99e0d..c0e2ede1ac 100644 --- a/packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts +++ b/packages/bridge-ui-v2/src/libs/token/getTokenInfo.ts @@ -34,6 +34,7 @@ export const getTokenInfoFromAddress = async (address: Address) => { abi: erc721ABI, functionName: 'symbol', }); + details.type = tokenType; details.address = address; details.name = name;