import { exec } from "child_process"; import { promisify } from "util"; const execAsync = promisify(exec); export const getErrorMsg = (code) => `Exception thrown: (Message [(_exception : (String "Error")) ; (code : (Int32 ${code}))])`; export const getJSONValue = (value, type?) => { value = typeof value === "number" ? value.toString() : value; if ( typeof type === "string" && type.startsWith("ByStr") && typeof value === "string" ) { return value.toLowerCase(); } if ( typeof type === "string" && type.startsWith("List") && Array.isArray(value) ) { const types = type.replace(/[()]/g, "").split(" ").slice(1); return value.map((x) => getJSONValue(x, types.join(" "))); } if ( typeof type === "string" && type.startsWith("Pair") && Array.isArray(value) ) { const types = type.replace(/[()]/g, "").split(" ").slice(1); return { argtypes: types, arguments: value.map((x, i) => getJSONValue(x, types[i])), constructor: "Pair", }; } if (typeof value === "boolean") { return { argtypes: [], arguments: [], constructor: value ? "True" : "False", }; } return value; }; export const getJSONParam = (type, value, vname) => { return { type, value: getJSONValue(value, type), vname, }; }; const initParamsGetter = (contractInfo) => (...params) => { const res = contractInfo.params.map((cur, index) => { if (params[index] === undefined) { throw new Error("invalid params"); } return { ...cur, value: params[index] }; }); const versionParam = { vname: "_scilla_version", type: "Uint32", value: contractInfo.scilla_major_version, }; return [...res, versionParam]; }; const transitionParamsGetter = (contractInfo) => (name, ...params) => { const transition = contractInfo.transitions.find( (cur) => cur.vname === name ); if (transition === undefined) { throw new Error("invalid transition name"); } const res = transition.params.map((cur, index) => { if (params[index] === undefined) { throw new Error("invalid params"); } let type = cur.type; // ByStr20 with
end -> ByStr20 if (type.startsWith("ByStr")) { type = type.split(" ").shift(); } return { ...cur, type, value: getJSONValue(params[index], type), }; }); return res; }; export const useContractInfo = async ( container, src, gasLimit ): Promise => { try { const contractFilename = src.split("/").pop(); const scillaPath = "/scilla/0/"; const paths = { checker: `${scillaPath}bin/scilla-checker`, stdlib: `${scillaPath}src/stdlib`, dest: `${scillaPath}${contractFilename}`, }; await execAsync(`docker cp ${src} ${container}:${paths.dest}`); const cmd = [ "docker exec", container, paths.checker, "-libdir", paths.stdlib, "-gaslimit", gasLimit, paths.dest, "-contractinfo", ].join(" "); const res = await execAsync(cmd); const msg = JSON.parse(res.stdout); const contractInfo = msg.contract_info; return { contractInfo, getInitParams: initParamsGetter(contractInfo), getTransitionParams: transitionParamsGetter(contractInfo), callGetter: (contract, txParams) => (transitionName, ...args) => { return contract.call( transitionName, transitionParamsGetter(contractInfo)(transitionName, ...args), txParams ); }, }; } catch (error) { console.error(error); } }; const logDelta = (want, got) => console.log( "\x1b[32m", `\nExpected: ${want}`, "\x1b[31m", `\nReceived: ${got}` ); export const verifyEvents = (events, want) => { if (events === undefined) { return want === undefined; } for (const [index, event] of events.entries()) { if (event._eventname !== want[index].name) { logDelta(want[index].name, event._eventname); return false; } if ( JSON.stringify(event.params) !== JSON.stringify(want[index].getParams()) ) { logDelta( JSON.stringify(want[index].getParams()), JSON.stringify(event.params) ); return false; } } return true; }; export const verifyTransitions = (transitions, want) => { if (transitions === undefined) { return want === undefined; } for (const [index, transition] of transitions.entries()) { const { msg } = transition; if (want[index].amount && msg._amount !== want[index].amount.toString()) { logDelta(want[index].amount.toString(), msg._amount); return false; } if (want[index].recipient && msg._recipient !== want[index].recipient) { logDelta(want[index].recipient, msg._recipient); return false; } if (msg._tag !== want[index].tag) { logDelta(want[index].tag, msg._tag); return false; } if ( JSON.stringify(msg.params) !== JSON.stringify(want[index].getParams()) ) { logDelta( JSON.stringify(want[index].getParams()), JSON.stringify(msg.params) ); return false; } } return true; }; export const getBNum = async (zilliqa) => { const response = await zilliqa.provider.send("GetBlocknum", ""); return response.result; }; export const increaseBNum = async (zilliqa, n) => { const response = await zilliqa.provider.send("IncreaseBlocknum", n); if (!response.result) { throw new Error( `Failed to advanced block! Error: ${JSON.stringify(response.error)}` ); } }; export const getUsrDefADTValue = (contractAddress, name, values) => `{"argtypes":[],"arguments":${JSON.stringify( values )},"constructor":"${contractAddress.toLowerCase()}.${name}"}`;