Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support to generate unsigned txs in sui scripts #442

Merged
merged 3 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions sui/deploy-contract.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
const { Command, Option } = require('commander');
const { getLocalDependencies, updateMoveToml, TxBuilder, bcsStructs } = require('@axelar-network/axelar-cgp-sui');
const { toB64 } = require('@mysten/sui/utils');
const { bcs } = require('@mysten/sui/bcs');
const { Transaction } = require('@mysten/sui/transactions');
const { saveConfig, printInfo, validateParameters, writeJSON, getDomainSeparator, loadConfig, getChainConfig } = require('../common');
const { saveConfig, printInfo, validateParameters, getDomainSeparator, loadConfig, getChainConfig } = require('../common');
const {
addBaseOptions,
addOptionsToCommands,
Expand Down Expand Up @@ -342,16 +341,6 @@ async function mainProcessor(args, options, processor) {
await processor(keypair, client, ...args, config, sui, options);

saveConfig(config, options.env);

if (options.offline) {
const { txFilePath } = options;
validateParameters({ isNonEmptyString: { txFilePath } });

const txB64Bytes = toB64(options.txBytes);

writeJSON({ message: options.offlineMessage, status: 'PENDING', unsignedTx: txB64Bytes }, txFilePath);
printInfo(`Unsigned transaction`, txFilePath);
}
}

/**
Expand Down
33 changes: 27 additions & 6 deletions sui/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const {
getRawPrivateKey,
broadcast,
suiClockAddress,
saveGeneratedTx,
} = require('./utils');
const secp256k1 = require('secp256k1');

Expand Down Expand Up @@ -140,7 +141,10 @@ async function callContract(keypair, client, config, chain, contractConfig, args
});
}

await broadcast(client, keypair, tx, 'Message sent');
return {
tx,
message: 'Message sent',
};
}

async function approve(keypair, client, config, chain, contractConfig, args, options) {
Expand Down Expand Up @@ -173,7 +177,10 @@ async function approve(keypair, client, config, chain, contractConfig, args, opt
],
});

await broadcast(client, keypair, tx, 'Approved Messages');
return {
tx,
message: 'Approved Messages',
};
}

async function submitProof(keypair, client, config, chain, contractConfig, args, options) {
Expand Down Expand Up @@ -216,7 +223,10 @@ async function submitProof(keypair, client, config, chain, contractConfig, args,
throw new Error(`Unknown payload type: ${payload}`);
}

await broadcast(client, keypair, tx, 'Submitted Amplifier Proof');
return {
tx,
message: 'Submitted Amplifier Proof',
};
}

async function rotate(keypair, client, config, chain, contractConfig, args, options) {
Expand All @@ -243,7 +253,10 @@ async function rotate(keypair, client, config, chain, contractConfig, args, opti
],
});

await broadcast(client, keypair, tx, 'Rotated Signers');
return {
tx,
message: 'Rotated Signers',
};
}

async function mainProcessor(processor, args, options) {
Expand All @@ -257,9 +270,17 @@ async function mainProcessor(processor, args, options) {
throw new Error('Axelar Gateway package not found.');
}

await processor(keypair, client, config, chain, chain.contracts.AxelarGateway, args, options);
const { tx, message } = await processor(keypair, client, config, chain, chain.contracts.AxelarGateway, args, options);

saveConfig(config, options.env);

if (options.offline) {
const sender = options.sender || keypair.toSuiAddress();
tx.setSender(sender);
await saveGeneratedTx(tx, message, client, options);
} else {
await broadcast(client, keypair, tx, message);
}
}

if (require.main === module) {
Expand Down Expand Up @@ -302,7 +323,7 @@ if (require.main === module) {
mainProcessor(callContract, [destinationChain, destinationAddress, payload], options);
});

addOptionsToCommands(program, addBaseOptions);
addOptionsToCommands(program, addBaseOptions, { offline: true });

program.parse();
}
21 changes: 14 additions & 7 deletions sui/its.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { Command } = require('commander');
const { TxBuilder } = require('@axelar-network/axelar-cgp-sui');
const { loadConfig, saveConfig, getChainConfig } = require('../common/utils');
const { addBaseOptions, addOptionsToCommands, getWallet, printWalletInfo, broadcastFromTxBuilder } = require('./utils');
const { addBaseOptions, addOptionsToCommands, getWallet, printWalletInfo, broadcastFromTxBuilder, saveGeneratedTx } = require('./utils');

async function setupTrustedAddress(keypair, client, contracts, args, options) {
const [trustedChain, trustedAddress] = args;
Expand All @@ -22,13 +22,20 @@ async function setupTrustedAddress(keypair, client, contracts, args, options) {
arguments: [ITS, OwnerCap, trustedAddressesObject],
});

await broadcastFromTxBuilder(txBuilder, keypair, 'Setup Trusted Address');
if (options.offline) {
const tx = txBuilder.tx;
const sender = options.sender || keypair.toSuiAddress();
tx.setSender(sender);
await saveGeneratedTx(tx, `Set trusted address for ${trustedChain} to ${trustedAddress}`, client, options);
} else {
await broadcastFromTxBuilder(txBuilder, keypair, 'Setup Trusted Address');

// Add trusted address to ITS config
if (!contracts.ITS.trustedAddresses) contracts.ITS.trustedAddresses = {};
if (!contracts.ITS.trustedAddresses[trustedChain]) contracts.ITS.trustedAddresses[trustedChain] = [];
// Add trusted address to ITS config
if (!contracts.ITS.trustedAddresses) contracts.ITS.trustedAddresses = {};
if (!contracts.ITS.trustedAddresses[trustedChain]) contracts.ITS.trustedAddresses[trustedChain] = [];

contracts.ITS.trustedAddresses[trustedChain].push(trustedAddress);
contracts.ITS.trustedAddresses[trustedChain].push(trustedAddress);
}
}

async function processCommand(command, chain, args, options) {
Expand Down Expand Up @@ -62,7 +69,7 @@ if (require.main === module) {

program.addCommand(setupTrustedAddressProgram);

addOptionsToCommands(program, addBaseOptions);
addOptionsToCommands(program, addBaseOptions, { offline: true });

program.parse();
}
50 changes: 37 additions & 13 deletions sui/operators.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { Command, Option } = require('commander');
const { Transaction } = require('@mysten/sui/transactions');
const { printError, loadConfig, getChainConfig } = require('../common/utils');
const { loadConfig, getChainConfig } = require('../common/utils');
const {
addBaseOptions,
addOptionsToCommands,
Expand All @@ -9,6 +9,7 @@ const {
printWalletInfo,
broadcast,
findOwnedObjectIdByType,
saveGeneratedTx,
} = require('./utils');

function operatorMoveCall(contractConfig, gasServiceConfig, operatorCapId, tx, moveCall) {
Expand Down Expand Up @@ -50,7 +51,10 @@ async function collectGas(keypair, client, gasServiceConfig, contractConfig, arg
});
});

await broadcast(client, keypair, tx, 'Gas Collected');
return {
tx,
message: 'Gas Collected',
};
}

async function refund(keypair, client, gasServiceConfig, contractConfig, args, options) {
Expand Down Expand Up @@ -78,7 +82,10 @@ async function refund(keypair, client, gasServiceConfig, contractConfig, args, o
});
});

await broadcast(client, keypair, tx, 'Refunded Gas');
return {
tx,
message: 'Refunded Gas',
};
}

async function storeCap(keypair, client, gasServiceConfig, contractConfig, args, options) {
Expand All @@ -95,7 +102,10 @@ async function storeCap(keypair, client, gasServiceConfig, contractConfig, args,
typeArguments: [`${gasServiceConfig.address}::gas_service::GasCollectorCap`],
});

await broadcast(client, keypair, tx, 'Stored Capability');
return {
tx,
message: 'Stored Capability',
};
}

async function addOperator(keypair, client, gasServiceConfig, contractConfig, args, options) {
Expand All @@ -111,7 +121,10 @@ async function addOperator(keypair, client, gasServiceConfig, contractConfig, ar
arguments: [tx.object(operatorsObjectId), tx.object(ownerCapObjectId), tx.pure.address(newOperatorAddress)],
});

await broadcast(client, keypair, tx, 'Added Operator');
return {
tx,
message: 'Added Operator',
};
}

async function removeCap(keypair, client, gasServiceConfig, contractConfig, args, options) {
Expand All @@ -132,11 +145,10 @@ async function removeCap(keypair, client, gasServiceConfig, contractConfig, args

tx.transferObjects([cap], capReceiver);

try {
await broadcast(client, keypair, tx, 'Removed Capability');
} catch (e) {
printError('RemoveCap Error', e.message);
}
return {
tx,
message: 'Removed Capability',
};
}

async function removeOperator(keypair, client, gasServiceConfig, contractConfig, args, options) {
Expand All @@ -152,7 +164,10 @@ async function removeOperator(keypair, client, gasServiceConfig, contractConfig,
arguments: [tx.object(operatorsObjectId), tx.object(ownerCapObjectId), tx.pure.address(operatorAddress)],
});

await broadcast(client, keypair, tx, 'Removed Operator');
return {
tx,
message: 'Removed Operator',
};
}

async function mainProcessor(processor, args, options) {
Expand All @@ -172,7 +187,16 @@ async function mainProcessor(processor, args, options) {

const [keypair, client] = getWallet(chain, options);
await printWalletInfo(keypair, client, chain, options);
await processor(keypair, client, gasServiceConfig, contractConfig, args, options);

const { tx, message } = await processor(keypair, client, gasServiceConfig, contractConfig, args, options);

if (options.offline) {
const sender = options.sender || keypair.toSuiAddress();
tx.setSender(sender);
await saveGeneratedTx(tx, message, client, options);
} else {
await broadcast(client, keypair, tx, message);
}
}

if (require.main === module) {
Expand Down Expand Up @@ -231,7 +255,7 @@ if (require.main === module) {
.action((messageId, options) => mainProcessor(refund, [messageId], options)),
);

addOptionsToCommands(program, addBaseOptions);
addOptionsToCommands(program, addBaseOptions, { offline: true });

program.parse();
}
13 changes: 11 additions & 2 deletions sui/transfer-object.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { Transaction } = require('@mysten/sui/transactions');
const { Command, Option } = require('commander');
const { loadConfig, validateParameters, getChainConfig } = require('../common/utils');
const { getWallet, printWalletInfo, addExtendedOptions, broadcast } = require('./utils');
const { getWallet, printWalletInfo, addExtendedOptions, broadcast, saveGeneratedTx } = require('./utils');

async function processCommand(chain, options) {
const [keypair, client] = getWallet(chain, options);
Expand Down Expand Up @@ -38,7 +38,13 @@ async function processCommand(chain, options) {
const tx = new Transaction();
tx.transferObjects([`${objectId}`], tx.pure.address(recipient));

await broadcast(client, keypair, tx, 'Transferred Object');
if (options.offline) {
const sender = options.sender || keypair.toSuiAddress();
tx.setSender(sender);
await saveGeneratedTx(tx, 'Transferred Object', client, options);
} else {
await broadcast(client, keypair, tx, 'Transferred Object');
}
}

async function mainProcessor(options, processor) {
Expand All @@ -57,6 +63,9 @@ if (require.main === module) {
program.addOption(new Option('--objectId <objectId>', 'object id to be transferred'));
program.addOption(new Option('--objectName <objectName>', 'object name to be transferred'));
program.addOption(new Option('--recipient <recipient>', 'recipient to transfer object to').makeOptionMandatory(true));
program.addOption(new Option('--sender <sender>', 'transaction sender'));
program.addOption(new Option('--offline', 'store tx block for sign'));
program.addOption(new Option('--txFilePath <file>', 'unsigned transaction will be stored'));

program.action(async (options) => {
mainProcessor(options, processCommand);
Expand Down
6 changes: 6 additions & 0 deletions sui/utils/cli-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ const addBaseOptions = (program, options = {}) => {
program.addOption(new Option('--address <address>', 'override contract address'));
}

if (options.offline) {
program.addOption(new Option('--sender <sender>', 'transaction sender'));
program.addOption(new Option('--offline', 'store tx block for sign'));
program.addOption(new Option('--txFilePath <file>', 'unsigned transaction will be stored'));
}

return program;
};

Expand Down
12 changes: 5 additions & 7 deletions sui/utils/upgrade-utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { bcs } = require('@mysten/bcs');
const { fromB64 } = require('@mysten/bcs');
const { printInfo, validateParameters } = require('../../common/utils');
const { getObjectIdsByObjectTypes, suiPackageAddress, moveDir } = require('./utils');
const { getObjectIdsByObjectTypes, suiPackageAddress, moveDir, saveGeneratedTx } = require('./utils');
const UPGRADE_POLICIES = {
code_upgrade: 'only_additive_upgrades',
dependency_upgrade: 'only_dep_upgrades',
Expand All @@ -24,7 +24,6 @@ async function upgradePackage(client, keypair, packageToUpgrade, contractConfig,
const { packageDir, packageName } = packageToUpgrade;
const { modules, dependencies, digest } = await builder.getContractBuild(packageDir, moveDir);
const { offline } = options;
const sender = options.sender || keypair.toSuiAddress();
const upgradeCap = contractConfig.objects?.UpgradeCap;
const digestHash = options.digest ? fromB64(options.digest) : digest;
const policy = getUpgradePolicyId(options.policy);
Expand All @@ -50,13 +49,12 @@ async function upgradePackage(client, keypair, packageToUpgrade, contractConfig,
arguments: [cap, receipt],
});

tx.setSender(sender);
const txBytes = await tx.build({ client });

if (offline) {
options.txBytes = txBytes;
options.offlineMessage = `Transaction to upgrade ${packageDir}`;
const sender = options.sender || keypair.toSuiAddress();
tx.setSender(sender);
await saveGeneratedTx(tx, `Transaction to upgrade ${packageDir}`, client, options);
} else {
const txBytes = await tx.build({ client });
const signature = (await keypair.signTransaction(txBytes)).signature;
const result = await client.executeTransactionBlock({
transactionBlock: txBytes,
Expand Down
16 changes: 14 additions & 2 deletions sui/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

const { ethers } = require('hardhat');
const toml = require('toml');
const { printInfo, printError, printWarn } = require('../../common/utils');
const { printInfo, printError, printWarn, validateParameters, writeJSON } = require('../../common/utils');
const {
BigNumber,
utils: { arrayify, hexlify, toUtf8Bytes, keccak256 },
constants: { HashZero },
} = ethers;
const fs = require('fs');
const { fromB64 } = require('@mysten/bcs');
const { fromB64, toB64 } = require('@mysten/bcs');
const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate');
const {
updateMoveToml,
Expand Down Expand Up @@ -270,6 +270,17 @@ const checkTrustedAddresses = (trustedAddresses, destinationChain) => {
}
};

const saveGeneratedTx = async (tx, message, client, options) => {
const { txFilePath } = options;
validateParameters({ isNonEmptyString: { txFilePath } });

const txBytes = await tx.build({ client });
const txB64Bytes = toB64(txBytes);

writeJSON({ message, status: 'PENDING', unsignedTx: txB64Bytes }, txFilePath);
blockchainguyy marked this conversation as resolved.
Show resolved Hide resolved
printInfo(`Unsigned transaction`, txFilePath);
};

module.exports = {
suiCoinId,
getAmplifierSigners,
Expand All @@ -294,4 +305,5 @@ module.exports = {
checkTrustedAddresses,
parseDiscoveryInfo,
parseGatewayInfo,
saveGeneratedTx,
};
Loading