From b62f4914617fe14495d2a9d701e7238b170c8af8 Mon Sep 17 00:00:00 2001 From: Richard Kenigs Date: Thu, 14 Mar 2024 15:37:38 +0100 Subject: [PATCH] add logic to get tokens balances for chain and address, change getBalance and getDecimals to work without signer --- package-lock.json | 12 +++-- .../builder/fixtures/builderParamsMock.ts | 5 ++ packages/config/package.json | 3 +- .../src/ConfigService/ConfigService.test.ts | 5 ++ packages/config/src/chains.ts | 36 +++++++++++++ packages/sdk/src/contract/contract.factory.ts | 13 +++++ .../contract/contracts/Erc20/Erc20Public.ts | 46 +++++++++++++++++ .../sdk/src/getTransferData/getSourceData.ts | 50 +++++++------------ .../getTransferData/getTransferData.utils.ts | 32 ++++++------ packages/sdk/src/sdk.ts | 4 +- packages/types/package.json | 3 +- .../types/src/chain/parachain/EvmParachain.ts | 33 +++++++++++- 12 files changed, 180 insertions(+), 62 deletions(-) create mode 100644 packages/sdk/src/contract/contracts/Erc20/Erc20Public.ts diff --git a/package-lock.json b/package-lock.json index 3dde639b..f8540fe1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16732,9 +16732,9 @@ } }, "node_modules/viem": { - "version": "2.7.8", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.7.8.tgz", - "integrity": "sha512-5r5pkBDBmihCvMx4b3MqtP0FoZCRWE2ML1DssU80+vhJQur0PKd4yHdLbbvoiGGVD6bYiA394juhfdSvXIGgFA==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.8.6.tgz", + "integrity": "sha512-LqxLOSFtXfbC3tsiZ8Km8jKR4ktTOLfigL2dR9IN28He2+QrNhYvvwGPz3P4hbfU12Wvuxo6mWGZ2L1lpNtvrA==", "funding": [ { "type": "github", @@ -17290,7 +17290,8 @@ "license": "MIT", "dependencies": { "@moonbeam-network/xcm-builder": "2.0.1", - "@moonbeam-network/xcm-types": "2.0.1" + "@moonbeam-network/xcm-types": "2.0.1", + "viem": "^2.8.6" }, "peerDependencies": { "@polkadot/types": "^10.10.1", @@ -17325,7 +17326,8 @@ "dependencies": { "@moonbeam-network/xcm-utils": "2.0.1", "big.js": "^6.2.1", - "type-fest": "^3.8.0" + "type-fest": "^3.8.0", + "viem": "^2.8.6" } }, "packages/types/node_modules/type-fest": { diff --git a/packages/builder/fixtures/builderParamsMock.ts b/packages/builder/fixtures/builderParamsMock.ts index 8c408b18..573c4ec3 100644 --- a/packages/builder/fixtures/builderParamsMock.ts +++ b/packages/builder/fixtures/builderParamsMock.ts @@ -37,6 +37,11 @@ export const moonbaseAlphaMock = new EvmParachain({ isTestChain: true, key: 'moonbase-alpha', name: 'Moonbase Alpha', + nativeCurrency: { + decimals: 18, + name: 'MOCK', + symbol: 'MOCK', + }, parachainId: 1000, rpc: 'https://rpc.api.moonbase.moonbeam.network', ss58Format: 1287, diff --git a/packages/config/package.json b/packages/config/package.json index 6cca0ce9..9f311efc 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -51,7 +51,8 @@ "main": "./build/index.cjs", "dependencies": { "@moonbeam-network/xcm-builder": "2.0.1", - "@moonbeam-network/xcm-types": "2.0.1" + "@moonbeam-network/xcm-types": "2.0.1", + "viem": "^2.8.6" }, "peerDependencies": { "@polkadot/types": "^10.10.1", diff --git a/packages/config/src/ConfigService/ConfigService.test.ts b/packages/config/src/ConfigService/ConfigService.test.ts index 55ca9ecc..ff7793df 100644 --- a/packages/config/src/ConfigService/ConfigService.test.ts +++ b/packages/config/src/ConfigService/ConfigService.test.ts @@ -100,6 +100,11 @@ describe('config service', () => { isTestChain: true, key: 'test', name: 'test', + nativeCurrency: { + decimals: 18, + name: 'TEST', + symbol: 'TEST', + }, parachainId: 1000, rpc: '', ss58Format: 1287, diff --git a/packages/config/src/chains.ts b/packages/config/src/chains.ts index fa22819e..88611816 100644 --- a/packages/config/src/chains.ts +++ b/packages/config/src/chains.ts @@ -329,6 +329,11 @@ export const darwinia = new EvmParachain({ id: 46, key: 'darwinia', name: 'Darwinia', + nativeCurrency: { + decimals: 18, + name: 'RING', + symbol: 'RING', + }, parachainId: 2046, rpc: 'https://rpc.darwinia.network', ss58Format: 18, @@ -355,12 +360,18 @@ export const darwiniaCrab = new EvmParachain({ id: 44, key: 'darwinia-crab', name: 'Darwinia Crab', + nativeCurrency: { + decimals: 18, + name: 'CRAB', + symbol: 'CRAB', + }, parachainId: 2105, rpc: 'https://crab-rpc.darwinia.network', ss58Format: 18, ws: 'wss://crab-parachain-rpc.darwinia.network', }); +// FIXME: do we need this chain? it looks dead to me - https://pangoro.subscan.io/ export const darwiniaPangoro = new EvmParachain({ assetsData: [ { @@ -382,6 +393,11 @@ export const darwiniaPangoro = new EvmParachain({ isTestChain: true, key: 'darwinia-pangoro', name: 'Pangoro', + nativeCurrency: { + decimals: 18, + name: '???', + symbol: '???', + }, parachainId: 2105, rpc: 'https://pangoro-rpc.darwinia.network', ss58Format: 18, @@ -729,6 +745,11 @@ export const moonbaseAlpha = new EvmParachain({ isTestChain: true, key: 'moonbase-alpha', name: 'Moonbase Alpha', + nativeCurrency: { + decimals: 18, + name: 'DEV', + symbol: 'DEV', + }, parachainId: 1000, rpc: 'https://rpc.api.moonbase.moonbeam.network', ss58Format: 1287, @@ -759,6 +780,11 @@ export const moonbaseBeta = new EvmParachain({ isTestChain: true, key: 'moonbase-beta', name: 'Moonbase Beta', + nativeCurrency: { + decimals: 18, + name: 'DEV', + symbol: 'DEV', + }, parachainId: 888, rpc: 'https://frag-moonbase-beta-rpc.g.moonbase.moonbeam.network', ss58Format: 1287, @@ -931,6 +957,11 @@ export const moonbeam = new EvmParachain({ id: 1284, key: 'moonbeam', name: 'Moonbeam', + nativeCurrency: { + decimals: 18, + name: 'Glimmer', + symbol: 'GLMR', + }, parachainId: 2004, rpc: 'https://rpc.api.moonbeam.network', ss58Format: 1284, @@ -1046,6 +1077,11 @@ export const moonriver = new EvmParachain({ id: 1285, key: 'moonriver', name: 'Moonriver', + nativeCurrency: { + decimals: 18, + name: 'MOVR', + symbol: 'MOVR', + }, parachainId: 2023, rpc: 'https://rpc.api.moonriver.moonbeam.network', ss58Format: 1285, diff --git a/packages/sdk/src/contract/contract.factory.ts b/packages/sdk/src/contract/contract.factory.ts index a90a76d7..0ef0be76 100644 --- a/packages/sdk/src/contract/contract.factory.ts +++ b/packages/sdk/src/contract/contract.factory.ts @@ -1,10 +1,12 @@ import { ContractConfig } from '@moonbeam-network/xcm-builder'; +import { EvmParachain } from '@moonbeam-network/xcm-types'; import { EvmSigner } from '../sdk.interfaces'; import { BalanceContractInterface, TransferContractInterface, } from './contract.interfaces'; import { Erc20, Xtokens } from './contracts'; +import { Erc20Public } from './contracts/Erc20/Erc20Public'; export function createContract( config: ContractConfig, @@ -20,3 +22,14 @@ export function createContract( throw new Error(`Contract ${config.module} not found`); } + +export function createContractWithoutSigner( + config: ContractConfig, + chain: EvmParachain, +): TransferContractInterface | BalanceContractInterface { + if (config.module === 'Erc20') { + return new Erc20Public(config, chain.getViemChain()); + } + + throw new Error(`Public Contract ${config.module} not found`); +} diff --git a/packages/sdk/src/contract/contracts/Erc20/Erc20Public.ts b/packages/sdk/src/contract/contracts/Erc20/Erc20Public.ts new file mode 100644 index 00000000..df91ca78 --- /dev/null +++ b/packages/sdk/src/contract/contracts/Erc20/Erc20Public.ts @@ -0,0 +1,46 @@ +import { ContractConfig } from '@moonbeam-network/xcm-builder'; +import { Chain, PublicClient, createPublicClient, http } from 'viem'; +import { BalanceContractInterface } from '../../contract.interfaces'; +import abi from './Erc20ABI.json'; + +export class Erc20Public implements BalanceContractInterface { + readonly address: string; + + readonly #config: ContractConfig; + + readonly #publicClient: PublicClient; + + constructor(config: ContractConfig, chain: Chain) { + if (!config.address) { + throw new Error('Contract address is required'); + } + this.address = config.address; + + this.#config = config; + + this.#publicClient = createPublicClient({ + chain, + transport: http(), + }); + } + + async getBalance(): Promise { + const data = await this.#publicClient.readContract({ + abi, + address: this.#config.address as `0x${string}`, + functionName: 'balanceOf', + }); + + return data as unknown as bigint; + } + + async getDecimals(): Promise { + const data = await this.#publicClient.readContract({ + abi, + address: this.#config.address as `0x${string}`, + functionName: 'decimals', + }); + + return data as unknown as number; + } +} diff --git a/packages/sdk/src/getTransferData/getSourceData.ts b/packages/sdk/src/getTransferData/getSourceData.ts index 3b36e552..0a85e869 100644 --- a/packages/sdk/src/getTransferData/getSourceData.ts +++ b/packages/sdk/src/getTransferData/getSourceData.ts @@ -340,7 +340,6 @@ export async function getAssetsBalances({ address, chain, assets, - evmSigner, polkadot, }: GetAssetsBalancesParams) { const result = []; @@ -358,40 +357,25 @@ export async function getAssetsBalances({ // eslint-disable-next-line no-restricted-syntax for (const asset of uniqueAssets) { - try { - console.log(asset); - - // eslint-disable-next-line no-await-in-loop - const decimals = await getDecimals({ - address, - asset: asset.asset, - chain, - config: asset, - evmSigner, - polkadot, - }); + // eslint-disable-next-line no-await-in-loop + const decimals = await getDecimals({ + address, + asset: asset.asset, + chain, + config: asset, + polkadot, + }); - // eslint-disable-next-line no-await-in-loop - const balance = await getBalance({ - address, - chain, - config: asset, - decimals, - evmSigner, - polkadot, - }); + // eslint-disable-next-line no-await-in-loop + const balance = await getBalance({ + address, + chain, + config: asset, + decimals, + polkadot, + }); - result.push({ balance, asset: asset.asset }); - } catch (error) { - console.log( - '\x1b[34m████████████████████▓▓▒▒░ getSourceData.ts:406 ░▒▒▓▓████████████████████\x1b[0m', - ); - console.log('* error = '); - console.log(error); - console.log( - '\x1b[34m▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄\x1b[0m', - ); - } + result.push({ asset: asset.asset, balance, decimals }); } return result; } diff --git a/packages/sdk/src/getTransferData/getTransferData.utils.ts b/packages/sdk/src/getTransferData/getTransferData.utils.ts index cd9c1fb8..ec989cd3 100644 --- a/packages/sdk/src/getTransferData/getTransferData.utils.ts +++ b/packages/sdk/src/getTransferData/getTransferData.utils.ts @@ -1,8 +1,11 @@ import { CallType, SubstrateQueryConfig } from '@moonbeam-network/xcm-builder'; import { AssetConfig } from '@moonbeam-network/xcm-config'; -import { AnyChain, Asset } from '@moonbeam-network/xcm-types'; +import { AnyChain, Asset, EvmParachain } from '@moonbeam-network/xcm-types'; import { convertDecimals, toBigInt } from '@moonbeam-network/xcm-utils'; -import { BalanceContractInterface, createContract } from '../contract'; +import { + BalanceContractInterface, + createContractWithoutSigner, +} from '../contract'; import { PolkadotService } from '../polkadot'; import { EvmSigner } from '../sdk.interfaces'; @@ -23,7 +26,6 @@ export async function getBalance({ chain, config, decimals, - evmSigner, polkadot, }: GetBalancesParams) { const cfg = config.balance.build({ @@ -38,13 +40,10 @@ export async function getBalance({ : balance; } - if (!evmSigner) { - throw new Error( - `getBalance: Evm signer must be provided. Asset: ${config.asset.key}`, - ); - } - - const contract = createContract(cfg, evmSigner) as BalanceContractInterface; + const contract = createContractWithoutSigner( + cfg, + chain as EvmParachain, + ) as BalanceContractInterface; return contract.getBalance(); } @@ -53,8 +52,8 @@ export async function getDecimals({ address, asset, config, - evmSigner, polkadot, + chain, }: GetDecimalsParams) { const cfg = config.balance.build({ address, @@ -65,13 +64,10 @@ export async function getDecimals({ return polkadot.getAssetDecimals(asset || config.asset); } - if (!evmSigner) { - throw new Error( - `getDecimals: Evm signer must be provided. Asset: ${asset?.key}`, - ); - } - - const contract = createContract(cfg, evmSigner) as BalanceContractInterface; + const contract = createContractWithoutSigner( + cfg, + chain as EvmParachain, + ) as BalanceContractInterface; return contract.getDecimals(); } diff --git a/packages/sdk/src/sdk.ts b/packages/sdk/src/sdk.ts index ba57ea63..d2c7988d 100644 --- a/packages/sdk/src/sdk.ts +++ b/packages/sdk/src/sdk.ts @@ -8,7 +8,7 @@ import { AnyChain, Asset, Ecosystem } from '@moonbeam-network/xcm-types'; import { getAssetsBalances } from './getTransferData/getSourceData'; import { getTransferData as gtd } from './getTransferData/getTransferData'; import { PolkadotService } from './polkadot'; -import { EvmSigner, Signers, TransferData } from './sdk.interfaces'; +import { Signers, TransferData } from './sdk.interfaces'; export interface SdkOptions extends Partial { configService?: IConfigService; @@ -88,7 +88,6 @@ export function Sdk(options?: SdkOptions) { export async function getParachainBalances( chain: AnyChain, address: string, - evmSigner?: EvmSigner, ): Promise { const configService = new ConfigService(); const chainsConfig = configService.getChainConfig(chain); @@ -100,7 +99,6 @@ export async function getParachainBalances( chain, assets, address, - evmSigner, polkadot, }); diff --git a/packages/types/package.json b/packages/types/package.json index 54876f2a..b7ea62bf 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -51,6 +51,7 @@ "dependencies": { "@moonbeam-network/xcm-utils": "2.0.1", "big.js": "^6.2.1", - "type-fest": "^3.8.0" + "type-fest": "^3.8.0", + "viem": "^2.8.6" } } diff --git a/packages/types/src/chain/parachain/EvmParachain.ts b/packages/types/src/chain/parachain/EvmParachain.ts index bf2aae97..e2fbc836 100644 --- a/packages/types/src/chain/parachain/EvmParachain.ts +++ b/packages/types/src/chain/parachain/EvmParachain.ts @@ -1,3 +1,5 @@ +import { defineChain } from 'viem'; +import { Chain } from 'viem/chains'; import { ChainType } from '../Chain.interfaces'; import { Parachain, ParachainConstructorParams } from './Parachain'; @@ -5,17 +7,46 @@ export interface EvmParachainConstructorParams extends Omit { id: number; rpc: string; + nativeCurrency: NativeCurrency; } +type NativeCurrency = { + decimals: number; + name: string; + symbol: string; +}; + export class EvmParachain extends Parachain { readonly id: number; readonly rpc: string; - constructor({ id, rpc, ...others }: EvmParachainConstructorParams) { + readonly nativeCurrency: NativeCurrency; + + constructor({ + id, + rpc, + nativeCurrency, + ...others + }: EvmParachainConstructorParams) { super({ type: ChainType.EvmParachain, ...others }); this.id = id; this.rpc = rpc; + this.nativeCurrency = nativeCurrency; + } + + getViemChain(): Chain { + return defineChain({ + id: this.id, + name: this.name, + nativeCurrency: this.nativeCurrency, + rpcUrls: { + default: { + http: [this.rpc], + webSocket: [this.ws], + }, + }, + }); } }