Skip to content

Commit

Permalink
asdf
Browse files Browse the repository at this point in the history
  • Loading branch information
andrearampin committed Oct 30, 2023
1 parent abc4a2d commit f5eeaa8
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 72 deletions.
5 changes: 4 additions & 1 deletion packages/checkout/sdk/src/balances/balances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,11 @@ export const getAllBalances = async (
config: CheckoutConfiguration,
web3Provider: Web3Provider,
walletAddress: string,
chainId: ChainId,
chainId?: ChainId,
): Promise<GetAllBalancesResult> => {
// eslint-disable-next-line no-param-reassign
chainId ||= await web3Provider.getSigner().getChainId();

const { tokens } = await getTokenAllowList(
config,
{
Expand Down
104 changes: 57 additions & 47 deletions packages/checkout/sdk/src/smartCheckout/balanceCheck/balanceCheck.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable arrow-body-style */
import { Web3Provider } from '@ethersproject/providers';
import { BigNumber, Contract } from 'ethers';
import {
Expand All @@ -13,7 +12,7 @@ import {
NativeItem,
ERC20Item,
} from '../../types';
import { getBalances } from '../../balances';
import { getAllBalances } from '../../balances';
import { CheckoutConfiguration } from '../../config';
import {
BalanceCheckResult,
Expand All @@ -36,22 +35,21 @@ const getTokenBalances = async (
ownerAddress: string,
itemRequirements: ItemRequirement[],
) : Promise<ItemBalance[]> => {
let tokenBalances: TokenBalance[] = [];

try {
const tokenList: TokenInfo[] = getTokensFromRequirements(itemRequirements);
const { balances } = await getBalances(config, provider, ownerAddress, tokenList);
tokenBalances = [
...balances.map((balance) => balance as TokenBalance),
];
const tokenMap = new Map<string, TokenInfo>();
getTokensFromRequirements(itemRequirements).forEach(
(item) => tokenMap.set((item.address || '').toLocaleLowerCase(), item),
);
const { balances } = await getAllBalances(config, provider, ownerAddress);
return balances.filter(
(balance) => tokenMap.get((balance.token.address || '').toLocaleLowerCase()),
) as TokenBalance[];
} catch (error: any) {
throw new CheckoutError(
'Failed to get balances',
CheckoutErrorType.GET_BALANCE_ERROR,
);
}

return tokenBalances;
};

/**
Expand Down Expand Up @@ -118,59 +116,71 @@ export const balanceCheck = async (
itemRequirements: ItemRequirement[],
) : Promise<BalanceCheckResult> => {
const aggregatedItems = balanceAggregator(itemRequirements);
if (aggregatedItems.filter((itemRequirement) => {
return itemRequirement.type !== ItemType.ERC721
&& itemRequirement.type !== ItemType.ERC20
&& itemRequirement.type !== ItemType.NATIVE;
}).length > 0) {

const requiredToken: ItemRequirement[] = [];
const requiredERC721: ItemRequirement[] = [];

aggregatedItems.forEach((item) => {
switch (item.type) {
case ItemType.ERC20:
case ItemType.NATIVE:
requiredToken.push(item);
break;
case ItemType.ERC721:
requiredERC721.push(item);
break;
default:
}
});

if (requiredERC721.length === 0 && requiredToken.length === 0) {
throw new CheckoutError(
'Unsupported item requirement balance check',
CheckoutErrorType.UNSUPPORTED_BALANCE_REQUIREMENT_ERROR,
);
}

// Get all ERC20 and NATIVE balances
const currentBalances: Promise<ItemBalance[]>[] = [];
const tokenItemRequirements: ItemRequirement[] = aggregatedItems
.filter((itemRequirement) => itemRequirement.type === ItemType.ERC20 || itemRequirement.type === ItemType.NATIVE);
if (tokenItemRequirements.length > 0) {
currentBalances.push(getTokenBalances(config, provider, ownerAddress, aggregatedItems));
const balancePromises: Promise<ItemBalance[]>[] = [];
if (requiredToken.length > 0) {
balancePromises.push(getTokenBalances(config, provider, ownerAddress, aggregatedItems));
}

// Get all ERC721 balances
const erc721ItemRequirements: ItemRequirement[] = aggregatedItems
.filter((itemRequirement) => itemRequirement.type === ItemType.ERC721);
if (erc721ItemRequirements.length > 0) {
currentBalances.push(getERC721Balances(provider, ownerAddress, aggregatedItems));
if (requiredERC721.length > 0) {
balancePromises.push(getERC721Balances(provider, ownerAddress, aggregatedItems));
}

// Wait for all balances and calculate the requirements
const balanceRequirements: BalanceRequirement[] = await Promise.all(currentBalances).then((balances) => {
const requirements: BalanceRequirement[] = [];
if (balances.length > 1 || tokenItemRequirements.length > 0) {
const tokenBalances = balances[0];
tokenItemRequirements.forEach((tokenItemRequirement) => {
requirements.push(getTokenBalanceRequirement(tokenItemRequirement as (NativeItem | ERC20Item), tokenBalances));
const promisesResponses = await Promise.all(balancePromises);

const balanceRequirements: BalanceRequirement[] = [];

// Get all ERC20 and NATIVE balances
if (requiredToken.length > 0 && promisesResponses.length > 0) {
const result = promisesResponses.pop();
if (result) {
requiredToken.forEach((item) => {
balanceRequirements.push(getTokenBalanceRequirement(item as (NativeItem | ERC20Item), result));
});
if (erc721ItemRequirements.length > 0) {
const erc721Balances = balances[1];
erc721ItemRequirements.forEach((erc721ItemRequirement) => {
requirements.push(getERC721BalanceRequirement(erc721ItemRequirement as ERC721Item, erc721Balances));
});
}
} else if (erc721ItemRequirements.length > 0) {
// Only erc721
const erc721Balances = balances[0];
erc721ItemRequirements.forEach((erc721ItemRequirement) => {
requirements.push(getERC721BalanceRequirement(erc721ItemRequirement as ERC721Item, erc721Balances));
}
}

// Get all ERC721 balances
if (requiredERC721.length > 0 && promisesResponses.length > 0) {
const result = promisesResponses.pop();
if (result) {
requiredERC721.forEach((item) => {
balanceRequirements.push(getERC721BalanceRequirement(item as (ERC721Item), result));
});
}
return requirements;
});
}

// Find if there are any requirements that aren't sufficient.
// If there is not item with sufficient === false then the requirements
// are satisfied.
const sufficient = balanceRequirements.find((req) => req.sufficient === false) === undefined;

const sufficient = balanceRequirements.reduce((acc, balanceRequirement) => {
return acc && balanceRequirement.sufficient;
}, true);
return {
sufficient,
balanceRequirements,
Expand Down
56 changes: 32 additions & 24 deletions packages/checkout/sdk/src/smartCheckout/buy/buy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import {
FulfillOrderResponse,
OrderStatusName,
} from '@imtbl/orderbook';
import { GetTokenResult } from '@imtbl/generated-clients/dist/multi-rollup';
import * as instance from '../../instance';
import { CheckoutConfiguration } from '../../config';
import { CheckoutConfiguration, getL1ChainId, getL2ChainId } from '../../config';
import { CheckoutError, CheckoutErrorType } from '../../errors';
import {
ItemType,
Expand All @@ -35,9 +36,9 @@ import {
signFulfillmentTransactions,
} from '../actions';
import { SignTransactionStatusType } from '../actions/types';
import { ERC20ABI } from '../../types';
import { calculateFees } from '../fees/fees';
import { debugLogger, measureAsyncExecution } from '../../utils/debugLogger';
import { getAllBalances } from '../../balances';

export const getItemRequirement = (
type: ItemType,
Expand Down Expand Up @@ -87,28 +88,43 @@ export const buy = async (
provider: Web3Provider,
orders: Array<BuyOrder>,
): Promise<BuyResult> => {
let orderbook;
let order: ListingResult;
let spenderAddress = '';
const gasLimit = constants.estimatedFulfillmentGasGwei;

if (orders.length === 0) {
throw new CheckoutError(
'No orders were provided to the orders array. Please provide at least one order.',
CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR,
);
}

let order: ListingResult;
let spenderAddress = '';
let decimals = 18;

const gasLimit = constants.estimatedFulfillmentGasGwei;
const orderbook = instance.createOrderbookInstance(config);
const blockchainClient = instance.createBlockchainDataInstance(config);

const fulfillerAddress = await measureAsyncExecution<string>(
config,
'Time to get the address from the provider',
provider.getSigner().getAddress(),
);

// Prefetch balances and store them in memory
getAllBalances(config, provider, fulfillerAddress, getL1ChainId(config));
getAllBalances(config, provider, fulfillerAddress, getL2ChainId(config));

const { id, takerFees } = orders[0];

let orderChainName: string;
try {
orderbook = instance.createOrderbookInstance(config);
order = await measureAsyncExecution<ListingResult>(
config,
'Time to fetch the listing from the orderbook',
orderbook.getListing(id),
);
const { seaportContractAddress } = orderbook.config();
const { seaportContractAddress, chainName } = orderbook.config();

orderChainName = chainName;
spenderAddress = seaportContractAddress;
} catch (err: any) {
throw new CheckoutError(
Expand All @@ -131,20 +147,16 @@ export const buy = async (
},
);
}
const buyToken = order.result.buy[0];
let decimals = 18;
if (order.result.buy[0].type === 'ERC20') {
const tokenContract = instance.getTokenContract(
order.result.buy[0].contractAddress,
ERC20ABI,
provider,
);

decimals = await measureAsyncExecution<number>(
const buyToken = order.result.buy[0];
if (buyToken.type === 'ERC20') {
const token = await measureAsyncExecution<GetTokenResult>(
config,
'Time to get decimals of token contract for the buy token',
tokenContract.decimals(),
blockchainClient.getToken({ contractAddress: buyToken.contractAddress, chainName: orderChainName }),
);

if (token.result.decimals) decimals = token.result.decimals;
}

let fees: FeeValue[] = [];
Expand All @@ -158,16 +170,12 @@ export const buy = async (

const fulfillOrderStartTime = performance.now();
try {
const fulfillerAddress = await measureAsyncExecution<string>(
config,
'Time to get the address from the provider',
provider.getSigner().getAddress(),
);
const { actions } = await measureAsyncExecution<FulfillOrderResponse>(
config,
'Time to call fulfillOrder from the orderbook',
orderbook.fulfillOrder(id, fulfillerAddress, fees),
);

orderActions = actions;
unsignedApprovalTransactions = await measureAsyncExecution<TransactionRequest[]>(
config,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { ChainId, IMX_ADDRESS_ZKEVM, ImxAddressConfig } from '../../../types';
export const INDEXER_ETH_ROOT_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000000001';

export const getIndexerChainName = (chainId: ChainId): string => {
if (chainId === ChainId.IMTBL_ZKEVM_MAINNET) return 'imtbl-zkevm-mainnet';
if (chainId === ChainId.IMTBL_ZKEVM_TESTNET) return 'imtbl-zkevm-testnet';
if (chainId === ChainId.IMTBL_ZKEVM_DEVNET) return 'imtbl-zkevm-devent';
return '';
};

Expand Down
1 change: 1 addition & 0 deletions packages/checkout/sdk/src/smartCheckout/smartCheckout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const smartCheckout = async (
transactionOrGasAmount: FulfillmentTransaction | GasAmount,
): Promise<SmartCheckoutResult> => {
const ownerAddress = await provider.getSigner().getAddress();

let aggregatedItems = itemAggregator(itemRequirements);

const erc20AllowancePromise = hasERC20Allowances(provider, ownerAddress, aggregatedItems);
Expand Down

0 comments on commit f5eeaa8

Please sign in to comment.