diff --git a/examples/blockchain-data/api-examples-with-node/get-token.ts b/examples/blockchain-data/api-examples-with-node/get-token.ts new file mode 100644 index 0000000000..9bd48153f3 --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/get-token.ts @@ -0,0 +1,12 @@ +import { blockchainData } from '@imtbl/sdk'; + +import { client } from '../lib'; + +export async function getToken( + contractAddress: string, +): Promise { + return await client.getToken({ + chainName: 'imtbl-zkevm-testnet', + contractAddress, + }); +} diff --git a/examples/blockchain-data/api-examples-with-node/index.ts b/examples/blockchain-data/api-examples-with-node/index.ts index ee9f13e523..4b0bda28fd 100644 --- a/examples/blockchain-data/api-examples-with-node/index.ts +++ b/examples/blockchain-data/api-examples-with-node/index.ts @@ -1,15 +1,24 @@ -import { verifySuccessfulMints } from "./verify-successful-mints"; -import { getChains } from "./exported-types"; -import { getCollection } from "./get-collection"; -import { getMetadata } from "./get-metadata"; -import { getNFT } from "./get-nft"; -import { listMetadata } from "./list-metadata"; -import { listCollections } from "./list-collections"; -import { listCollectionsByNFTOwner } from "./list-collections-by-owner"; -import { listActivities } from "./list-activities"; -import { listNFTsByAccountAddress } from "./list-nfts-by-account-address"; -import { refreshNFTMetadata } from "./refresh-nft-metadata"; -import { refreshStackedMetadata } from "./refresh-stacked-metadata"; +import { verifySuccessfulMints } from './verify-successful-mints'; +import { getChains } from './exported-types'; +import { getCollection } from './get-collection'; +import { getMetadata } from './get-metadata'; +import { getNFT } from './get-nft'; +import { getToken } from './get-token'; +import { listAllNFTs } from './list-nfts'; +import { listAllNFTOwners } from './list-all-nft-owners'; +import { listChains } from './list-chains'; +import { listMetadata } from './list-metadata'; +import { listCollections } from './list-collections'; +import { listCollectionsByNFTOwner } from './list-collections-by-owner'; +import { listActivities } from './list-activities'; +import { listActivitiesByActivityType } from './list-activties-by-activity-type'; +import { listNFTsByAccountAddress } from './list-nfts-by-account-address'; +import { listNFTsByCollection } from './list-nfts-by-collection'; +import { listNFTOwnersByContractAddress } from './list-nft-owners-by-contract-address'; +import { listNFTOwnersByTokenId } from './list-nft-owners-by-token-id'; +import { listTokens } from './list-tokens'; +import { refreshNFTMetadata } from './refresh-nft-metadata'; +import { refreshStackedMetadata } from './refresh-stacked-metadata'; export { verifySuccessfulMints, @@ -17,11 +26,20 @@ export { getCollection, getMetadata, getNFT, + getToken, + listAllNFTs, + listAllNFTOwners, + listChains, listMetadata, listCollections, listCollectionsByNFTOwner, listActivities, + listActivitiesByActivityType, listNFTsByAccountAddress, + listNFTsByCollection, + listNFTOwnersByContractAddress, + listNFTOwnersByTokenId, + listTokens, refreshNFTMetadata, refreshStackedMetadata, }; diff --git a/examples/blockchain-data/api-examples-with-node/list-activties-by-activity-type.ts b/examples/blockchain-data/api-examples-with-node/list-activties-by-activity-type.ts new file mode 100644 index 0000000000..f2a6f80641 --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-activties-by-activity-type.ts @@ -0,0 +1,13 @@ +import { blockchainData } from '@imtbl/sdk'; +import { client } from '../lib'; + +export async function listActivitiesByActivityType( + contractAddress: string, + activityType: blockchainData.Types.ActivityType, +): Promise { + return await client.listActivities({ + chainName: 'imtbl-zkevm-testnet', + contractAddress, + activityType, + }); +} diff --git a/examples/blockchain-data/api-examples-with-node/list-all-nft-owners.ts b/examples/blockchain-data/api-examples-with-node/list-all-nft-owners.ts new file mode 100644 index 0000000000..f29ea77300 --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-all-nft-owners.ts @@ -0,0 +1,8 @@ +import { blockchainData } from '@imtbl/sdk'; +import { client } from '../lib'; + +export async function listAllNFTOwners(): Promise { + return await client.listAllNFTOwners({ + chainName: 'imtbl-zkevm-testnet', + }); +} diff --git a/examples/blockchain-data/api-examples-with-node/list-chains.ts b/examples/blockchain-data/api-examples-with-node/list-chains.ts new file mode 100644 index 0000000000..a340d148ab --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-chains.ts @@ -0,0 +1,9 @@ +import { blockchainData } from '@imtbl/sdk'; + +import { client } from '../lib'; + +export async function listChains( + request: blockchainData.Types.ListChainsRequestParams, +): Promise { + return await client.listChains(request); +} diff --git a/examples/blockchain-data/api-examples-with-node/list-nft-owners-by-contract-address.ts b/examples/blockchain-data/api-examples-with-node/list-nft-owners-by-contract-address.ts new file mode 100644 index 0000000000..aaa59213e3 --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-nft-owners-by-contract-address.ts @@ -0,0 +1,11 @@ +import { blockchainData } from '@imtbl/sdk'; +import { client } from '../lib'; + +export async function listNFTOwnersByContractAddress( + contractAddress: string, +): Promise { + return await client.listNFTOwnersByContractAddress({ + chainName: 'imtbl-zkevm-testnet', + contractAddress, + }); +} diff --git a/examples/blockchain-data/api-examples-with-node/list-nft-owners-by-token-id.ts b/examples/blockchain-data/api-examples-with-node/list-nft-owners-by-token-id.ts new file mode 100644 index 0000000000..5e68fb2bff --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-nft-owners-by-token-id.ts @@ -0,0 +1,13 @@ +import { blockchainData } from '@imtbl/sdk'; +import { client } from '../lib'; + +export async function listNFTOwnersByTokenId( + contractAddress: string, + tokenId: string, +): Promise { + return await client.listNFTOwners({ + chainName: 'imtbl-zkevm-testnet', + contractAddress, + tokenId, + }); +} diff --git a/examples/blockchain-data/api-examples-with-node/list-nfts-by-collection.ts b/examples/blockchain-data/api-examples-with-node/list-nfts-by-collection.ts new file mode 100644 index 0000000000..0dc3e59d26 --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-nfts-by-collection.ts @@ -0,0 +1,13 @@ +import { blockchainData } from '@imtbl/sdk'; +import { client } from '../lib'; + +export async function listNFTsByCollection( + contractAddress: string, + tokenId: string[], +): Promise { + return await client.listNFTs({ + chainName: 'imtbl-zkevm-testnet', + contractAddress, + tokenId, + }); +} diff --git a/examples/blockchain-data/api-examples-with-node/list-nfts.ts b/examples/blockchain-data/api-examples-with-node/list-nfts.ts new file mode 100644 index 0000000000..f048d4c7e2 --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-nfts.ts @@ -0,0 +1,8 @@ +import { blockchainData } from '@imtbl/sdk'; +import { client } from '../lib'; + +export async function listAllNFTs(): Promise { + return await client.listAllNFTs({ + chainName: 'imtbl-zkevm-testnet', + }); +} diff --git a/examples/blockchain-data/api-examples-with-node/list-tokens.ts b/examples/blockchain-data/api-examples-with-node/list-tokens.ts new file mode 100644 index 0000000000..13299e919f --- /dev/null +++ b/examples/blockchain-data/api-examples-with-node/list-tokens.ts @@ -0,0 +1,9 @@ +import { blockchainData } from '@imtbl/sdk'; + +import { client } from '../lib'; + +export async function listTokens(): Promise { + return await client.listTokens({ + chainName: 'imtbl-zkevm-testnet', + }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/create-erc1155-mint-request-with-metadata.ts b/examples/blockchain-data/minting-api-examples-with-node/create-erc1155-mint-request-with-metadata.ts new file mode 100644 index 0000000000..812dc95e5e --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/create-erc1155-mint-request-with-metadata.ts @@ -0,0 +1,52 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function createMintRequestWithTokenIdAndMetadataAndAmount( + chainName: string, + contractAddress: string, + owner_address: string, + reference_id: string, + token_id: string, + amount: string +): Promise { + return await client.createMintRequest({ + chainName, + contractAddress, + createMintRequestRequest: { + assets: [ + { + owner_address, + reference_id, + token_id, + amount, + metadata: { + name: "Brown Dog Red Car", + description: "This SFT is a Brown Dog in a Red Car", + image: "https://mt-test-2.s3.ap-southeast-2.amazonaws.com/BDRC.png", + external_url: null, + animation_url: null, + youtube_url: null, + attributes: [ + { + trait_type: "Pet", + value: "Dog", + }, + { + trait_type: "Pet Colour", + value: "Brown", + }, + { + trait_type: "Vehicle", + value: "Car", + }, + { + trait_type: "Vehicle Colour", + value: "Red", + }, + ], + }, + }, + ], + }, + }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/create-erc1155-mint-request.ts b/examples/blockchain-data/minting-api-examples-with-node/create-erc1155-mint-request.ts new file mode 100644 index 0000000000..78333e3965 --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/create-erc1155-mint-request.ts @@ -0,0 +1,26 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function createMintRequestWithTokenIdAndMetadataAndAmount( + chainName: string, + contractAddress: string, + owner_address: string, + reference_id: string, + token_id: string, + amount: string +): Promise { + return await client.createMintRequest({ + chainName, + contractAddress, + createMintRequestRequest: { + assets: [ + { + owner_address, + reference_id, + token_id, + amount, + }, + ], + }, + }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-quantity-request-with-metadata.ts b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-quantity-request-with-metadata.ts new file mode 100644 index 0000000000..7835e1044d --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-quantity-request-with-metadata.ts @@ -0,0 +1,78 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function createMintRequestWithMetadata( + chainName: string, + contractAddress: string, + owner_address: string, + reference_id: string +): Promise { + return await client.createMintRequest({ + chainName, + contractAddress, + createMintRequestRequest: { + assets: [ + { + owner_address, + reference_id, + metadata: { + name: "Brown Dog Green Car", + description: "This NFT is a Brown Dog in a Green Car", + image: "https://mt-test-2.s3.ap-southeast-2.amazonaws.com/BDGC.png", + external_url: null, + animation_url: null, + youtube_url: null, + attributes: [ + { + trait_type: "Pet", + value: "Dog", + }, + { + trait_type: "Pet Colour", + value: "Brown", + }, + { + trait_type: "Vehicle", + value: "Car", + }, + { + trait_type: "Vehicle Colour", + value: "Green", + }, + ], + }, + }, + { + owner_address, + reference_id, + metadata: { + name: "Brown Dog Red Car", + description: "This NFT is a Brown Dog in a Red Car", + image: "https://mt-test-2.s3.ap-southeast-2.amazonaws.com/BDRC.png", + external_url: null, + animation_url: null, + youtube_url: null, + attributes: [ + { + trait_type: "Pet", + value: "Dog", + }, + { + trait_type: "Pet Colour", + value: "Brown", + }, + { + trait_type: "Vehicle", + value: "Car", + }, + { + trait_type: "Vehicle Colour", + value: "Red", + }, + ], + }, + }, + ], + }, + }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-quantity-request.ts b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-quantity-request.ts new file mode 100644 index 0000000000..4ffef08ec5 --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-quantity-request.ts @@ -0,0 +1,22 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function createMintRequest( + chainName: string, + contractAddress: string, + owner_address: string, + reference_id: string +): Promise { + return await client.createMintRequest({ + chainName, + contractAddress, + createMintRequestRequest: { + assets: [ + { + owner_address, + reference_id, + }, + ], + }, + }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-request-with-metadata.ts b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-request-with-metadata.ts new file mode 100644 index 0000000000..86367a56d8 --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-request-with-metadata.ts @@ -0,0 +1,81 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function createMintRequestWithTokenIdAndMetadata( + chainName: string, + contractAddress: string, + owner_address: string, + reference_id: string, + token_id: string +): Promise { + return await client.createMintRequest({ + chainName, + contractAddress, + createMintRequestRequest: { + assets: [ + { + owner_address, + reference_id, + token_id, + metadata: { + name: "Brown Dog Green Car", + description: "This NFT is a Brown Dog in a Green Car", + image: "https://mt-test-2.s3.ap-southeast-2.amazonaws.com/BDGC.png", + external_url: null, + animation_url: null, + youtube_url: null, + attributes: [ + { + trait_type: "Pet", + value: "Dog", + }, + { + trait_type: "Pet Colour", + value: "Brown", + }, + { + trait_type: "Vehicle", + value: "Car", + }, + { + trait_type: "Vehicle Colour", + value: "Green", + }, + ], + }, + }, + { + owner_address, + reference_id, + token_id, + metadata: { + name: "Brown Dog Red Car", + description: "This NFT is a Brown Dog in a Red Car", + image: "https://mt-test-2.s3.ap-southeast-2.amazonaws.com/BDRC.png", + external_url: null, + animation_url: null, + youtube_url: null, + attributes: [ + { + trait_type: "Pet", + value: "Dog", + }, + { + trait_type: "Pet Colour", + value: "Brown", + }, + { + trait_type: "Vehicle", + value: "Car", + }, + { + trait_type: "Vehicle Colour", + value: "Red", + }, + ], + }, + }, + ], + }, + }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-request.ts b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-request.ts new file mode 100644 index 0000000000..831a06761d --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/create-erc721-mint-request.ts @@ -0,0 +1,24 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function createMintRequestWithTokenId( + chainName: string, + contractAddress: string, + owner_address: string, + reference_id: string, + token_id: string +): Promise { + return await client.createMintRequest({ + chainName, + contractAddress, + createMintRequestRequest: { + assets: [ + { + owner_address, + reference_id, + token_id, + }, + ], + }, + }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/get-mint-request.ts b/examples/blockchain-data/minting-api-examples-with-node/get-mint-request.ts new file mode 100644 index 0000000000..4f72559d53 --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/get-mint-request.ts @@ -0,0 +1,10 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function getMintRequest( + chainName: string, + contractAddress: string, + referenceId: string +): Promise { + return await client.getMintRequest({ chainName, contractAddress, referenceId }); +} diff --git a/examples/blockchain-data/minting-api-examples-with-node/list-mint-requests.ts b/examples/blockchain-data/minting-api-examples-with-node/list-mint-requests.ts new file mode 100644 index 0000000000..41e9248237 --- /dev/null +++ b/examples/blockchain-data/minting-api-examples-with-node/list-mint-requests.ts @@ -0,0 +1,9 @@ +import { blockchainData } from "@imtbl/sdk"; +import { client } from "../lib"; + +export async function listMintRequests( + chainName: string, + contractAddress: string, +): Promise { + return await client.listMintRequests({ chainName, contractAddress }); +} diff --git a/examples/blockchain-data/test/blockchain-data.test.ts b/examples/blockchain-data/test/blockchain-data.test.ts index 75975ad50f..639338e902 100644 --- a/examples/blockchain-data/test/blockchain-data.test.ts +++ b/examples/blockchain-data/test/blockchain-data.test.ts @@ -1,4 +1,5 @@ import { describe, expect, test } from '@jest/globals'; +import { blockchainData } from '@imtbl/sdk'; import { verifySuccessfulMints, @@ -6,16 +7,35 @@ import { getCollection, getMetadata, getNFT, + getToken, + listAllNFTs, + listAllNFTOwners, + listChains, listMetadata, listCollections, listCollectionsByNFTOwner, listActivities, + listActivitiesByActivityType, listNFTsByAccountAddress, + listNFTsByCollection, + listNFTOwnersByTokenId, + listNFTOwnersByContractAddress, + listTokens, } from '../api-examples-with-node'; const CHAIN_NAME = 'imtbl-zkevm-testnet'; const CONTRACT_ADDRESS = '0x21F0D60cfE554B6d5b7f9E799BDeBD97C5d64274'; const NFT_OWNER = '0x9C1634bebC88653D2Aebf4c14a3031f62092b1D9'; +const TOKEN_ADDRESS = '0x007a4bdf308ca0074d7b95628e72a62f12b2c58f'; + +describe('Chains', () => { + describe('listChains', () => { + test('returns a list of chains', async () => { + const result = await listChains({}); + expect(result.result.length).toBeGreaterThan(0); + }); + }); +}); describe('Activities', () => { describe('listActivities', () => { @@ -25,6 +45,18 @@ describe('Activities', () => { }); }); + describe('listActivities', () => { + test('listing activities by activity type returns activities of that type', async () => { + const result = await listActivitiesByActivityType( + CONTRACT_ADDRESS, + blockchainData.Types.ActivityType.Mint, + ); + expect(result.result[0].type).toBe( + blockchainData.Types.ActivityType.Mint, + ); + }); + }); + describe('verifySuccessfulMints', () => { test('listing activities from a contract address returns mint activities', async () => { const result = await verifySuccessfulMints(CONTRACT_ADDRESS); @@ -76,6 +108,13 @@ describe('Metadata', () => { }); describe('NFTs', () => { + describe('listAllNFTs', () => { + test('returns a list of NFTs', async () => { + const result = await listAllNFTs(); + expect(result.result.length).toBeGreaterThan(0); + }); + }); + describe('listNFTsByAccountAddress', () => { test('returns a list of NFTs', async () => { const result = await listNFTsByAccountAddress( @@ -87,12 +126,66 @@ describe('NFTs', () => { }); }); + describe('listNFTsByCollection', () => { + test('returns a list of NFTs', async () => { + const result = await listNFTsByCollection( + '0xd9cfd0a6d1496a4da6e8ad570344e1482ce3c257', + ['1', '2'], + ); + expect(result.result.length).toBeGreaterThan(0); + }); + }); + test('returns nft', async () => { const result = await getNFT(CHAIN_NAME, CONTRACT_ADDRESS, '199144'); expect(result.result).not.toBe(null); }); }); +describe('NFT Owners', () => { + describe('listAllNFTOwners', () => { + test('returns a list of NFT Owners', async () => { + const result = await listAllNFTOwners(); + expect(result.result.length).toBeGreaterThan(0); + }); + }); + + describe('listNFTOwnersByContractAddress', () => { + test('returns a list of NFT Owners', async () => { + const result = await listNFTOwnersByContractAddress( + '0xd9cfd0a6d1496a4da6e8ad570344e1482ce3c257', + ); + expect(result.result.length).toBeGreaterThan(0); + }); + }); + + describe('listNFTOwnersByTokenId', () => { + test('returns a list of NFT Owners', async () => { + const result = await listNFTOwnersByTokenId( + '0xd9cfd0a6d1496a4da6e8ad570344e1482ce3c257', + '1', + ); + expect(result.result.length).toBeGreaterThan(0); + }); + }); +}); + +describe('Tokens', () => { + describe('listTokens', () => { + test('returns a list of tokens', async () => { + const result = await listTokens(); + expect(result.result.length).toBeGreaterThan(0); + }); + }); + + describe('getToken', () => { + test('returns a token', async () => { + const result = await getToken(TOKEN_ADDRESS); + expect(result).not.toBe(null); + }); + }); +}); + describe('Setup', () => { describe('getChains', () => { test('returns a chain', async () => { diff --git a/examples/minting/README.md b/examples/minting/README.md deleted file mode 100644 index b5f8f3ea0b..0000000000 --- a/examples/minting/README.md +++ /dev/null @@ -1 +0,0 @@ -# Coming Soon™ \ No newline at end of file diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx b/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx index 770accaf9a..6d1c226a42 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/AddFundsWidget.tsx @@ -90,10 +90,14 @@ export default function AddFundsWidget({ chainIds, evmAddress: fromAddress, }); + const filteredBalances = balances?.evmBalances?.filter( + (balance) => balance.balance !== '0', + ); + addFundsDispatch({ payload: { type: AddFundsActions.SET_BALANCES, - balances: balances?.evmBalances ?? [], + balances: filteredBalances ?? [], }, }); })(); @@ -140,7 +144,6 @@ export default function AddFundsWidget({ {viewState.view.type === AddFundsWidgetViews.ADD_FUNDS && ( new Promise((resolve) => { + setTimeout(resolve, ms); +}); diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useExecute.ts b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useExecute.ts new file mode 100644 index 0000000000..ed3fd387a0 --- /dev/null +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useExecute.ts @@ -0,0 +1,51 @@ +import { Web3Provider } from '@ethersproject/providers'; +import { RouteResponse } from '@0xsquid/squid-types'; +import { Squid } from '@0xsquid/sdk'; +import { TransactionResponses } from '@0xsquid/sdk/dist/types'; + +export const useExecute = async () => { + const checkProviderChain = async (provider: Web3Provider, chainId: string) => { + if (!provider.provider.request) { + throw Error('provider does not have request method'); + } + + const fromChainHex = `0x${parseInt(chainId, 10).toString(16)}`; + const providerChainId = await provider.provider.request({ + method: 'eth_chainId', + }); + + if (fromChainHex !== providerChainId) { + await provider.provider.request({ + method: 'wallet_switchEthereumChain', + params: [ + { + chainId: fromChainHex, + }, + ], + }); + } + }; + + const approve = async (squid: Squid, provider: Web3Provider, routeResponse: RouteResponse): Promise => { + await checkProviderChain(provider, routeResponse.route.params.fromChain); + return squid.approveRoute({ + signer: provider.getSigner(), + route: routeResponse.route, + }); + }; + + const execute = async ( + squid: Squid, + provider: Web3Provider, + routeResponse: RouteResponse, + ): Promise => { + await checkProviderChain(provider, routeResponse.route.params.fromChain); + return squid.executeRoute({ + signer: provider.getSigner(), + route: routeResponse.route, + }); + }; + return { + approve, execute, + }; +}; diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts index a896337ec9..d6a46116de 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/hooks/useRoutes.ts @@ -1,73 +1,98 @@ -/* eslint-disable no-console */ import { TokenBalance } from '@0xsquid/sdk/dist/types'; import { RouteResponse, Token } from '@0xsquid/squid-types'; import { Squid } from '@0xsquid/sdk'; import { utils } from 'ethers'; import { useState } from 'react'; - -const delay = (ms: number) => new Promise((resolve) => { - setTimeout(resolve, ms); -}); - -export type AmountData = { - fromAmount: string; - fromToken: Token; - toToken: Token; - toAmount: string; - balance: TokenBalance; -}; - -export type RouteData = { - amountData: AmountData; - route: RouteResponse; -}; +import { delay } from '../functions/delay'; +import { AmountData, RouteData } from '../types'; export const useRoutes = () => { const [routes, setRoutes] = useState([]); - const getFromAmounts = ( + const getFromAmount = async ( + squid: Squid, + balance: TokenBalance, + toAmount: string, + toChainId: string, + toTokenAddress: string, + ): Promise => { + const fromTokenData = squid?.getTokenData( + balance.address, + balance.chainId.toString(), + ); + const toTokenData = squid?.getTokenData(toTokenAddress, toChainId); + + if (!fromTokenData || !toTokenData) { + return undefined; + } + + try { + const fromAmount = await squid.getFromAmount({ + fromToken: fromTokenData, + toToken: toTokenData, + toAmount, + }); + + return { + fromAmount, + fromToken: fromTokenData, + toToken: toTokenData, + toAmount, + balance, + }; + } catch (error) { + return undefined; + } + }; + + const getSufficientFromAmounts = async ( squid: Squid, balances: TokenBalance[], - toChanId: string, + toChainId: string, toTokenAddress: string, toAmount: string, - ): Promise[] => { + bulkNumber: number, + delayMs: number, + ): Promise => { const filteredBalances = balances.filter( - (balance) => balance.address !== toTokenAddress, + (balance) => !(balance.address === toTokenAddress && balance.chainId === toChainId), ); - return filteredBalances.map( - (balance: TokenBalance): Promise => { - const fromTokenData = squid?.getTokenData( - balance.address, - balance.chainId.toString(), - ); - const toTokenData = squid?.getTokenData(toTokenAddress, toChanId); - - if (!fromTokenData || !toTokenData) { - console.log('tokenData not found', fromTokenData, toTokenData); - return Promise.resolve(undefined); - } - - return squid - .getFromAmount({ - fromToken: fromTokenData, - toToken: toTokenData, - toAmount, - }) - .then((fromAmount: string) => ({ - fromAmount, - fromToken: fromTokenData, - toToken: toTokenData, - toAmount, - balance, - })) - .catch((error) => { - console.log('error', error); - return Promise.resolve(undefined); - }); + const result :AmountData[] = []; + + for (let i = 0; i < filteredBalances.length; i += bulkNumber) { + const promises = filteredBalances.slice(i, i + bulkNumber).map( + (balance) => getFromAmount( + squid, + balance, + toAmount, + toChainId, + toTokenAddress, + ), + ); + + // eslint-disable-next-line no-await-in-loop + const amountsData = await Promise.all(promises); + + const filteredAmountsData = amountsData.filter( + (amountData): amountData is AmountData => amountData !== undefined, + ); + + if (filteredAmountsData.length > 0) { + result.push(...filteredAmountsData); + } + + // eslint-disable-next-line no-await-in-loop + await delay(delayMs); + } + + const filteredAmountData = result.filter( + (data: AmountData) => { + const formattedBalance = utils.formatUnits(data.balance.balance, data.balance.decimals); + return parseFloat(formattedBalance.toString()) > parseFloat(data.fromAmount); }, ); + return filteredAmountData; }; const getRoute = async ( @@ -77,66 +102,93 @@ export const useRoutes = () => { toAmount: string, toAddress: string, quoteOnly = true, - ): Promise => { - const fromAmount = await squid.getFromAmount({ - fromToken, - toToken, - toAmount, - }); + ): Promise => { + try { + const fromAmount = await squid.getFromAmount({ + fromToken, + toToken, + toAmount, + }); + + const parsedFromAmount = parseFloat(fromAmount).toFixed(fromToken.decimals); + const formattedFromAmount = utils.parseUnits( + parsedFromAmount, + fromToken.decimals, + ); + + const route = await squid.getRoute({ + fromChain: fromToken.chainId, + fromToken: fromToken.address, + fromAmount: formattedFromAmount.toString(), + toChain: toToken.chainId, + toToken: toToken.address, + toAddress, + quoteOnly, + enableBoost: true, + }); + + return route; + } catch (error) { + return undefined; + } + }; - const parsedFromAmount = parseFloat(fromAmount).toFixed(fromToken.decimals); - const formattedFromAmount = utils.parseUnits( - parsedFromAmount, - fromToken.decimals, + const getRoutes = async ( + squid: Squid, + amountDataArray: AmountData[], + toTokenAddress: string, + ): Promise => { + const routePromises = amountDataArray.map( + (data) => getRoute( + squid, + data.fromToken, + data.toToken, + data.toAmount, + toTokenAddress, + ).then((route) => ({ + amountData: data, + route, + })), ); - return squid.getRoute({ - fromChain: fromToken.chainId, - fromToken: fromToken.address, - fromAmount: formattedFromAmount.toString(), - toChain: toToken.chainId, - toToken: toToken.address, - toAddress, - quoteOnly, - enableBoost: true, - }); + const routesData = await Promise.all(routePromises); + return routesData.filter((route): route is RouteData => route !== undefined); }; - const getRoutes = async ( + const fetchRoutesWithRateLimit = async ( squid: Squid, balances: TokenBalance[], toChanId: string, toTokenAddress: string, toAmount: string, - ) => { - const getAmountData = await Promise.all( - getFromAmounts(squid, balances, toChanId, toTokenAddress, toAmount), + bulkNumber = 5, + delayMs = 1000, + ):Promise => { + const amountDataArray = await getSufficientFromAmounts( + squid, + balances, + toChanId, + toTokenAddress, + toAmount, + 10, + 1000, ); - const filteredAmountData = getAmountData.filter( - (amountData) => amountData !== undefined, - ) as AmountData[]; - delay(2000); + const allRoutes: RouteData[] = []; - const getRoutePromises = filteredAmountData.map((data: AmountData): Promise => getRoute( - squid, - data.fromToken, - data.toToken, - data.toAmount, - toTokenAddress, - ).then((route) => ({ - amountData: data, - route, - })).catch((error) => { - console.log('error', error); - return Promise.resolve(undefined); - })); - - const getRouteData = await Promise.all(getRoutePromises); - const routesData = getRouteData.filter((routeData) => routeData !== undefined) as RouteData[]; - setRoutes(routesData); - return routesData; + for (let i = 0; i < amountDataArray.length; i += bulkNumber) { + const slicedAmountDataArray = amountDataArray.slice(i, i + bulkNumber); + + // eslint-disable-next-line no-await-in-loop + allRoutes.push(...await getRoutes(squid, slicedAmountDataArray, toTokenAddress)); + + // eslint-disable-next-line no-await-in-loop + await delay(delayMs); + } + + setRoutes(allRoutes); + return allRoutes; }; - return { routes, getRoutes, getRoute }; + return { routes, fetchRoutesWithRateLimit }; }; diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts b/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts index 895810afe3..ce5c8bad7b 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/types.ts @@ -1,6 +1,22 @@ +import { TokenBalance } from '@0xsquid/sdk/dist/types'; +import { RouteResponse, Token } from '@0xsquid/squid-types'; + export type Chain = { id: string; type: string; name: string; iconUrl: string; }; + +export type AmountData = { + fromToken: Token; + fromAmount: string; + toToken: Token; + toAmount: string; + balance: TokenBalance; +}; + +export type RouteData = { + amountData: AmountData; + route: RouteResponse; +}; diff --git a/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx b/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx index 34f0f27322..6d0c1e7f93 100644 --- a/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx +++ b/packages/checkout/widgets-lib/src/widgets/add-funds/views/AddFunds.tsx @@ -1,5 +1,3 @@ -/* eslint-disable no-console */ -import { Web3Provider } from '@ethersproject/providers'; import { Checkout, IMTBLWidgetEvents, @@ -30,7 +28,6 @@ import { interface AddFundsProps { checkout?: Checkout; - provider?: Web3Provider; showBackButton?: boolean; showOnrampOption?: boolean; showSwapOption?: boolean; @@ -43,7 +40,6 @@ interface AddFundsProps { export function AddFunds({ checkout, - provider, toAmount, toTokenAddress, showBackButton = false, @@ -53,11 +49,6 @@ export function AddFunds({ onBackButtonClick, onCloseButtonClick, }: AddFundsProps) { - console.log('provider', provider); - console.log('showOnrampOption', showOnrampOption); - console.log('showSwapOption', showSwapOption); - console.log('showBridgeOption', showBridgeOption); - const showBack = showBackButton || !!onBackButtonClick; const { addFundsDispatch } = useContext(AddFundsContext); @@ -174,10 +165,6 @@ export function AddFunds({ // }; const onPayWithCard = (paymentType: OptionTypes) => { - console.log('paymentType', paymentType); - console.log('=== toTokenAddress', currentToTokenAddress); - console.log('=== toAmount', toAmount); - if (paymentType === OptionTypes.SWAP) { orchestrationEvents.sendRequestSwapEvent( eventTarget,