Skip to content

Commit

Permalink
add: update foreign assets script
Browse files Browse the repository at this point in the history
  • Loading branch information
anondev2323 committed Oct 12, 2023
1 parent 6a0d438 commit e77fdf5
Show file tree
Hide file tree
Showing 8 changed files with 1,963 additions and 2,523 deletions.
132 changes: 132 additions & 0 deletions core/tokenRegistry/src/foreignAssets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// patch out annoying logs
const info = console.info;
console.info = function (x: any, ...rest: any) {
if (x !== 'secp256k1 unavailable, reverting to browser version') {
info(x, ...rest);
}
};
const warn = console.warn;
console.warn = function (x: any, ...rest: any) {
if (
!x
.toString()
.startsWith(
'Error: Error: RPC Validation Error: The response returned from RPC server does not match the TypeScript definition. This is likely because the SDK version is not compatible with the RPC server.',
)
) {
warn(x, ...rest);
}
};

import { ChainName, chains } from "@wormhole-foundation/sdk-base";
import { ForeignAssetsCache, TokensConfig } from "./types";
import { TokenId, Wormhole, toNative } from "@wormhole-foundation/connect-sdk";

// TODO: Question: How do we handle if a user tries to perform an action for a chain/platform which isn't installed??
// const supportedPlatforms: PlatformName[] = ['Evm', 'Solana'];
const supportedChains: ChainName[] = ['Ethereum', 'Polygon', 'Celo', 'Moonbeam', 'Fantom', 'Avalanche', 'Bsc', 'Optimism', 'Arbitrum', 'Solana']

export const isSupportedChain = (chain: ChainName) => {
return supportedChains.includes(chain);
}

export const createTokenId = (chain: ChainName, address: string) => {
if (!isSupportedChain(chain)) return;
return {
chain,
address: toNative(chain, address),
}
}

export const getForeignAddress = async (wh: Wormhole, chain: ChainName, tokenId: TokenId) => {
if (!isSupportedChain(chain)) return;
let foreignAddress: string | null = null;
try {
const foreignId = await wh.getWrappedAsset(chain, tokenId);
foreignAddress = foreignId.address.toString();
} catch (e: any) {
if (
e?.message === '3104 RPC not configured' ||
e?.message === 'wormchain RPC not configured'
) {
// do not throw on wormchain errors
} else if (e?.message.includes('is not a wrapped asset')) {
// do not throw if wrapped asset does not exist
} else {
// log error but keep going
console.error(e)
}
}
return foreignAddress;
}

export const getForeignAssetsData = async (wh: Wormhole, chain: ChainName, tokenId: TokenId | undefined, foreignAssetsCache: ForeignAssetsCache | undefined) => {
if (!tokenId) return;
let updates: ForeignAssetsCache = {};
for (const foreignChain of chains) {
const isSupported = isSupportedChain(foreignChain);
if (foreignChain !== tokenId.chain && isSupported) {
const configForeignAddress = foreignAssetsCache ? foreignAssetsCache[foreignChain] : undefined;
const foreignAddress = await getForeignAddress(wh, foreignChain, tokenId);
if (foreignAddress) {
const foreignDecimals = await wh.getDecimals(
foreignChain,
toNative(foreignChain, foreignAddress),
);
if (configForeignAddress) {
if (configForeignAddress.address !== foreignAddress) {
throw new Error(
`❌ Invalid foreign address detected! Env: ${wh.conf.network}, Existing Address: ${configForeignAddress.address}, Chain: ${chain}, Expected: ${foreignAddress}, Received: ${configForeignAddress.address}`,
);
} else if (configForeignAddress.decimals !== Number(foreignDecimals)) {
throw new Error(
`❌ Invalid foreign decimals detected! Env: ${wh.conf.network}, Existing Address: ${configForeignAddress.address}, Chain: ${chain}, Expected: ${foreignDecimals}, Received: ${configForeignAddress.decimals}`,
);
} else {
// console.log('✅ Config matches');
}
} else {
const update = {
[foreignChain]: {
address: foreignAddress,
decimals: Number(foreignDecimals)
}
}
updates = { ...updates, ...update }
}
}
}
}
return updates;
}

