@tessellatedgeometry/tezos-msig-cli
Version:
CLI Client for Tezos timelock multisig.
223 lines • 15.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.execute = exports.submit = exports.rotateKey = exports.cancel = exports.deployMultisig = exports.cancelbytesToSubmit = exports.keyRotationbytesToSubmit = exports.bytesToSubmit = void 0;
const utils_1 = __importDefault(require("./utils"));
const helpers_1 = require("./helpers");
const conseiljs_1 = require("conseiljs");
const operation_fee_estimator_1 = __importDefault(require("./operation-fee-estimator"));
const constants_1 = __importDefault(require("./constants"));
const CONTRACT_SOURCE = `${__dirname}/msig-timelock.tz`;
const bytesToSubmit = async (operation, nodeUrl, operationId, multiSigContractAddress, attemptAutomatic) => {
const chainId = await helpers_1.getChainId(nodeUrl);
const actualOperationId = operationId
? operationId
: (await helpers_1.getOperationId(multiSigContractAddress, nodeUrl)) + 1;
const lambda = helpers_1.compileOperation(operation);
const michelson = `Pair "${chainId}" (Pair ${actualOperationId} ${lambda})`;
utils_1.default.print('Data to encode');
utils_1.default.print(`Pair "${chainId}" (Pair ${actualOperationId} ${lambda})'`);
utils_1.default.print(``);
utils_1.default.print('Encode bytes with: ');
utils_1.default.print(`tezos-client -E ${nodeUrl} hash data 'Pair "${chainId}" (Pair ${actualOperationId} ${lambda})' of type 'pair chain_id (pair nat (lambda unit (list operation)))'`);
utils_1.default.print('');
utils_1.default.print(`Verify these bytes with: `);
utils_1.default.print(`tezos-client -E ${nodeUrl} unpack michelson data 0x<BYTES>`);
utils_1.default.print('');
utils_1.default.print(`Sign these bytes with: `);
utils_1.default.print(`tezos-client -E ${nodeUrl} sign bytes 0x<BYTES> for <KEY>`);
utils_1.default.print('');
if (attemptAutomatic) {
const hex = conseiljs_1.TezosMessageUtils.writePackedData(michelson, 'pair (chain_id) (pair (nat) (lambda unit (list operation)))', conseiljs_1.TezosParameterFormat.Michelson);
utils_1.default.print(`[Experimental] I tried to encode the bytes myself. Here is what I came up with: `);
utils_1.default.print(hex);
utils_1.default.print('');
}
};
exports.bytesToSubmit = bytesToSubmit;
const keyRotationbytesToSubmit = async (threshold, keyList, nodeUrl, operationId, multiSigContractAddress, attemptAutomatic) => {
const chainId = await helpers_1.getChainId(nodeUrl);
const actualOperationId = operationId ? operationId : (await helpers_1.getOperationId(multiSigContractAddress, nodeUrl)) + 1;
const keyListMichelson = keyList.reduce((previous, current) => {
return `${previous} "${current}";`;
}, '');
const michelson = `Pair "${chainId}" (Pair ${actualOperationId} (Pair ${threshold} {${keyListMichelson}}))`;
utils_1.default.print('Data to encode');
utils_1.default.print(`${michelson}`);
utils_1.default.print(``);
utils_1.default.print('Encode bytes with: ');
utils_1.default.print(`tezos-client -E ${nodeUrl} hash data '${michelson}' of type 'pair chain_id (pair nat (pair nat (list key)))'`);
utils_1.default.print('');
utils_1.default.print(`Verify these bytes with: `);
utils_1.default.print(`tezos-client -E ${nodeUrl} unpack michelson data 0x<BYTES>`);
utils_1.default.print('');
utils_1.default.print(`Sign these bytes with: `);
utils_1.default.print(`tezos-client -E ${nodeUrl} sign bytes 0x<BYTES> for <KEY>`);
utils_1.default.print('');
if (attemptAutomatic) {
const hex = conseiljs_1.TezosMessageUtils.writePackedData(michelson, 'pair chain_id (pair nat (pair nat (list key)))', conseiljs_1.TezosParameterFormat.Michelson);
utils_1.default.print(`[Experimental] I tried to encode the bytes myself. Here is what I came up with: `);
utils_1.default.print(hex);
utils_1.default.print('');
}
};
exports.keyRotationbytesToSubmit = keyRotationbytesToSubmit;
const cancelbytesToSubmit = async (operationIdToCancel, nodeUrl, operationId, multiSigContractAddress, attemptAutomatic) => {
const chainId = await helpers_1.getChainId(nodeUrl);
const actualOperationId = operationId ? operationId : (await helpers_1.getOperationId(multiSigContractAddress, nodeUrl)) + 1;
const michelson = `Pair "${chainId}" (Pair ${actualOperationId} ${operationIdToCancel})`;
utils_1.default.print('Data to encode');
utils_1.default.print(`${michelson}`);
utils_1.default.print(``);
utils_1.default.print('Encode bytes with: ');
utils_1.default.print(`tezos-client -E ${nodeUrl} hash data '${michelson}' of type 'pair chain_id (pair nat nat)'`);
utils_1.default.print('');
utils_1.default.print(`Verify these bytes with: `);
utils_1.default.print(`tezos-client -E ${nodeUrl} unpack michelson data 0x<BYTES>`);
utils_1.default.print('');
utils_1.default.print(`Sign these bytes with: `);
utils_1.default.print(`tezos-client -E ${nodeUrl} sign bytes 0x<BYTES> for <KEY>`);
utils_1.default.print('');
if (attemptAutomatic) {
const hex = conseiljs_1.TezosMessageUtils.writePackedData(michelson, 'pair chain_id (pair nat nat)', conseiljs_1.TezosParameterFormat.Michelson);
utils_1.default.print(`[Experimental] I tried to encode the bytes myself. Here is what I came up with: `);
utils_1.default.print(hex);
utils_1.default.print('');
}
};
exports.cancelbytesToSubmit = cancelbytesToSubmit;
const deployMultisig = async (timelockSeconds, threshold, publicKeys, nodeUrl, privateKey) => {
const source = helpers_1.loadContract(CONTRACT_SOURCE);
const sortedPublicKeys = publicKeys.sort();
const michelsonPublicKeyList = sortedPublicKeys.reduce((previous, current) => {
return `${previous} "${current}"`;
}, '');
const storage = `(Pair(Pair 0 { ${michelsonPublicKeyList}}) (Pair ${threshold} (Pair { } ${timelockSeconds})))`;
const keyStore = await utils_1.default.keyStoreFromPrivateKey(privateKey);
const signer = await utils_1.default.signerFromKeyStore(keyStore);
utils_1.default.print(`Deploying from: ${keyStore.publicKeyHash} `);
utils_1.default.print(`Storage: ${storage} `);
await utils_1.default.revealAccountIfNeeded(nodeUrl, keyStore, signer);
let counter = await conseiljs_1.TezosNodeReader.getCounterForAccount(nodeUrl, keyStore.publicKeyHash);
counter++;
const deployResult = await helpers_1.deployContract(nodeUrl, source, storage, keyStore, counter);
utils_1.default.print(`Deployed!`);
utils_1.default.print(`Address: ${deployResult.contractAddress} `);
utils_1.default.print(`Operation Hash: ${deployResult.operationHash} `);
};
exports.deployMultisig = deployMultisig;
const cancel = async (operationIdToCancel, addresses, signatures, operationId, multiSigContractAddress, nodeUrl, privateKey, attemptAutomatic) => {
const keyStore = await utils_1.default.keyStoreFromPrivateKey(privateKey);
const signer = await utils_1.default.signerFromKeyStore(keyStore);
const actualOperationId = operationId ? operationId : (await helpers_1.getOperationId(multiSigContractAddress, nodeUrl)) + 1;
utils_1.default.print(`Submitting cancel operation from: ${keyStore.publicKeyHash} `);
utils_1.default.print(`Using operation ID: ${actualOperationId} `);
await utils_1.default.revealAccountIfNeeded(nodeUrl, keyStore, signer);
const counter = await conseiljs_1.TezosNodeReader.getCounterForAccount(nodeUrl, keyStore.publicKeyHash);
const chainId = await helpers_1.getChainId(nodeUrl);
let signaturesMap = '';
for (let i = 0; i < addresses.length; i++) {
const address = addresses[i];
const signature = signatures[i];
signaturesMap += `Elt "${address}" "${signature}"; `;
}
const param = `Pair { ${signaturesMap} } (Pair "${chainId}" (Pair ${actualOperationId} ${operationIdToCancel}))`;
utils_1.default.print(`Use tezos-client to submit the operation manually.`);
utils_1.default.print(`tezos-client -E ${nodeUrl} transfer 0 from ${keyStore.publicKeyHash} to ${multiSigContractAddress} --arg '${param}' --entrypoint 'cancel'`);
utils_1.default.print('');
if (attemptAutomatic) {
utils_1.default.print(`Attempting to inject automatically:`);
const operation = conseiljs_1.TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, counter + 1, multiSigContractAddress, 0, 0, constants_1.default.storageLimit, constants_1.default.gasLimit, 'cancel', `${param} `, conseiljs_1.TezosParameterFormat.Michelson);
const operationFeeEstimator = new operation_fee_estimator_1.default(nodeUrl);
const operationsWithFees = await operationFeeEstimator.estimateAndApplyFees([operation]);
const nodeResult = await conseiljs_1.TezosNodeWriter.sendOperation(nodeUrl, operationsWithFees, signer);
const hash = nodeResult.operationGroupID.replace(/"/g, '');
utils_1.default.print(`Executed with hash: ${hash} `);
}
};
exports.cancel = cancel;
const rotateKey = async (threshold, keyList, addresses, signatures, operationId, multiSigContractAddress, nodeUrl, privateKey, attemptAutomatic) => {
const keyStore = await utils_1.default.keyStoreFromPrivateKey(privateKey);
const signer = await utils_1.default.signerFromKeyStore(keyStore);
const actualOperationId = operationId ? operationId : (await helpers_1.getOperationId(multiSigContractAddress, nodeUrl)) + 1;
utils_1.default.print(`Submitting rotate from: ${keyStore.publicKeyHash} `);
utils_1.default.print(`Using operation ID: ${actualOperationId} `);
await utils_1.default.revealAccountIfNeeded(nodeUrl, keyStore, signer);
const counter = await conseiljs_1.TezosNodeReader.getCounterForAccount(nodeUrl, keyStore.publicKeyHash);
const chainId = await helpers_1.getChainId(nodeUrl);
const keyListMichelson = keyList.reduce((previous, current) => {
return `${previous} "${current}";`;
}, '');
let signaturesMap = '';
for (let i = 0; i < addresses.length; i++) {
const address = addresses[i];
const signature = signatures[i];
signaturesMap += `Elt "${address}" "${signature}"; `;
}
const param = `Pair { ${signaturesMap} } (Pair "${chainId}" (Pair ${actualOperationId} (Pair ${threshold} {${keyListMichelson}})))`;
utils_1.default.print(`Use tezos-client to submit the operation manually.`);
utils_1.default.print(`tezos-client -E ${nodeUrl} transfer 0 from ${keyStore.publicKeyHash} to ${multiSigContractAddress} --arg '${param}' --entrypoint 'rotate'`);
utils_1.default.print('');
if (attemptAutomatic) {
utils_1.default.print(`Attempting to inject automatically:`);
const operation = conseiljs_1.TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, counter + 1, multiSigContractAddress, 0, 0, constants_1.default.storageLimit, constants_1.default.gasLimit, 'rotate', `${param} `, conseiljs_1.TezosParameterFormat.Michelson);
const operationFeeEstimator = new operation_fee_estimator_1.default(nodeUrl);
const operationsWithFees = await operationFeeEstimator.estimateAndApplyFees([operation]);
const nodeResult = await conseiljs_1.TezosNodeWriter.sendOperation(nodeUrl, operationsWithFees, signer);
const hash = nodeResult.operationGroupID.replace(/"/g, '');
utils_1.default.print(`Executed with hash: ${hash} `);
}
};
exports.rotateKey = rotateKey;
const submit = async (operation, addresses, signatures, operationId, multiSigContractAddress, nodeUrl, privateKey, attemptAutomatic) => {
const keyStore = await utils_1.default.keyStoreFromPrivateKey(privateKey);
const signer = await utils_1.default.signerFromKeyStore(keyStore);
utils_1.default.print(`Submitting operation from: ${keyStore.publicKeyHash} `);
utils_1.default.print(`Using operation ID: ${operationId} `);
await utils_1.default.revealAccountIfNeeded(nodeUrl, keyStore, signer);
const actualOperationId = operationId ? operationId : (await helpers_1.getOperationId(multiSigContractAddress, nodeUrl)) + 1;
utils_1.default.print(`Using operation ID: ${actualOperationId} `);
const counter = await conseiljs_1.TezosNodeReader.getCounterForAccount(nodeUrl, keyStore.publicKeyHash);
const chainId = await helpers_1.getChainId(nodeUrl);
const lambda = helpers_1.compileOperation(operation);
let signaturesMap = '';
for (let i = 0; i < addresses.length; i++) {
const address = addresses[i];
const signature = signatures[i];
signaturesMap += `Elt "${address}" "${signature}"; `;
}
const param = `Pair { ${signaturesMap} } (Pair "${chainId}" (Pair ${actualOperationId} ${lambda}))`;
utils_1.default.print(`Use tezos-client to submit the operation manually.`);
utils_1.default.print(`tezos-client -E ${nodeUrl} transfer 0 from ${keyStore.publicKeyHash} to ${multiSigContractAddress} --arg '${param}' --entrypoint 'submit'`);
utils_1.default.print('');
if (attemptAutomatic) {
utils_1.default.print(`Attempting to inject automatically:`);
const operation = conseiljs_1.TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, counter + 1, multiSigContractAddress, 0, 0, constants_1.default.storageLimit, constants_1.default.gasLimit, 'submit', `${param} `, conseiljs_1.TezosParameterFormat.Michelson);
const operationFeeEstimator = new operation_fee_estimator_1.default(nodeUrl);
const operationsWithFees = await operationFeeEstimator.estimateAndApplyFees([operation]);
const nodeResult = await conseiljs_1.TezosNodeWriter.sendOperation(nodeUrl, operationsWithFees, signer);
const hash = nodeResult.operationGroupID.replace(/"/g, '');
utils_1.default.print(`Executed with hash: ${hash} `);
}
};
exports.submit = submit;
const execute = async (operationId, multiSigContractAddress, nodeUrl, privateKey) => {
const keyStore = await utils_1.default.keyStoreFromPrivateKey(privateKey);
const signer = await utils_1.default.signerFromKeyStore(keyStore);
utils_1.default.print(`Sending execute from: ${keyStore.publicKeyHash} `);
utils_1.default.print(`Using operation ID: ${operationId} `);
await utils_1.default.revealAccountIfNeeded(nodeUrl, keyStore, signer);
const counter = await conseiljs_1.TezosNodeReader.getCounterForAccount(nodeUrl, keyStore.publicKeyHash);
const operation = conseiljs_1.TezosNodeWriter.constructContractInvocationOperation(keyStore.publicKeyHash, counter + 1, multiSigContractAddress, 0, 0, constants_1.default.storageLimit, constants_1.default.gasLimit, 'execute', `${operationId} `, conseiljs_1.TezosParameterFormat.Michelson);
const operationFeeEstimator = new operation_fee_estimator_1.default(nodeUrl);
const operationsWithFees = await operationFeeEstimator.estimateAndApplyFees([
operation,
]);
const nodeResult = await conseiljs_1.TezosNodeWriter.sendOperation(nodeUrl, operationsWithFees, signer);
const hash = nodeResult.operationGroupID.replace(/"/g, '');
utils_1.default.print(`Executed with hash: ${hash} `);
};
exports.execute = execute;
//# sourceMappingURL=commands.js.map