Skip to content

Commit

Permalink
replace ethereum-multicall with ethers-multicall-provider for more co…
Browse files Browse the repository at this point in the history
…nsistent interface, less complexity, better batch handling for super large query sets, etc
  • Loading branch information
chuckbergeron committed Jul 13, 2023
1 parent ccbd894 commit 48e295f
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 166 deletions.
7 changes: 2 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,5 @@
"prettier": "2.7.1",
"typescript": "4.8.4"
},
"packageManager": "[email protected]",
"dependencies": {
"@generationsoftware/pt-v5-utils-js": "file:.yalc/@generationsoftware/pt-v5-utils-js"
}
}
"packageManager": "[email protected]"
}
2 changes: 1 addition & 1 deletion packages/arb-liquidator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"dependencies": {
"defender-relay-client": "1.39.0",
"ethereum-multicall": "^2.17.0",
"ethers-multicall-provider": "^3.0.5",
"figlet": "^1.6.0",
"tsdx": "^0.14.1"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/arb-liquidator/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default defineConfig((opt) => {
'inquirer',
'@generationsoftware/pt-v5-autotasks-library',
'@generationsoftware/pt-v5-utils-js',
'ethereum-multicall',
'ethers-multicall-provider',
'configstore',
],
format: 'cjs',
Expand Down
2 changes: 1 addition & 1 deletion packages/draw-reserve/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default defineConfig((opt) => {
'inquirer',
'@generationsoftware/pt-v5-autotasks-library',
'@generationsoftware/pt-v5-utils-js',
'ethereum-multicall',
'ethers-multicall-provider',
'configstore',
],
format: 'cjs',
Expand Down
197 changes: 68 additions & 129 deletions packages/library/src/utils/arbLiquidatorMulticall.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { Contract, BigNumber } from 'ethers';
import { Provider } from '@ethersproject/providers';
import { ContractCallContext } from 'ethereum-multicall';
import { ContractsBlob, getComplexMulticallResults } from '@generationsoftware/pt-v5-utils-js';
import {
ContractsBlob,
getEthersMulticallProviderResults,
} from '@generationsoftware/pt-v5-utils-js';

import { ArbLiquidatorContext, Token, TokenWithRate } from '../types';
import { parseBigNumberAsFloat, MARKET_RATE_CONTRACT_DECIMALS } from '../utils';
import { ERC20Abi } from '../abis/ERC20Abi';

import { ethers } from 'ethers';

import ethersMulticallProviderPkg from 'ethers-multicall-provider';
const { MulticallWrapper } = ethersMulticallProviderPkg;

/**
* Gather information about this specific liquidation pair
* `tokenIn` is the token to supply (likely the prize token, which is probably POOL),
Expand All @@ -27,183 +34,115 @@ export const arbLiquidatorMulticall = async (
readProvider: Provider,
relayerAddress: string,
): Promise<ArbLiquidatorContext> => {
const tokenInCalls: ContractCallContext['calls'] = [];
// @ts-ignore Provider == BaseProvider
const multicallProvider = MulticallWrapper.wrap(readProvider);

let queries: Record<string, any> = {};

// 1. IN TOKEN
const tokenInAddress = await liquidationPair.tokenIn();
const tokenInContract = new ethers.Contract(tokenInAddress, ERC20Abi, multicallProvider);

tokenInCalls.push({
reference: `decimals`,
methodName: 'decimals',
methodParameters: [],
});
tokenInCalls.push({
reference: `name`,
methodName: 'name',
methodParameters: [],
});
tokenInCalls.push({
reference: `symbol`,
methodName: 'symbol',
methodParameters: [],
});

const tokenOutCalls: ContractCallContext['calls'] = [];
queries[`tokenIn-decimals`] = tokenInContract.decimals();
queries[`tokenIn-name`] = tokenInContract.name();
queries[`tokenIn-symbol`] = tokenInContract.symbol();

// 2. OUT TOKEN
const tokenOutAddress = await liquidationPair.tokenOut();
const tokenOutContract = new ethers.Contract(tokenOutAddress, ERC20Abi, multicallProvider);

tokenOutCalls.push({
reference: `decimals`,
methodName: 'decimals',
methodParameters: [],
});
tokenOutCalls.push({
reference: `name`,
methodName: 'name',
methodParameters: [],
});
tokenOutCalls.push({
reference: `symbol`,
methodName: 'symbol',
methodParameters: [],
});
queries[`tokenOut-decimals`] = tokenOutContract.decimals();
queries[`tokenOut-name`] = tokenOutContract.name();
queries[`tokenOut-symbol`] = tokenOutContract.symbol();

// // 3. VAULT UNDERLYING ASSET TOKEN
const vaultUnderlyingAssetCalls: ContractCallContext['calls'] = [];

const vaultContract = contracts.contracts.find(
(contract) => contract.type === 'Vault' && contract.address === tokenOutAddress,
);
const vaultUnderlyingAsset = vaultContract.tokens[0].extensions.underlyingAsset;
const vaultUnderlyingAssetAddress = vaultUnderlyingAsset.address;

vaultUnderlyingAssetCalls.push({
reference: `decimals`,
methodName: 'decimals',
methodParameters: [],
});
vaultUnderlyingAssetCalls.push({
reference: `name`,
methodName: 'name',
methodParameters: [],
});
vaultUnderlyingAssetCalls.push({
reference: `symbol`,
methodName: 'symbol',
methodParameters: [],
});

// // 4. RELAYER tokenIn BALANCE
tokenInCalls.push({
reference: `balanceOf`,
methodName: 'balanceOf',
methodParameters: [relayerAddress],
});

// // 5. RELAYER tokenIn ALLOWANCE for spender LiquidationRouter
tokenInCalls.push({
reference: `allowance`,
methodName: 'allowance',
methodParameters: [relayerAddress, liquidationRouter.address],
});
const vaultUnderlyingAssetContract = new ethers.Contract(
vaultUnderlyingAssetAddress,
ERC20Abi,
multicallProvider,
);

queries[`vaultUnderlyingAsset-decimals`] = vaultUnderlyingAssetContract.decimals();
queries[`vaultUnderlyingAsset-name`] = vaultUnderlyingAssetContract.name();
queries[`vaultUnderlyingAsset-symbol`] = vaultUnderlyingAssetContract.symbol();

// 4. RELAYER tokenIn BALANCE
queries[`tokenIn-balanceOf`] = tokenInContract.balanceOf(relayerAddress);
queries[`tokenIn-allowance`] = tokenInContract.allowance(
relayerAddress,
liquidationRouter.address,
);

// 5. RELAYER tokenIn ALLOWANCE for spender LiquidationRouter

// 6. MarketRate Calls
const marketRateCalls: ContractCallContext['calls'] = [];

// // // prize token/pool
const marketRateContractBlob = contracts.contracts.find(
(contract) => contract.type === 'MarketRate',
);
const marketRateAddress = marketRate.address;
marketRateCalls.push({
reference: `priceFeed-${tokenInAddress}`,
methodName: 'priceFeed',
methodParameters: [tokenInAddress, 'USD'],
});

// // yield token/vault underlying asset rate
marketRateCalls.push({
reference: `priceFeed-${vaultUnderlyingAssetAddress}`,
methodName: 'priceFeed',
methodParameters: [vaultUnderlyingAssetAddress, 'USD'],
});

const queries: ContractCallContext[] = [
{
reference: tokenInAddress,
contractAddress: tokenInAddress,
abi: ERC20Abi,
calls: tokenInCalls,
},
{
reference: tokenOutAddress,
contractAddress: tokenOutAddress,
abi: ERC20Abi,
calls: tokenOutCalls,
},
{
reference: vaultUnderlyingAssetAddress,
contractAddress: vaultUnderlyingAssetAddress,
abi: ERC20Abi,
calls: vaultUnderlyingAssetCalls,
},
{
reference: marketRateAddress,
contractAddress: marketRateAddress,
abi: marketRateContractBlob.abi,
calls: marketRateCalls,
},
];

// Get and process results!
const multicallResults = await getComplexMulticallResults(readProvider, queries);

const marketRateMulticallResults = multicallResults[marketRateAddress];
const tokenInPriceFeedResults = marketRateMulticallResults[`priceFeed-${tokenInAddress}`][0];
const marketRateContract = new ethers.Contract(
marketRateAddress,
marketRateContractBlob.abi,
multicallProvider,
);

queries[`priceFeed-${tokenInAddress}`] = marketRateContract.priceFeed(tokenInAddress, 'USD');
queries[`priceFeed-${vaultUnderlyingAssetAddress}`] = marketRateContract.priceFeed(
vaultUnderlyingAssetAddress,
'USD',
);

// 7. Get and process results!
const results = await getEthersMulticallProviderResults(multicallProvider, queries);

// const marketRateMulticallResults = results[marketRateAddress];
const tokenInPriceFeedResults = results[`priceFeed-${tokenInAddress}`];

// 1. tokenIn results
const tokenInMulticallResults = multicallResults[tokenInAddress];
const tokenInAssetRateUsd = parseBigNumberAsFloat(
BigNumber.from(tokenInPriceFeedResults),
MARKET_RATE_CONTRACT_DECIMALS,
);
const tokenIn: TokenWithRate = {
address: tokenInAddress,
decimals: tokenInMulticallResults.decimals[0],
name: tokenInMulticallResults.name[0],
symbol: tokenInMulticallResults.symbol[0],
decimals: results['tokenIn-decimals'],
name: results['tokenIn-name'],
symbol: results['tokenIn-symbol'],
assetRateUsd: tokenInAssetRateUsd,
};

// 2. tokenOut results (vault token)
const tokenOutMulticallResults = multicallResults[tokenOutAddress];
const tokenOut: Token = {
address: tokenOutAddress,
decimals: tokenOutMulticallResults.decimals[0],
name: tokenOutMulticallResults.name[0],
symbol: tokenOutMulticallResults.symbol[0],
decimals: results['tokenOut-decimals'],
name: results['tokenOut-name'],
symbol: results['tokenOut-symbol'],
};

// 3. vault underlying asset (hard asset such as DAI or USDC) results
const vaultUnderlyingAssetMulticallResults = multicallResults[vaultUnderlyingAssetAddress];
const vaultUnderlyingAssetPriceFeedResults =
marketRateMulticallResults[`priceFeed-${vaultUnderlyingAssetAddress}`][0];
const vaultUnderlyingAssetPriceFeedResults = results[`priceFeed-${vaultUnderlyingAssetAddress}`];
const vaultUnderlyingAssetAssetRateUsd = parseBigNumberAsFloat(
BigNumber.from(vaultUnderlyingAssetPriceFeedResults),
MARKET_RATE_CONTRACT_DECIMALS,
);
const vaultUnderlyingAssetUnderlyingAsset: TokenWithRate = {
address: vaultUnderlyingAsset.address,
decimals: vaultUnderlyingAssetMulticallResults.decimals[0],
name: vaultUnderlyingAssetMulticallResults.name[0],
symbol: vaultUnderlyingAssetMulticallResults.symbol[0],
decimals: results['vaultUnderlyingAsset-decimals'],
name: results['vaultUnderlyingAsset-name'],
symbol: results['vaultUnderlyingAsset-symbol'],
assetRateUsd: vaultUnderlyingAssetAssetRateUsd,
};

const relayer = {
tokenInBalance: BigNumber.from(tokenInMulticallResults.balanceOf[0]),
tokenInAllowance: BigNumber.from(tokenInMulticallResults.allowance[0]),
tokenInBalance: BigNumber.from(results['tokenIn-balanceOf']),
tokenInAllowance: BigNumber.from(results['tokenIn-allowance']),
};

return {
Expand Down
1 change: 0 additions & 1 deletion packages/prize-claimer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"dependencies": {
"configstore": "^6.0.0",
"defender-relay-client": "1.39.0",
"ethereum-multicall": "^2.16.1",
"figlet": "^1.6.0",
"graphql-request": "^5.2.0",
"lodash.groupby": "^4.6.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/prize-claimer/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default defineConfig((opt) => {
'inquirer',
'@generationsoftware/pt-v5-autotasks-library',
'@generationsoftware/pt-v5-utils-js',
'ethereum-multicall',
'ethers-multicall-provider',
'configstore',
'lodash.groupby',
],
Expand Down
2 changes: 1 addition & 1 deletion packages/testnet-complete-draw/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default defineConfig((opt) => {
noExternal: [
'@generationsoftware/pt-v5-autotasks-library',
'@generationsoftware/pt-v5-utils-js',
'ethereum-multicall',
'ethers-multicall-provider',
'configstore',
],
format: 'cjs',
Expand Down
2 changes: 1 addition & 1 deletion packages/withdraw-claim-rewards/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default defineConfig((opt) => {
'inquirer',
'@generationsoftware/pt-v5-autotasks-library',
'@generationsoftware/pt-v5-utils-js',
'ethereum-multicall',
'ethers-multicall-provider',
'configstore',
],
format: 'cjs',
Expand Down
2 changes: 1 addition & 1 deletion packages/yieldvault-mintrate/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default defineConfig((opt) => {
noExternal: [
'@generationsoftware/pt-v5-autotasks-library',
'@generationsoftware/pt-v5-utils-js',
'ethereum-multicall',
'ethers-multicall-provider',
'configstore',
],
format: 'cjs',
Expand Down
Loading

0 comments on commit 48e295f

Please sign in to comment.