export const getSuggestedUpdates = async (wh: Wormhole, tokensConfig: TokensConfig) => {
let suggestedUpdates: TokensConfig = {};
let numUpdates = 0;

for (const [chain, chainTokensConfig] of Object.entries(tokensConfig)) {
for (const [token, config] of Object.entries(chainTokensConfig)) {
const tokenId = createTokenId(chain as ChainName, token);
const updates = await getForeignAssetsData(wh, chain as ChainName, tokenId, config.foreignAssets);
if (updates && Object.values(updates).length > 0) {
numUpdates += Object.values(updates).length;
suggestedUpdates = {
...suggestedUpdates,
[chain]: {
...(suggestedUpdates[chain as ChainName] || {}),
[token]: {
...(suggestedUpdates[chain as ChainName] ? suggestedUpdates[chain as ChainName]![token] || {} : {}),
foreignAssets: {
...(suggestedUpdates[chain as ChainName] ? suggestedUpdates[chain as ChainName]![token] ? suggestedUpdates[chain as ChainName]![token]!.foreignAssets : {} : {}),
...updates,
}
}
}
}
}
}
}
// console.log(`${numUpdates} updates available`);
// console.log(JSON.stringify(suggestedUpdates, null, 4));
return [numUpdates, suggestedUpdates];
}
99 changes: 18 additions & 81 deletions core/tokenRegistry/src/scripts/checkForeignAssetConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,100 +18,37 @@ console.warn = function (x: any, ...rest: any) {
}
};

import { ChainName, Network, PlatformName, chainToPlatform, chains } from "@wormhole-foundation/sdk-base";
import { ForeignAssetsCache, TokensConfig } from "../types";
import { TESTNET_TOKENS } from "../tokens/testnetTokens";
import { TokenId, Wormhole, toNative } from "@wormhole-foundation/connect-sdk";
import * as fs from 'fs';
import { Network } from "@wormhole-foundation/sdk-base";
import { Wormhole } from "@wormhole-foundation/connect-sdk";
import { EvmPlatform } from "@wormhole-foundation/connect-sdk-evm";
import { SolanaPlatform } from "@wormhole-foundation/connect-sdk-solana";
import { getSuggestedUpdates } from '../foreignAssets';
import { TokensConfig } from "../types";

// TODO: How do we handle if a user tries to perform an action for a chain/platform which isn't installed??
const supportedPlatforms: PlatformName[] = ['Evm', 'Solana'];

const isSupportedPlatform = (chain: ChainName) => {
const platform = chainToPlatform(chain);
return supportedPlatforms.includes(platform);
}

const createTokenId = (chain: ChainName, address: string) => {
if (!isSupportedPlatform(chain)) return;
return {
chain,
address: toNative(chain, address),
}
}
const testnetTokens = fs.readFileSync('src/tokens/testnetTokens.json', 'utf-8');
const TESTNET_TOKENS = JSON.parse(testnetTokens) as TokensConfig;
const mainnetTokens = fs.readFileSync('src/tokens/mainnetTokens.json', 'utf-8');
const MAINNET_TOKENS = JSON.parse(mainnetTokens) as TokensConfig;

