|
| 1 | +const { writeFileSync } = require("fs"); |
| 2 | +const { NEAR, Gas } = require("near-units"); |
| 3 | +const { init } = require("../near"); |
| 4 | +const nearAPI = require('near-api-js'); |
| 5 | +const { networkOption, doubleCheck, parseHashReturnValue, getBase58CodeHash } = require("./common"); |
| 6 | + |
| 7 | +exports.command = 'store-dao-contract <dao>'; |
| 8 | +exports.desc = 'Store DAO contract code from DAO factory'; |
| 9 | +exports.builder = yargs => { |
| 10 | + yargs |
| 11 | + .positional('dao', { |
| 12 | + describe: 'DAO contract address to store DAO contract code', |
| 13 | + type: 'string' |
| 14 | + }) |
| 15 | + .option('network', networkOption) |
| 16 | + .option('wasm', { |
| 17 | + describe: 'DAO contract wasm file path', |
| 18 | + default: 'res/sputnikdao.wasm' |
| 19 | + }) |
| 20 | + .option('signer', { |
| 21 | + describe: 'signer account ID' |
| 22 | + }) |
| 23 | + .option('hash', { |
| 24 | + describe: 'DAO contract code hash to store' |
| 25 | + }) |
| 26 | + .demandOption(['signer', 'dao', 'hash']) |
| 27 | +} |
| 28 | + |
| 29 | +exports.handler = async function (argv) { |
| 30 | + const { dao, hash, network } = argv; |
| 31 | + |
| 32 | + const factory = dao.split('.').slice(1).join('.'); |
| 33 | + console.log(`Fetch DAO contract code from factory ${factory} with code hash ${hash} ...`); |
| 34 | + |
| 35 | + const near = await init(network); |
| 36 | + const signer = await near.account(argv.signer); |
| 37 | + const contract = await near.account(dao); |
| 38 | + |
| 39 | + const code = await signer.viewFunction(factory, 'get_code', { code_hash: hash }, { parse: (code) => code }); |
| 40 | + writeFileSync(argv.wasm, code); |
| 41 | + const codeHash = getBase58CodeHash(code); |
| 42 | + if(codeHash !== hash) { |
| 43 | + console.error(`The fetched code hash ${codeHash} is not the same as the provided ${hash}`); |
| 44 | + return; |
| 45 | + } |
| 46 | + |
| 47 | + const deposit = (BigInt(code.length + 32) * 10n ** 19n).toString() |
| 48 | + |
| 49 | + console.log(`Store DAO contract code with hash ${codeHash} to DAO ${dao}`); |
| 50 | + console.log(`- Code hash: ${codeHash}`); |
| 51 | + console.log(`- Storage cost: ${NEAR.from(deposit).toHuman()}`); |
| 52 | + console.log(`- DAO: ${dao}`); |
| 53 | + |
| 54 | + const deployedCodeHash = (await contract.state()).code_hash; |
| 55 | + if (codeHash === deployedCodeHash) { |
| 56 | + console.log( |
| 57 | + "Contract's code hash is the same as the wasm file. There's no need to store the same code again.", |
| 58 | + ); |
| 59 | + return; |
| 60 | + } |
| 61 | + |
| 62 | + // check if the blob already exists |
| 63 | + const found = await signer.viewFunction(dao, 'has_blob', { hash: codeHash }); |
| 64 | + if (found) { |
| 65 | + console.error(`The blob with ${codeHash} already exists. No need to store the same blob.`); |
| 66 | + } else { |
| 67 | + // store new blob |
| 68 | + console.log(`Store blob with hash ${codeHash}. Are you sure?`); |
| 69 | + await doubleCheck(); |
| 70 | + const outcome = await signer.signAndSendTransaction( |
| 71 | + { |
| 72 | + receiverId: dao, |
| 73 | + actions: [ |
| 74 | + nearAPI.transactions.functionCall( |
| 75 | + 'store_blob', |
| 76 | + code, |
| 77 | + Gas.parse('100 Tgas'), |
| 78 | + deposit |
| 79 | + ) |
| 80 | + ] |
| 81 | + } |
| 82 | + ); |
| 83 | + const hash = parseHashReturnValue(outcome); |
| 84 | + console.log(`Stored blob with hash ${hash}`); |
| 85 | + } |
| 86 | +} |
0 commit comments