Skip to content

Commit

Permalink
Merge branch 'main' into monitoring/add-to-project
Browse files Browse the repository at this point in the history
  • Loading branch information
blockchainguyy authored Oct 26, 2023
2 parents 3a26a69 + 3f42aeb commit 5fecce4
Show file tree
Hide file tree
Showing 17 changed files with 689 additions and 1,160 deletions.
162 changes: 82 additions & 80 deletions axelar-chains-config/info/mainnet.json

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions axelar-chains-config/info/testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,8 @@
"gasOptions": {
"gasLimit": 300000000
},
"confirmations": 3
"confirmations": 3,
"eip1559": true
},
"linea": {
"name": "Linea",
Expand Down Expand Up @@ -1646,11 +1647,7 @@
"gasOptions": {
"gasLimit": 8000000
},
"skipRevertTests": true,
"staticGasOptions": {
"gasLimit": 3000000,
"gasPrice": 1000000000
}
"skipRevertTests": true
},
"scroll": {
"name": "Scroll",
Expand Down
107 changes: 107 additions & 0 deletions evm/LedgerSigner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
'use strict';

const { ethers } = require('hardhat');
const {
BigNumber,
Signer,
VoidSigner,
utils: { serializeTransaction },
} = ethers;
const TransportNodeHid = require('@ledgerhq/hw-transport-node-hid').default;
const Eth = require('@ledgerhq/hw-app-eth').default;

const { printInfo } = require('./utils');

class LedgerSigner extends Signer {
constructor(provider, path = "m/44'/60'/0'/0/0") {
super();
this.path = path;
this.provider = provider;
}

async connect(provider = null) {
if (provider) {
this.provider = provider;
}

this.transport = await TransportNodeHid.open();
this.eth = new Eth(this.transport);
}

async getAddress() {
if (!this.eth) await this.connect();
const result = await this.eth.getAddress(this.path);
return result.address;
}

async signMessage(message) {
if (!this.eth) await this.connect();

if (typeof message === 'string') {
message = ethers.utils.toUtf8Bytes(message);
}

const messageHex = ethers.utils.hexlify(message).substring(2);

const sig = await this.eth.signPersonalMessage(this.path, messageHex);

return ethers.utils.joinSignature(await this._fixSignature(sig, 2, 1));
}

async signTransaction(tx) {
if (!this.eth) await this.connect();

delete tx.from;

tx = await ethers.utils.resolveProperties(tx);

console.log('Unsigned tx', tx);

const rawTx = serializeTransaction(tx).substring(2);

const sig = await this._fixSignature(await this.eth.signTransaction(this.path, rawTx, null), tx.type, tx.chainId);

const signedTx = serializeTransaction(tx, sig);

printInfo('Signed Tx', signedTx);

return signedTx;
}

async populateTransaction(tx) {
if (!this.eth) await this.connect();

return new VoidSigner(await this.getAddress(), this.provider).populateTransaction(tx);
}

async _fixSignature(signature, type, chainId) {
let v = BigNumber.from('0x' + signature.v).toNumber();

if (type === 2) {
// EIP-1559 transaction. Nothing to do.
// v is already returned as 0 or 1 by Ledger for Type 2 txs
} else {
// Undefined or Legacy Type 0 transaction. Ledger computes EIP-155 sig.v computation incorrectly in this case
// v in {0,1} + 2 * chainId + 35
// Ledger gives this value mod 256
// So from that, compute whether v is 0 or 1 and then add to 2 * chainId + 35 without doing a mod
v = 2 * chainId + 35 + ((v + 256 * 100000000000 - (2 * chainId + 35)) % 256);
}

return {
r: '0x' + signature.r,
s: '0x' + signature.s,
v,
};
}

disconnect() {
if (this.transport) {
this.transport.close();
}
}
}

module.exports = {
LedgerSigner,
};
48 changes: 31 additions & 17 deletions evm/broadcast-transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,38 @@ const {
providers: { getDefaultProvider },
} = ethers;

const { printError, printInfo, printWarn, prompt, mainProcessor } = require('./utils');
const { printError, printInfo, printWarn, getConfigByChainId, prompt, loadConfig } = require('./utils');
const { sendTransaction, getSignedTx, storeSignedTx } = require('./sign-utils');

async function processCommand(_, chain, options) {
const { filePath, rpc } = options;
async function processCommand(config, _, options, file) {
const { rpc } = options;

const transaction = await getSignedTx(file);
const parsedTx = ethers.utils.parseTransaction(transaction.signedTx);

const chain = getConfigByChainId(parsedTx.chainId, config);

const provider = getDefaultProvider(rpc || chain.rpc);

if (parsedTx.chainId !== transaction.unsignedTx.chainId) {
printError(
`ChainId mismatch: signed tx chain id ${parsedTx.chainId} doesn't match unsigned tx chain id ${transaction.unsignedTx.chainId}`,
);
return;
}

if (
prompt(
`Proceed with the broadcasting of all pending signed transactions for file ${chalk.green(
options.filePath,
)} on chain ${chalk.green(chain.name)}`,
`Proceed with the broadcasting of all pending signed transactions for file ${chalk.green(file)} on chain ${chalk.green(
chain.name,
)}`,
options.yes,
)
) {
return;
}

if (!filePath) {
throw new Error('FilePath is not provided in user info');
}

const transaction = await getSignedTx(filePath);

if (transaction.status === 'PENDING') {
if (transaction.status !== 'SUCCESS') {
printInfo('Broadcasting transaction', JSON.stringify(transaction.unsignedTx, null, 2));

// Send the signed transaction
Expand All @@ -46,29 +52,37 @@ async function processCommand(_, chain, options) {
printError('Error broadcasting tx', error);
}

storeSignedTx(filePath, transaction);
storeSignedTx(file, transaction);
} else {
printWarn('Skipping broadcast, transaction status is', transaction.status);
}
}

async function main(options) {
await mainProcessor(options, processCommand);
const config = loadConfig(options.env);
const { files } = options;

if (!files || files.length === 0) {
throw new Error('FilePath is not provided in user info');
}

for (const file of files) {
await processCommand(config, null, options, file);
}
}

const program = new Command();

program.name('broadcast-transactions').description('Broadcast all the pending signed transactions of the signer');

program.addOption(new Option('--filePath <filePath>', 'The file where the signed tx are stored').makeOptionMandatory(true));
program.addOption(new Option('--files [files...]', 'The file where the signed tx are stored').makeOptionMandatory(true));
program.addOption(
new Option('-e, --env <env>', 'environment')
.choices(['local', 'devnet', 'stagenet', 'testnet', 'mainnet'])
.default('testnet')
.makeOptionMandatory(true)
.env('ENV'),
);
program.addOption(new Option('-n, --chainName <chainName>', 'chain names').makeOptionMandatory(true));
program.addOption(new Option('-r, --rpc <rpc>', 'The chain rpc'));
program.addOption(new Option('-y, --yes', 'skip prompts'));

Expand Down
3 changes: 2 additions & 1 deletion evm/check-wallet-balance.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ async function processCommand(_, chain, options) {
const gasLimit = BigNumber.from(staticGasOptions.gasLimit);
const gasPrice = BigNumber.from(staticGasOptions.gasPrice);
const minRequiredBalance = gasLimit * gasPrice * 1.5;
printError(`${chain.name} minimum required Balance`, `${minRequiredBalance / 1e18}`);

const nonceData = getNonceFileData();
const nonces = nonceData[options.env][chainName];

Expand All @@ -36,7 +38,6 @@ async function processCommand(_, chain, options) {
const balance = await provider.getBalance(address);

if (balance < minRequiredBalance) {
printError(`${chain.name} minimum required Balance`, `${minRequiredBalance / 1e18}`);
printError(`${chain.name} Wallet Balance for ${address} is`, `${balance / 1e18}`);
}
}
Expand Down
3 changes: 2 additions & 1 deletion evm/deploy-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
printInfo,
printWarn,
printError,
copyObject,
isString,
isNumber,
isAddressArray,
Expand Down Expand Up @@ -258,7 +259,7 @@ async function processCommand(config, chain, options) {
printInfo('Pre-deploy Contract bytecode hash', predeployCodehash);

const constructorArgs = await getConstructorArgs(contractName, chain, wallet, options);
const gasOptions = JSON.parse(JSON.stringify(contractConfig.gasOptions || chain.gasOptions || {}));
const gasOptions = copyObject(contractConfig.gasOptions || chain.gasOptions || {});

// Some chains require a gas adjustment
if (env === 'mainnet' && !gasOptions.gasPrice && (chain.name === 'Fantom' || chain.name === 'Binance' || chain.name === 'Polygon')) {
Expand Down
6 changes: 3 additions & 3 deletions evm/deploy-gateway-v6.2.x.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,8 @@ async function upgrade(_, chain, options) {

printInfo('Upgrading to implementation', contractConfig.implementation);
printInfo('New Implementation codehash', implementationCodehash);
printInfo('Governance', governance);
printInfo('Mint limiter', mintLimiter);
printInfo('Setup params', setupParams);

const gasOptions = contractConfig.gasOptions || chain.gasOptions || {};
Expand All @@ -434,7 +436,7 @@ async function upgrade(_, chain, options) {
const { baseTx, signedTx } = await signTransaction(wallet, chain, tx, options);

if (offline) {
const filePath = `./tx/signed-tx-${env}-${chainName}-gateway-upgrade-address-${address}-nonce-${baseTx.nonce}.json`;
const filePath = `./tx/signed-tx-${env}-gateway-upgrade-${chainName}-address-${address}-nonce-${baseTx.nonce}.json`;
printInfo(`Storing signed Tx offline in file ${filePath}`);

// Storing the fields in the data that will be stored in file
Expand All @@ -446,8 +448,6 @@ async function upgrade(_, chain, options) {
};

storeSignedTx(filePath, data);

options.nonceOffset = (options.nonceOffset || 0) + 1;
} else {
const newImplementation = await gateway.implementation();
printInfo('New implementation', newImplementation);
Expand Down
29 changes: 27 additions & 2 deletions evm/governance.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
const { Command, Option } = require('commander');
const {
printInfo,
copyObject,
printWalletInfo,
isValidTimeFormat,
dateToEta,
Expand Down Expand Up @@ -62,7 +63,7 @@ async function getGatewaySetupParams(governance, gateway, contracts, options) {
}

async function processCommand(_, chain, options) {
const { contractName, address, action, date, privateKey, yes } = options;
const { env, contractName, address, action, date, privateKey, yes } = options;

const contracts = chain.contracts;
const contractConfig = contracts[contractName];
Expand Down Expand Up @@ -103,7 +104,13 @@ async function processCommand(_, chain, options) {

const governance = new Contract(governanceAddress, IGovernance.abi, wallet);

const gasOptions = contractConfig?.gasOptions || chain?.gasOptions || { gasLimit: 5e6 };
const gasOptions = copyObject(contractConfig?.gasOptions || chain?.gasOptions || { gasLimit: 5e6 });

// Some chains require a gas adjustment
if (env === 'mainnet' && !gasOptions.gasPrice && (chain.name === 'Fantom' || chain.name === 'Binance' || chain.name === 'Polygon')) {
gasOptions.gasPrice = Math.floor((await provider.getGasPrice()) * 1.4);
}

printInfo('Gas options', JSON.stringify(gasOptions, null, 2));

printInfo('Proposal Action', action);
Expand Down Expand Up @@ -464,6 +471,23 @@ async function processCommand(_, chain, options) {
break;
}

case 'cancelUpgrade': {
const eta = dateToEta(date);
const implementation = options.implementation || chain.contracts.AxelarGateway?.implementation;
const newGatewayImplementationCodeHash = await getBytecodeHash(implementation, chain.name, provider);
const gateway = new Contract(target, IGateway.abi, wallet);
const setupParams = await getGatewaySetupParams(governance, gateway, contracts, options);
calldata = gateway.interface.encodeFunctionData('upgrade', [implementation, newGatewayImplementationCodeHash, setupParams]);

const commandType = 1;
const types = ['uint256', 'address', 'bytes', 'uint256', 'uint256'];
const values = [commandType, target, calldata, nativeValue, eta];

gmpPayload = defaultAbiCoder.encode(types, values);

break;
}

case 'withdraw': {
if (!isValidTimeFormat(date)) {
throw new Error(`Invalid ETA: ${date}. Please pass the eta in the format YYYY-MM-DDTHH:mm:ss`);
Expand Down Expand Up @@ -609,6 +633,7 @@ program.addOption(
'gatewayUpgrade',
'submitUpgrade',
'executeUpgrade',
'cancelUpgrade',
'withdraw',
'getProposalEta',
]),
Expand Down
14 changes: 10 additions & 4 deletions evm/multisig.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ async function processCommand(_, chain, options) {

if (!offline) {
await preExecutionChecks(multisigContract, action, wallet, multisigTarget, multisigCalldata, 0, yes);

// loop over each token
for (let i = 0; i < symbolsArray.length; i++) {
const token = await gateway.tokenAddresses(symbolsArray[i]);
const limit = await gateway.tokenMintLimit(token);
printInfo(`Token ${symbolsArray[i]} address`, token);
printInfo(`Token ${symbolsArray[i]} limit`, limit);
}
}

tx = await multisigContract.populateTransaction.executeContract(multisigTarget, multisigCalldata, 0, gasOptions);
Expand Down Expand Up @@ -284,7 +292,7 @@ async function processCommand(_, chain, options) {
const { baseTx, signedTx } = await signTransaction(wallet, chain, tx, options);

if (offline) {
const filePath = `./tx/signed-tx-${env}-${chain.name.toLowerCase()}-multisig-${action}-address-${walletAddress}-nonce-${
const filePath = `./tx/signed-tx-${env}-multisig-${action}-${chain.name.toLowerCase()}-address-${walletAddress}-nonce-${
baseTx.nonce
}.json`;
printInfo(`Storing signed Tx offline in file ${filePath}`);
Expand All @@ -298,13 +306,11 @@ async function processCommand(_, chain, options) {
};

storeSignedTx(filePath, data);

options.nonceOffset = (options.nonceOffset || 0) + 1;
}
}

async function main(options) {
await mainProcessor(options, processCommand);
await mainProcessor(options, processCommand, false);
}

const program = new Command();
Expand Down
Loading

0 comments on commit 5fecce4

Please sign in to comment.