// warning: be careful optimizing the RPC calls in this script, you may 429 yourself
// slow and steady, or something like that
const checkEnvConfig = async (
env: Network,
tokensConfig: TokensConfig,
) => {
const wh = new Wormhole(env, [EvmPlatform, SolanaPlatform])

const getForeignAddress = async (chain: ChainName, tokenId: TokenId) => {
if (!isSupportedPlatform(chain)) return;
let foreignAddress: string | null = null;
try {
const foreignId = await wh.getWrappedAsset(chain, tokenId);
console.log(foreignId.address)
foreignAddress = foreignId.address.toString();
} catch (e: any) {
if (
e?.message === '3104 RPC not configured' ||
e?.message === 'wormchain RPC not configured'
) {
// do not throw on wormchain errors
} else {
// log error but keep going
console.error(e)
}
}
return foreignAddress;
}

const getForeignAssetsData = async (chain: ChainName, tokenId: TokenId | undefined, foreignAssetsCache: ForeignAssetsCache | undefined) => {
if (!tokenId) return;
for (const foreignChain of chains) {
const isSupported = isSupportedPlatform(foreignChain);
if (foreignChain !== tokenId.chain && isSupported) {
console.log('FOREIGN CHAIN', foreignChain)
const configForeignAddress = foreignAssetsCache ? foreignAssetsCache[foreignChain] : undefined;
const foreignAddress = await getForeignAddress(foreignChain, tokenId);
console.log(foreignAddress)
if (foreignAddress) {
const foreignDecimals = await wh.getDecimals(
foreignChain,
toNative(foreignChain, foreignAddress),
);
console.log('FOREIGN', foreignAddress, foreignDecimals)
if (configForeignAddress) {
if (configForeignAddress.address !== foreignAddress) {
throw new Error(
`❌ Invalid foreign address detected! Env: ${wh.conf.network}, Existing Address: ${configForeignAddress.address}, Chain: ${chain}, Expected: ${foreignAddress}, Received: ${configForeignAddress.address}`,
);
} else if (configForeignAddress.decimals !== Number(foreignDecimals)) {
throw new Error(
`❌ Invalid foreign decimals detected! Env: ${wh.conf.network}, Existing Address: ${configForeignAddress.address}, Chain: ${chain}, Expected: ${foreignDecimals}, Received: ${configForeignAddress.decimals}`,
);
} else {
console.log('✅ Config matches');
}
}
}
}
}
}

for (const [chain, chainTokensConfig] of Object.entries(tokensConfig)) {
console.log(`--------CHAIN--------\n${chain}\n`)
for (const [token, config] of Object.entries(chainTokensConfig)) {
const tokenId = createTokenId(chain as ChainName, token);
await getForeignAssetsData(chain as ChainName, tokenId, config.foreignAssets);
}
const wh = new Wormhole(env, [EvmPlatform, SolanaPlatform]);

const [numUpdates, suggestedUpdates] = await getSuggestedUpdates(wh, tokensConfig);
if (numUpdates as number > 0) {
console.log(`${numUpdates} updates available`);
console.log(JSON.stringify(suggestedUpdates, null, 4));
} else {
console.log('Up to date')
}
}

(async () => {
await checkEnvConfig('Testnet', TESTNET_TOKENS);
await checkEnvConfig('Mainnet', MAINNET_TOKENS);
})();
36 changes: 36 additions & 0 deletions core/tokenRegistry/src/scripts/updateForeignAssetConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as fs from 'fs';
import { Network } from "@wormhole-foundation/sdk-base";
import { Wormhole } from "@wormhole-foundation/connect-sdk";
import { EvmPlatform } from "@wormhole-foundation/connect-sdk-evm";
import { SolanaPlatform } from "@wormhole-foundation/connect-sdk-solana";
import { getSuggestedUpdates } from "../foreignAssets";
import { TokensConfig } from "../types";

const testnetTokens = fs.readFileSync('src/tokens/testnetTokens.json', 'utf-8');
const TESTNET_TOKENS = JSON.parse(testnetTokens) as TokensConfig;
const mainnetTokens = fs.readFileSync('src/tokens/mainnetTokens.json', 'utf-8');
const MAINNET_TOKENS = JSON.parse(mainnetTokens) as TokensConfig;

// warning: be careful optimizing the RPC calls in this script, you may 429 yourself
// slow and steady, or something like that
const checkEnvConfig = async (
env: Network,
tokensConfig: TokensConfig,
) => {
const wh = new Wormhole(env, [EvmPlatform, SolanaPlatform]);

const data = await getSuggestedUpdates(wh, tokensConfig);
const suggestedUpdates = data[0] as TokensConfig;
const newConfig = {
...tokensConfig,
...suggestedUpdates,
}
console.log('CONFIG\n', JSON.stringify(newConfig, null, 4));
const filePath = env === 'Mainnet' ? 'src/tokens/mainnetTokens.json' : 'src/tokens/testnetTokens.json';
fs.writeFileSync(filePath, JSON.stringify(newConfig, null, 2));
}

(async () => {
await checkEnvConfig('Testnet', TESTNET_TOKENS);
await checkEnvConfig('Mainnet', MAINNET_TOKENS);
})();
Loading

0 comments on commit e77fdf5

Please sign in to comment.