Skip to content

Commit

Permalink
Merge branch 'main' into chore/gh-workflow-for-sui-scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
npty authored Aug 23, 2024
2 parents 0b2791d + da16c8c commit d5806e4
Show file tree
Hide file tree
Showing 12 changed files with 408 additions and 45 deletions.
21 changes: 15 additions & 6 deletions common/cli-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

require('dotenv').config();

const { Option } = require('commander');
const fs = require('fs');
const { Option, Command } = require('commander');

// A path to the chain configuration files
const CHAIN_CONFIG_PATH = `${__dirname}/../axelar-chains-config/info`;

// A list of available chain environments which are the names of the files in the CHAIN_CONFIG_PATH
const CHAIN_ENVIRONMENTS = fs.readdirSync(CHAIN_CONFIG_PATH).map((chainName) => chainName.split('.')[0]);

const addBaseOptions = (program, options = {}) => {
program.addOption(
new Option('-e, --env <env>', 'environment')
.choices(['local', 'devnet', 'devnet-amplifier', 'devnet-verifiers', 'stagenet', 'testnet', 'mainnet'])
.default('testnet')
.makeOptionMandatory(true)
.env('ENV'),
new Option('-e, --env <env>', 'environment').choices(CHAIN_ENVIRONMENTS).default('testnet').makeOptionMandatory(true).env('ENV'),
);
program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES'));
program.addOption(new Option('--parallel', 'run script parallely wrt chains'));
Expand Down Expand Up @@ -81,7 +84,13 @@ const addExtendedOptions = (program, options = {}) => {
return program;
};

if (require.main === module) {
addBaseOptions(new Command());
}

module.exports = {
CHAIN_CONFIG_PATH,
CHAIN_ENVIRONMENTS,
addBaseOptions,
addExtendedOptions,
};
7 changes: 2 additions & 5 deletions cosmwasm/deploy-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require('dotenv').config();
const { isNil } = require('lodash');

const { CHAIN_ENVIRONMENTS } = require('../common');
const { isNumber, printInfo, loadConfig, saveConfig, prompt } = require('../evm/utils');
const {
prepareWallet,
Expand Down Expand Up @@ -113,11 +114,7 @@ const programHandler = () => {
program.name('upload-contract').description('Upload CosmWasm contracts');

program.addOption(
new Option('-e, --env <env>', 'environment')
.choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet'])
.default('testnet')
.makeOptionMandatory(true)
.env('ENV'),
new Option('-e, --env <env>', 'environment').choices(CHAIN_ENVIRONMENTS).default('testnet').makeOptionMandatory(true).env('ENV'),
);
program.addOption(new Option('-m, --mnemonic <mnemonic>', 'mnemonic').makeOptionMandatory(true).env('MNEMONIC'));
program.addOption(new Option('-a, --artifactPath <artifactPath>', 'artifact path').makeOptionMandatory(true).env('ARTIFACT_PATH'));
Expand Down
3 changes: 2 additions & 1 deletion cosmwasm/submit-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const {
governanceAddress,
} = require('./utils');
const { isNumber, saveConfig, loadConfig, printInfo, prompt } = require('../evm/utils');
const { CHAIN_ENVIRONMENTS } = require('../common');
const {
StoreCodeProposal,
StoreAndInstantiateContractProposal,
Expand Down Expand Up @@ -251,7 +252,7 @@ const programHandler = () => {
// TODO: combine deploy-contract and submit-proposal options to remove duplicates
program.addOption(
new Option('-e, --env <env>', 'environment')
.choices(['local', 'devnet', 'devnet-amplifier', 'devnet-verifiers', 'stagenet', 'testnet', 'mainnet'])
.choices(CHAIN_ENVIRONMENTS)
.default('devnet-amplifier')
.makeOptionMandatory(true)
.env('ENV'),
Expand Down
2 changes: 1 addition & 1 deletion evm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ node evm/verify-contract.js -e [env] -n [chain] -c TokenManagerProxy --dir /path

Download the pending requests [spreadsheet](https://docs.google.com/spreadsheets/d/1zKH1DINTiz83iXbbZRNRurxxZTaU0r5JS4A1c8b9-9A/edit?resourcekey=&gid=1705825087#gid=1705825087) into a csv format.

`node evm/check-ownership-requests.js -f sheet_path.csv`
`node evm/check-ownership-request.js -f sheet_path.csv`

## Verify AxelarAmplifierGateway contract.
`--address` can be optionally specified (otherwise will default to the value from config).
Expand Down
109 changes: 98 additions & 11 deletions evm/check-ownership-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ const {
} = require('./utils');

const interchainTokenABI = getContractJSON('InterchainToken').abi;
const tokenAddressRowIndex = 1;
const destinationChainsRowIndex = 3;
const contactDetailsRowIndex = 4;
const dustTxRowIndex = 5;
const commentsRowIndex = 6;

async function processCommand(config, options) {
const { file, startingIndex } = options;
Expand All @@ -29,24 +34,31 @@ async function processCommand(config, options) {
validateParameters({ isValidNumber: { startingIndex } });
}

const data = await loadCsvFile(file, startingIndex);
const { columnNames, inputData } = await loadCsvFile(file, startingIndex);
columnNames.forEach((columnName, index) => {
columnNames[index] = columnName.replace(/,/g, '');
});
const data = removeDuplicateEntries(file, columnNames, inputData);
const finalData = copyObject(data);
let totalRowsRemoved = 0;

for (let i = 0; i < data.length; ++i) {
const row = data[i];
const tokenAddress = row[0];
const destinationChainsRaw = row[2].split(',');
const tokenAddress = row[tokenAddressRowIndex];

printInfo(`Verifying data at index ${i + 2} for Token address`, tokenAddress);

const destinationChainsRaw = row[destinationChainsRowIndex].split(',');
const destinationChains = destinationChainsRaw.map((chain) => chain.trim().toLowerCase()).filter((chain) => chain);
const dustTx = row[4];
const dustTx = row[dustTxRowIndex];

validateParameters({ isValidAddress: { tokenAddress } });

const invalidDestinationChains = await verifyChains(config, tokenAddress, destinationChains);
const validDestinationChains = destinationChains.filter((chain) => !invalidDestinationChains.includes(chain));

if (validDestinationChains.length > 0) {
finalData[i - totalRowsRemoved][2] =
finalData[i - totalRowsRemoved][destinationChainsRowIndex] =
validDestinationChains.length === 1 ? `${validDestinationChains[0]}` : `"${validDestinationChains.join(', ')}"`;
} else {
finalData.splice(i - totalRowsRemoved, 1);
Expand All @@ -57,14 +69,14 @@ async function processCommand(config, options) {
const chain = validDestinationChains[0];
const apiUrl = config.chains[chain].explorer.api;
const apiKey = keys.chains[chain].api;
let deploymentTx, isValidDustx;
let deploymentTx, isValidDustTx;

try {
deploymentTx = await getDeploymentTx(apiUrl, apiKey, tokenAddress);
isValidDustx = await verifyDustTx(deploymentTx, dustTx, config.chains);
isValidDustTx = await verifyDustTx(deploymentTx, dustTx, config.chains);
} catch {}

if (!isValidDustx) {
if (!isValidDustTx) {
finalData.splice(i - totalRowsRemoved, 1);
++totalRowsRemoved;
}
Expand All @@ -73,6 +85,64 @@ async function processCommand(config, options) {
await createCsvFile('pending_ownership_requests.csv', finalData);
}

function removeDuplicateEntries(filePath, columnNames, inputData) {
const uniqueArrays = [];
const manualCheckIndices = [];
const subarrayMap = new Map();

// Identify and remove duplicates based on subarray values
inputData.forEach((currentArray, index) => {
const subarray = currentArray.slice(1);
const subarrayKey = subarray.join(',');

if (!subarrayMap.has(subarrayKey)) {
subarrayMap.set(subarrayKey, index);
uniqueArrays.push(currentArray);
} else {
const existingIndex = subarrayMap.get(subarrayKey);

if (existingIndex > index) {
// Remove from uniqueArrays if previously added
uniqueArrays.splice(
uniqueArrays.findIndex((arr) => arr === inputData[existingIndex]),
1,
);
uniqueArrays.push(currentArray);
subarrayMap.set(subarrayKey, index);
}
}
});

// Check for matching values in column 1 across different internal arrays
const seenValues = new Map();
uniqueArrays.forEach((arr, index) => {
const value = arr[tokenAddressRowIndex]; // Check only TokenAddress row
const originalIndex = inputData.indexOf(arr); // Find the original index

if (seenValues.has(value)) {
manualCheckIndices.push([seenValues.get(value), originalIndex]);
} else {
seenValues.set(value, originalIndex);
}
});

if (manualCheckIndices.length !== 0) {
printError('Manually check the following indexes', manualCheckIndices);
}

const updatedData = copyObject(uniqueArrays);
updatedData.forEach((arr) => {
arr[destinationChainsRowIndex] = `"${arr[destinationChainsRowIndex]}"`;
arr[commentsRowIndex] = `"${arr[commentsRowIndex]}"`;

if (!arr[commentsRowIndex]) {
arr[commentsRowIndex] = 'No Comments';
}
});
updateCSVFile(filePath, columnNames, updatedData);
return uniqueArrays;
}

async function verifyDustTx(deploymentTx, dustTx, chains) {
const senderDeploymentTx = await getSenderDeploymentTx(deploymentTx);
const senderDustTx = await getSenderDustTx(dustTx, chains);
Expand Down Expand Up @@ -128,25 +198,39 @@ async function verifyChains(config, tokenAddress, destinationChains) {

validateParameters({ isValidTokenId: { tokenId } });
} catch {
// printWarn(`No Interchain token found for address ${tokenAddress} on chain ${chain}`);
invalidDestinationChains.push(chain);
}
}

return invalidDestinationChains;
}

function updateCSVFile(filePath, columnNames, data) {
if (!data.length) {
printWarn('Not updating the csv file', filePath);
return;
}

const csvContent = [columnNames, ...data].map((row) => row.join(',')).join('\n');
writeCSVData(filePath, csvContent);
}

async function loadCsvFile(filePath, startingIndex = 0) {
const results = [];
let columnNames = [];

try {
const stream = createReadStream(filePath).pipe(csv());

for await (const row of stream) {
if (columnNames.length === 0) {
columnNames = Object.keys(row);
}

results.push(Object.values(row));
}

return results.slice(startingIndex);
return { columnNames, inputData: results.slice(startingIndex) };
} catch (error) {
throw new Error(`Error loading CSV file: ${error}`);
}
Expand All @@ -159,14 +243,17 @@ async function createCsvFile(filePath, data) {
}

const columnNames = ['Token Address', 'Chains to claim token ownership on', 'Telegram Contact details'];
const selectedColumns = [0, 2, 3]; // Indexes of required columns
const selectedColumns = [tokenAddressRowIndex, destinationChainsRowIndex, contactDetailsRowIndex]; // Indexes of required columns

const filteredData = data.map((row) => {
return selectedColumns.map((index) => row[index]);
});

const csvContent = [columnNames, ...filteredData].map((row) => row.join(',')).join('\n');
writeCSVData(filePath, csvContent);
}

function writeCSVData(filePath, csvContent) {
writeFile(filePath, csvContent, { encoding: 'utf8' }, (error) => {
if (error) {
printError('Error writing CSV file:', error);
Expand Down
7 changes: 2 additions & 5 deletions stellar/balances.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { Command, Option } = require('commander');
const { getWallet } = require('./utils');
const { loadConfig } = require('../evm/utils');
const { CHAIN_ENVIRONMENTS } = require('../common');
require('./cli-utils');

async function processCommand(options, _, chain) {
Expand All @@ -13,11 +14,7 @@ if (require.main === module) {
program.name('balances').description('Wallet balance');

program.addOption(
new Option('-e, --env <env>', 'environment')
.choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet'])
.default('testnet')
.makeOptionMandatory(true)
.env('ENV'),
new Option('-e, --env <env>', 'environment').choices(CHAIN_ENVIRONMENTS).default('testnet').makeOptionMandatory(true).env('ENV'),
);

program.addOption(new Option('-p, --privateKey <privateKey>', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY'));
Expand Down
7 changes: 2 additions & 5 deletions stellar/generate-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { execSync } = require('child_process');
const { loadConfig } = require('../evm/utils');
const path = require('path');
const { getNetworkPassphrase } = require('./utils');
const { CHAIN_ENVIRONMENTS } = require('../common');
require('./cli-utils');

function processCommand(options, _, chain) {
Expand All @@ -28,11 +29,7 @@ function main() {
program.name('Generate TypeScript Bindings for Soroban contract').description('Generates TypeScript bindings for a Soroban contract.');

program.addOption(
new Option('-e, --env <env>', 'environment')
.choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet'])
.default('testnet')
.makeOptionMandatory(true)
.env('ENV'),
new Option('-e, --env <env>', 'environment').choices(CHAIN_ENVIRONMENTS).default('testnet').makeOptionMandatory(true).env('ENV'),
);
program.addOption(new Option('--wasmPath <wasmPath>', 'path to the WASM file').makeOptionMandatory(true));
program.addOption(new Option('--contractId <contractId>', 'contract ID').makeOptionMandatory(true));
Expand Down
7 changes: 2 additions & 5 deletions stellar/operators.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const { Contract, Address, nativeToScVal } = require('@stellar/stellar-sdk');
const { Command, Option } = require('commander');
const { getWallet, prepareTransaction, buildTransaction, sendTransaction, estimateCost } = require('./utils');
const { loadConfig, printInfo, parseArgs, validateParameters } = require('../evm/utils');
const { CHAIN_ENVIRONMENTS } = require('../common');
require('./cli-utils');

async function processCommand(options, _, chain) {
Expand Down Expand Up @@ -116,11 +117,7 @@ if (require.main === module) {
program.name('operators').description('Operators contract management');

program.addOption(
new Option('-e, --env <env>', 'environment')
.choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet'])
.default('testnet')
.makeOptionMandatory(true)
.env('ENV'),
new Option('-e, --env <env>', 'environment').choices(CHAIN_ENVIRONMENTS).default('testnet').makeOptionMandatory(true).env('ENV'),
);

program.addOption(new Option('-p, --privateKey <privateKey>', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY'));
Expand Down
26 changes: 26 additions & 0 deletions sui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,29 @@ node sui/transfer-object.js --objectId <object id to be transferred> --recipient

node sui/transfer-object.js --contractName <Can be checked from config> --objectName <picked from config> --recipient <recipient address>
```

## Coins Management

List of coins in the wallet:

```bash
node sui/tokens.js list
```

Merge the coins:

```bash
node sui/tokens.js merge --coin-type <coin type to merge>
```

If coin type is not provided, it will merge all the coins.

Split the coins:

```bash
node sui/tokens.js split --amount <amount> --coin-type <coin type to split> --transfer <recipient address>
```

Note:
- If coin type is not provided, it will split all the coins.
- If transfer address is not provided, it will split the coins in the same wallet. Otherwise, it will transfer the splitted coins to the provided address.
Loading

0 comments on commit d5806e4

Please sign in to comment.