Skip to content

Commit

Permalink
add ronin and fix supported)tokens logic (#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
aelmanaa authored Jan 3, 2025
1 parent 517d8a6 commit 8bae265
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 89 deletions.
20 changes: 20 additions & 0 deletions ccip/offchain/config/mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,5 +298,25 @@
"version": "1.5.0"
},
"feeTokens": ["LINK", "WETH"]
},
"roninMainnet": {
"chainSelector": "6916147374840168594",
"router": {
"address": "0x46527571D5D1B68eE7Eb60B18A32e6C60DcEAf99",
"version": "1.2.0"
},
"armProxy": {
"address": "0xceA253a8c2BB995054524d071498281E89aACD59",
"version": "1.5.0"
},
"registryModule": {
"address": "0x5055DA89A16b71fEF91D1af323b139ceDe2d8320",
"version": "1.5.0"
},
"tokenAdminRegistry": {
"address": "0x90e83d532A4aD13940139c8ACE0B93b0DdbD323a",
"version": "1.5.0"
},
"feeTokens": ["LINK", "WRON"]
}
}
20 changes: 20 additions & 0 deletions ccip/offchain/config/testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,5 +298,25 @@
"version": "1.5.0"
},
"feeTokens": ["LINK", "WETH"]
},
"roninSaigon": {
"chainSelector": "13116810400804392105",
"router": {
"address": "0x0aCAe4e51D3DA12Dd3F45A66e8b660f740e6b820",
"version": "1.2.0"
},
"armProxy": {
"address": "0xf206c6D3f3810eBbD75e7B4684291b5e51023D2f",
"version": "1.5.0"
},
"registryModule": {
"address": "0xE31827cd24d7D419fC17E7Ff889BaF62A17991A0",
"version": "1.5.0"
},
"tokenAdminRegistry": {
"address": "0x057879f376041D527a98327DE2Ec00F201c9cA25",
"version": "1.5.0"
},
"feeTokens": ["LINK", "WRON"]
}
}
9 changes: 5 additions & 4 deletions ccip/offchain/javascript/src/config/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ const getRpcUrlName = (network) =>
const getProviderRpcUrl = (network) => {
require("@chainlink/env-enc").config();
if (!supportedNetworks.includes(network))
throw new Error("Unsupported network: " + network);
throw new Error(
`[ERROR] Network '${network}' is not supported. Supported networks: ${supportedNetworks.join(", ")}`
);

const environmentVariableName = getRpcUrlName(network);

const rpcUrl = process.env[environmentVariableName];

if (!rpcUrl)
throw new Error(
`rpcUrl empty for network ${network} - check your environment variables`
`[ERROR] RPC URL not found for network '${network}'. Please set ${environmentVariableName} in your environment variables`
);
return rpcUrl;
};
Expand All @@ -24,7 +25,7 @@ const getPrivateKey = () => {
const privateKey = process.env.PRIVATE_KEY;
if (!privateKey)
throw new Error(
"private key not provided - check your environment variables"
`[ERROR] PRIVATE_KEY not found in environment variables. Please set PRIVATE_KEY using chainlink env-enc`
);
return privateKey;
};
Expand Down
152 changes: 105 additions & 47 deletions ccip/offchain/javascript/src/supported-tokens.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,113 +10,171 @@ const { ethers } = require("ethers");
const routerAbi = require("../../abi/Router.json");
const erc20Abi = require("../../abi/IERC20Metadata.json");
const tokenAdminRegistryAbi = require("../../abi/TokenAdminRegistry.json");
const tokenPoolAbi = require("../../abi/TokenPool.json");

// Function to handle command-line arguments
const handleArguments = () => {
// Check if the correct number of arguments have been passed
if (process.argv.length !== 4) {
throw new Error(
"Expects 2 arguments. Expected format: node src/supported-tokens.js <sourceChain> <destinationChain>"
);
}

// Retrieve the chain names from command line arguments
const sourceChain = process.argv[2];
const destinationChain = process.argv[3];

return { sourceChain, destinationChain };
};

