From a8fe795189ccfe30a9d73694568e889e9e83da90 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Thu, 9 May 2024 17:50:26 +0200 Subject: [PATCH] FeeCurrencyDirectory support --- .../cli/src/commands/network/whitelist.ts | 10 ++- packages/sdk/contractkit/package.json | 2 +- packages/sdk/contractkit/src/base.ts | 1 + .../sdk/contractkit/src/contract-cache.ts | 6 ++ .../contractkit/src/web3-contract-cache.ts | 2 + .../wrappers/AbstractFeeCurrencyWrapper.ts | 70 ++++++++++++++++++ .../wrappers/FeeCurrencyDirectoryWrapper.ts | 21 ++++++ .../wrappers/FeeCurrencyWhitelistWrapper.ts | 71 ++----------------- 8 files changed, 115 insertions(+), 68 deletions(-) create mode 100644 packages/sdk/contractkit/src/wrappers/AbstractFeeCurrencyWrapper.ts create mode 100644 packages/sdk/contractkit/src/wrappers/FeeCurrencyDirectoryWrapper.ts diff --git a/packages/cli/src/commands/network/whitelist.ts b/packages/cli/src/commands/network/whitelist.ts index 6aa1349d5..2abd014c6 100644 --- a/packages/cli/src/commands/network/whitelist.ts +++ b/packages/cli/src/commands/network/whitelist.ts @@ -1,3 +1,4 @@ +import { isCel2 } from '@celo/connect' import { BaseCommand } from '../../base' export default class Whitelist extends BaseCommand { @@ -14,9 +15,12 @@ export default class Whitelist extends BaseCommand { async run() { const kit = await this.getKit() - const feeCurrencyWhitelist = await kit.contracts.getFeeCurrencyWhitelist() - const validFeeCurrencies = await feeCurrencyWhitelist.getWhitelist() - const pairs = (await feeCurrencyWhitelist.getFeeCurrencyInformation(validFeeCurrencies)).map( + const feeCurrencyContract = await ((await isCel2(kit.web3)) + ? kit.contracts.getFeeCurrencyDirectory() + : kit.contracts.getFeeCurrencyWhitelist()) + const validFeeCurrencies = await feeCurrencyContract.getAddresses() + + const pairs = (await feeCurrencyContract.getFeeCurrencyInformation(validFeeCurrencies)).map( ({ name, symbol, address, adaptedToken }) => `${address} - ${name || 'unknown name'} (${symbol || 'N/A'})${ adaptedToken ? ` (adapted token: ${adaptedToken})` : '' diff --git a/packages/sdk/contractkit/package.json b/packages/sdk/contractkit/package.json index 8c7f35b89..0fda7b321 100644 --- a/packages/sdk/contractkit/package.json +++ b/packages/sdk/contractkit/package.json @@ -24,7 +24,7 @@ "lint": "yarn run --top-level eslint -c .eslintrc.js " }, "dependencies": { - "@celo/abis": "11.0.0", + "@celo/abis": "11.0.0-fee-currency-directory.0", "@celo/base": "^6.0.1", "@celo/connect": "^5.3.0", "@celo/utils": "^6.0.1", diff --git a/packages/sdk/contractkit/src/base.ts b/packages/sdk/contractkit/src/base.ts index 3ae198f82..6c4986a7a 100644 --- a/packages/sdk/contractkit/src/base.ts +++ b/packages/sdk/contractkit/src/base.ts @@ -9,6 +9,7 @@ export enum CeloContract { ERC20 = 'ERC20', Escrow = 'Escrow', FederatedAttestations = 'FederatedAttestations', + FeeCurrencyDirectory = 'FeeCurrencyDirectory', FeeCurrencyWhitelist = 'FeeCurrencyWhitelist', FeeHandler = 'FeeHandler', Freezer = 'Freezer', diff --git a/packages/sdk/contractkit/src/contract-cache.ts b/packages/sdk/contractkit/src/contract-cache.ts index e2daadfb9..926ed987a 100644 --- a/packages/sdk/contractkit/src/contract-cache.ts +++ b/packages/sdk/contractkit/src/contract-cache.ts @@ -15,6 +15,7 @@ import { EpochRewardsWrapper } from './wrappers/EpochRewards' import { Erc20Wrapper } from './wrappers/Erc20Wrapper' import { EscrowWrapper } from './wrappers/Escrow' import { FederatedAttestationsWrapper } from './wrappers/FederatedAttestations' +import { FeeCurrencyDirectoryWrapper } from './wrappers/FeeCurrencyDirectoryWrapper' import { FeeCurrencyWhitelistWrapper } from './wrappers/FeeCurrencyWhitelistWrapper' import { FreezerWrapper } from './wrappers/Freezer' import { GasPriceMinimumWrapper } from './wrappers/GasPriceMinimum' @@ -35,6 +36,7 @@ const WrapperFactories = { [CeloContract.ERC20]: Erc20Wrapper, [CeloContract.Escrow]: EscrowWrapper, [CeloContract.FederatedAttestations]: FederatedAttestationsWrapper, + [CeloContract.FeeCurrencyDirectory]: FeeCurrencyDirectoryWrapper, [CeloContract.FeeCurrencyWhitelist]: FeeCurrencyWhitelistWrapper, [CeloContract.Freezer]: FreezerWrapper, [CeloContract.GasPriceMinimum]: GasPriceMinimumWrapper, @@ -84,6 +86,7 @@ interface WrapperCacheMap { [CeloContract.ERC20]?: Erc20Wrapper [CeloContract.Escrow]?: EscrowWrapper [CeloContract.FederatedAttestations]?: FederatedAttestationsWrapper + [CeloContract.FeeCurrencyDirectory]?: FeeCurrencyDirectoryWrapper [CeloContract.FeeCurrencyWhitelist]?: FeeCurrencyWhitelistWrapper [CeloContract.Freezer]?: FreezerWrapper [CeloContract.GasPriceMinimum]?: GasPriceMinimumWrapper @@ -155,6 +158,9 @@ export class WrapperCache implements ContractCacheType { getFederatedAttestations() { return this.getContract(CeloContract.FederatedAttestations) } + getFeeCurrencyDirectory() { + return this.getContract(CeloContract.FeeCurrencyDirectory) + } getFeeCurrencyWhitelist() { return this.getContract(CeloContract.FeeCurrencyWhitelist) } diff --git a/packages/sdk/contractkit/src/web3-contract-cache.ts b/packages/sdk/contractkit/src/web3-contract-cache.ts index da802f0b9..1a9c05d2c 100644 --- a/packages/sdk/contractkit/src/web3-contract-cache.ts +++ b/packages/sdk/contractkit/src/web3-contract-cache.ts @@ -30,6 +30,7 @@ import { newValidators } from '@celo/abis/web3/Validators' import { newReserve } from '@celo/abis/web3/mento/Reserve' import { newStableToken } from '@celo/abis/web3/mento/StableToken' +import { newFeeCurrencyDirectory } from '@celo/abis/web3/FeeCurrencyDirectory' import { newMentoFeeHandlerSeller } from '@celo/abis/web3/MentoFeeHandlerSeller' import { newUniswapFeeHandlerSeller } from '@celo/abis/web3/UniswapFeeHandlerSeller' @@ -46,6 +47,7 @@ export const ContractFactories = { [CeloContract.ERC20]: newIERC20, [CeloContract.Escrow]: newEscrow, [CeloContract.FederatedAttestations]: newFederatedAttestations, + [CeloContract.FeeCurrencyDirectory]: newFeeCurrencyDirectory, [CeloContract.FeeCurrencyWhitelist]: newFeeCurrencyWhitelist, [CeloContract.Freezer]: newFreezer, [CeloContract.FeeHandler]: newFeeHandler, diff --git a/packages/sdk/contractkit/src/wrappers/AbstractFeeCurrencyWrapper.ts b/packages/sdk/contractkit/src/wrappers/AbstractFeeCurrencyWrapper.ts new file mode 100644 index 000000000..cf3c028ba --- /dev/null +++ b/packages/sdk/contractkit/src/wrappers/AbstractFeeCurrencyWrapper.ts @@ -0,0 +1,70 @@ +import { StrongAddress } from '@celo/base' +import { Contract } from '@celo/connect' +import { BaseWrapper } from './BaseWrapper' + +const MINIMAL_TOKEN_INFO_ABI = [ + { + type: 'function' as const, + stateMutability: 'view', + outputs: [{ type: 'string', name: '', internalType: 'string' }], + name: 'symbol', + inputs: [], + }, + { + type: 'function' as const, + stateMutability: 'view', + outputs: [{ type: 'string', name: '', internalType: 'string' }], + name: 'name', + inputs: [], + }, + { + type: 'function' as const, + stateMutability: 'view', + inputs: [], + outputs: [{ type: 'address', name: '', internalType: 'address' }], + name: 'adaptedToken', + }, +] as const + +export abstract class AbstractFeeCurrencyWrapper< + TContract extends Contract +> extends BaseWrapper { + abstract getAddresses(): Promise + + async getFeeCurrencyInformation(whitelist?: StrongAddress[]) { + const feeCurrencies = whitelist ?? (await this.getAddresses()) + + return Promise.all( + feeCurrencies.map(async (address) => { + // @ts-expect-error abi typing is not 100% correct but works + let contract = new this.connection.web3.eth.Contract(MINIMAL_TOKEN_INFO_ABI, address) + + const adaptedToken = (await contract.methods + .adaptedToken() + .call() + .catch(() => undefined)) as StrongAddress | undefined + + if (adaptedToken) { + // @ts-expect-error abi typing is not 100% correct but works + contract = new this.connection.web3.eth.Contract(MINIMAL_TOKEN_INFO_ABI, adaptedToken) + } + + return Promise.all([ + contract.methods + .name() + .call() + .catch(() => undefined) as Promise, + contract.methods + .symbol() + .call() + .catch(() => undefined) as Promise, + ]).then(([name, symbol]) => ({ + name, + symbol, + address, + adaptedToken, + })) + }) + ) + } +} diff --git a/packages/sdk/contractkit/src/wrappers/FeeCurrencyDirectoryWrapper.ts b/packages/sdk/contractkit/src/wrappers/FeeCurrencyDirectoryWrapper.ts new file mode 100644 index 000000000..046afa88b --- /dev/null +++ b/packages/sdk/contractkit/src/wrappers/FeeCurrencyDirectoryWrapper.ts @@ -0,0 +1,21 @@ +import { FeeCurrencyDirectory } from '@celo/abis/web3/FeeCurrencyDirectory' +import { StrongAddress } from '@celo/base' +import { AbstractFeeCurrencyWrapper } from './AbstractFeeCurrencyWrapper' +import { proxyCall } from './BaseWrapper' + +/** + * FeeCurrencyDirectory contract listing available currencies usable to pay fees + */ +export class FeeCurrencyDirectoryWrapper extends AbstractFeeCurrencyWrapper { + getCurrencies = proxyCall( + this.contract.methods.getCurrencies, + undefined, + (addresses) => [...new Set(addresses)].sort() as StrongAddress[] + ) + + getAddresses(): Promise { + return this.getCurrencies() + } + + // TODO add other methods as well +} diff --git a/packages/sdk/contractkit/src/wrappers/FeeCurrencyWhitelistWrapper.ts b/packages/sdk/contractkit/src/wrappers/FeeCurrencyWhitelistWrapper.ts index ab2f8c160..ded7b6139 100644 --- a/packages/sdk/contractkit/src/wrappers/FeeCurrencyWhitelistWrapper.ts +++ b/packages/sdk/contractkit/src/wrappers/FeeCurrencyWhitelistWrapper.ts @@ -1,81 +1,24 @@ import { FeeCurrencyWhitelist } from '@celo/abis/web3/FeeCurrencyWhitelist' import { StrongAddress } from '@celo/base' -import 'bignumber.js' -import { BaseWrapper, proxyCall } from './BaseWrapper' - -const MINIMAL_TOKEN_INFO_ABI = [ - { - type: 'function' as const, - stateMutability: 'view', - outputs: [{ type: 'string', name: '', internalType: 'string' }], - name: 'symbol', - inputs: [], - }, - { - type: 'function' as const, - stateMutability: 'view', - outputs: [{ type: 'string', name: '', internalType: 'string' }], - name: 'name', - inputs: [], - }, - { - type: 'function' as const, - stateMutability: 'view', - inputs: [], - outputs: [{ type: 'address', name: '', internalType: 'address' }], - name: 'adaptedToken', - }, -] as const +import { AbstractFeeCurrencyWrapper } from './AbstractFeeCurrencyWrapper' +import { proxyCall } from './BaseWrapper' /** * FeeCurrencyWhitelist contract listing available currencies usable to pay fees */ -export class FeeCurrencyWhitelistWrapper extends BaseWrapper { +export class FeeCurrencyWhitelistWrapper extends AbstractFeeCurrencyWrapper { getWhitelist = proxyCall( this.contract.methods.getWhitelist, undefined, (addresses) => [...new Set(addresses)].sort() as StrongAddress[] ) - async getFeeCurrencyInformation(whitelist?: StrongAddress[]) { - const feeCurrencies = whitelist ?? (await this.getWhitelist()) - - return Promise.all( - feeCurrencies.map(async (address) => { - // @ts-expect-error abi typing is not 100% correct but works - let contract = new this.connection.web3.eth.Contract(MINIMAL_TOKEN_INFO_ABI, address) - - const adaptedToken = (await contract.methods - .adaptedToken() - .call() - .catch(() => undefined)) as StrongAddress | undefined - - if (adaptedToken) { - // @ts-expect-error abi typing is not 100% correct but works - contract = new this.connection.web3.eth.Contract(MINIMAL_TOKEN_INFO_ABI, adaptedToken) - } - - return Promise.all([ - contract.methods - .name() - .call() - .catch(() => undefined) as Promise, - contract.methods - .symbol() - .call() - .catch(() => undefined) as Promise, - ]).then(([name, symbol]) => ({ - name, - symbol, - address, - adaptedToken, - })) - }) - ) - } - removeToken = proxyCall(this.contract.methods.removeToken) addToken = proxyCall(this.contract.methods.addToken) + + getAddresses(): Promise { + return this.getWhitelist() + } } export type GoldTokenWrapperType = FeeCurrencyWhitelistWrapper