Created
August 23, 2021 10:37
-
-
Save HoneyIsMoney/73589db09d2f2a9699a73bce99e6b118 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ethers from 'ethers'; | |
import abi from 'web3-eth-abi'; | |
import pkg from 'web3-utils'; | |
const { keccak256 } = pkg; | |
import {private_key } from '../.config.mjs'; | |
// main function | |
const run = async () => { | |
// 1. setup signer | |
const provider = ethers.getDefaultProvider('https://rpc.xdaichain.com/') | |
const signer = new ethers.Wallet(private_key, provider); | |
// 2. encode aggregator call data | |
const aggregatorCallData = await encodeActCall( | |
'addPowerSource(address,uint8,uint256)', [ | |
'0x45F453B8f60A9aa259e6AD76870B388594f18806', // testing stake agave token | |
1, // ERC20_WITH_CHECKPOINTING: 1, | |
1 // voting weight | |
] | |
) | |
// 3. create call script | |
const callscript = encodeCallScript([ | |
{ | |
to: '0x852c396de592ce0febda67b007d64d2ecb964485', // aggregator proxy | |
calldata: aggregatorCallData | |
}, | |
]) | |
// 4. create the voting contract to send script to | |
const votingApp = new ethers.Contract( | |
'0x56946de10d67b6a9e85df5d6e5dd1868822c5503', // voting proxy | |
[ | |
"function newVote(bytes,bytes) external", | |
], | |
signer | |
) | |
// 5. log script for manual execution | |
console.log(`EVMSCRIPT: | |
${callscript}`) | |
await votingApp.newVote(callscript, '0x'); | |
console.log('done!') | |
} | |
run() | |
.then(() => process.exit(0)) | |
.catch(e => { | |
console.error(e); | |
process.exit(1) | |
}) | |
/////////////// Encoding Functions //////////////////////// | |
function stripBytePrefix(bytes) { | |
return bytes.substring(0, 2) === "0x" ? bytes.slice(2) : bytes; | |
} | |
function createExecutorId(id) { | |
return `0x${String(id).padStart(8, "0")}`; | |
} | |
// Encodes an array of actions ({ to: address, calldata: bytes }) into the EVM call script format | |
// Sets spec id and concatenates per call | |
// [ 20 bytes (address) ] + [ 4 bytes (uint32: calldata length) ] + [ calldataLength bytes (payload) ] | |
// Defaults spec id to 1 | |
function encodeCallScript(actions, specId = 1) { | |
return actions.reduce((script, { to, calldata }) => { | |
const addr = abi.encodeParameter("address", to); | |
const calldataBytes = stripBytePrefix(calldata.slice(2)); | |
const length = abi.encodeParameter("uint256", calldataBytes.length / 2); | |
// Remove first 12 bytes of padding for addr and 28 bytes for uint32 | |
return ( | |
script + | |
stripBytePrefix(addr).slice(24) + | |
stripBytePrefix(length).slice(56) + | |
calldataBytes | |
); | |
}, createExecutorId(specId)); | |
} | |
/** | |
* Encode ACT function call | |
* @param {string} signature Function signature | |
* @param {any[]} params | |
*/ | |
function encodeActCall(signature, params = []) { | |
const sigBytes = abi.encodeFunctionSignature(signature); | |
const types = signature.replace(")", "").split("(")[1]; | |
// No params, return signature directly | |
if (types === "") { | |
return sigBytes; | |
} | |
const paramBytes = abi.encodeParameters(types.split(","), params); | |
return `${sigBytes}${paramBytes.slice(2)}`; | |
} | |
const EMPTY_CALLS_SCRIPT = createExecutorId(1); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment