Skip to content

Instantly share code, notes, and snippets.

@HoneyIsMoney
Created August 23, 2021 10:37
Show Gist options
  • Save HoneyIsMoney/73589db09d2f2a9699a73bce99e6b118 to your computer and use it in GitHub Desktop.
Save HoneyIsMoney/73589db09d2f2a9699a73bce99e6b118 to your computer and use it in GitHub Desktop.
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