// Function to fetch and display supported tokens
const getSupportedTokens = async () => {
// Get the source and target chain names from the command line arguments
console.log(`[INFO] Starting token discovery for cross-chain transfers`);
const { sourceChain, destinationChain } = handleArguments();

// Get the RPC URL for the chain from the config
const rpcUrl = getProviderRpcUrl(sourceChain);
// Initialize a provider using the obtained RPC URL
const provider = new ethers.JsonRpcProvider(rpcUrl);

// Get the router's address for the specified chain
const routerAddress = getRouterConfig(sourceChain).router.address;
// Get the chain selector for the target chain
const destinationChainSelector =
getRouterConfig(destinationChain).chainSelector;
const destinationChainSelector = getRouterConfig(destinationChain).chainSelector;

// Create a contract instance for the router using its ABI and address
const sourceRouterContract = new ethers.Contract(
routerAddress,
routerAbi,
provider
);

// Check if the destination chain is supported
const isChainSupported = await sourceRouterContract.isChainSupported(
destinationChainSelector
);

if (!isChainSupported) {
console.error(
`[ERROR] Lane ${sourceChain} -> ${destinationChain} is not supported`
);
throw new Error(
`Lane ${sourceChain} -> ${destinationChain} is not supported\n`
);
}
console.log(`[INFO] Lane ${sourceChain} -> ${destinationChain} is supported`);

// Check if TokenAdminRegistry is present for the source chain
const tokenAdminRegistryConfig = getTokenAdminRegistryConfig(sourceChain);
const tokenAdminRegistryAddress = tokenAdminRegistryConfig.address;
const tokenAdminRegistryContract = new ethers.Contract(
tokenAdminRegistryAddress,
tokenAdminRegistryAbi,
provider
);

let supportedTokens = [];
let startIndex = 0;
const maxCount = 100;
let tokensBatch = [];
const tokenToPoolMap = {}; // Mapping of token to pool
const uniqueTokens = new Set(); // Use Set to handle potential duplicates

console.log(
`[INFO] Fetching all registered tokens from ${sourceChain} using TokenAdminRegistry at ${tokenAdminRegistryAddress}`
);

if (tokenAdminRegistryConfig) {
// TokenAdminRegistry is present, use getAllConfiguredTokens
const tokenAdminRegistryAddress = tokenAdminRegistryConfig.address;
const tokenAdminRegistryContract = new ethers.Contract(
tokenAdminRegistryAddress,
tokenAdminRegistryAbi,
provider
let totalProcessed = 0;
do {
console.log(
`[INFO] Fetching batch: offset=${startIndex}, limit=${maxCount}`
);
tokensBatch = await tokenAdminRegistryContract.getAllConfiguredTokens(
startIndex,
maxCount
);
totalProcessed += tokensBatch.length;
console.log(
`[INFO] Found ${tokensBatch.length} tokens (total processed: ${totalProcessed})`
);

// Handle pagination
let startIndex = 0;
const maxCount = 100;
let tokensBatch = [];

do {
tokensBatch = await tokenAdminRegistryContract.getAllConfiguredTokens(
startIndex,
maxCount
);
supportedTokens.push(...tokensBatch);
startIndex += tokensBatch.length;
} while (tokensBatch.length === maxCount);
} else {
// TokenAdminRegistry not present, use Router.getSupportedTokens
supportedTokens = await sourceRouterContract.getSupportedTokens(
destinationChainSelector
tokensBatch.forEach((token) => uniqueTokens.add(token));
startIndex = startIndex + tokensBatch.length;

console.log(
`[INFO] Fetching pools for ${tokensBatch.length} tokens and checking support for ${destinationChain}`
);
}
const pools = await tokenAdminRegistryContract.getPools([...tokensBatch]);

// Process pools in chunks of 5 for parallel processing
for (let i = 0; i < tokensBatch.length; i += 5) {
const chunkEnd = Math.min(i + 5, tokensBatch.length);
const chunk = tokensBatch.slice(i, chunkEnd);
const poolsChunk = pools.slice(i, chunkEnd);

const supportCheckPromises = poolsChunk.map((poolAddress, index) => {
const tokenPoolContract = new ethers.Contract(
poolAddress,
tokenPoolAbi,
provider
);
return tokenPoolContract
.isSupportedChain(destinationChainSelector)
.then((isSupported) => ({
token: chunk[index],
pool: poolAddress,
isSupported,
error: null,
}))
.catch((error) => ({
token: chunk[index],
pool: poolAddress,
isSupported: false,
error,
}));
});

const results = await Promise.all(supportCheckPromises);

results.forEach(({ token, pool, isSupported, error }) => {
if (error) {
console.warn(
`Failed to check chain support for pool ${pool}, skipping...`
);
} else if (isSupported) {
tokenToPoolMap[token] = pool;
}
});
}
} while (tokensBatch.length === maxCount);

const eligibleTokens = Object.keys(tokenToPoolMap).length;
console.log(
`[SUMMARY] Found ${uniqueTokens.size} unique tokens, ${eligibleTokens} support ${destinationChain}`
);

const supportedTokens = Array.from(uniqueTokens);

// For each supported token, print its name, symbol, and decimal precision
for (const supportedToken of supportedTokens) {
// Create a contract instance for the token using its ABI and address
if (!tokenToPoolMap[supportedToken]) {
continue;
}

const erc20 = new ethers.Contract(supportedToken, erc20Abi, provider);

// Fetch the token's name, symbol, and decimal precision
const [name, symbol, decimals] = await Promise.all([
erc20.name(),
erc20.symbol(),
erc20.decimals(),
]);

// Print the token's details
const poolAddress = tokenToPoolMap[supportedToken];

console.log(
`ERC20 token with address ${supportedToken} is ${name} with symbol ${symbol} and decimals ${decimals}\n`
`[INFO] Token: ${name} (${symbol}) at ${supportedToken}, decimals=${decimals}, pool=${poolAddress}`
);
}
};

// Run the function and handle any errors
getSupportedTokens().catch((e) => {
// Print any error message and terminate the script with a non-zero exit code
console.error(e);
console.error(`[ERROR] Token discovery failed:`);
if (e instanceof Error) {
console.error(`[ERROR] Message: ${e.message}`);
if (e.stack) {
console.error(`[ERROR] Stack: ${e.stack}`);
}
} else {
console.error(`[ERROR] Unknown error type:`, e);
}
process.exit(1);
});
4 changes: 2 additions & 2 deletions ccip/offchain/typescript/src/config/ccip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ interface NetworkConfig {
address: string;
version: string;
};
registryModule?: {
registryModule: {
address: string;
version: string;
};
tokenAdminRegistry?: {
tokenAdminRegistry: {
address: string;
version: string;
};
Expand Down
7 changes: 3 additions & 4 deletions ccip/offchain/typescript/src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ const getRpcUrlName = (network: NETWORK) =>
const getProviderRpcUrl = (network: NETWORK) => {
require("@chainlink/env-enc").config();
if (!supportedNetworks.includes(network))
throw new Error("Unsupported network: " + network);
throw new Error(`[ERROR] Network '${network}' is not supported. Supported networks: ${supportedNetworks.join(", ")}`);

const environmentVariableName = getRpcUrlName(network);

const rpcUrl = process.env[environmentVariableName];

if (!rpcUrl)
throw new Error(
`rpcUrl empty for network ${network} - check your environment variables`
`[ERROR] RPC URL not found for network '${network}'. Please set ${environmentVariableName} in your environment variables`
);
return rpcUrl;
};
Expand All @@ -24,7 +23,7 @@ const getPrivateKey = () => {
const privateKey = process.env.PRIVATE_KEY;
if (!privateKey)
throw new Error(
"private key not provided - check your environment variables"
`[ERROR] PRIVATE_KEY not found in environment variables. Please set PRIVATE_KEY using chainlink env-enc`
);
return privateKey;
};
Expand Down
Loading

0 comments on commit 8bae265

Please sign in to comment.