Skip to content

Commit

Permalink
fix: fix input parsing and ABI for dynamic types (#3)
Browse files Browse the repository at this point in the history
* fix: parsing of array inputs

* fix: correct ABI handling for dynamic types
  • Loading branch information
yi-sun authored Feb 14, 2024
1 parent 28faed4 commit 089c09a
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 25 deletions.
17 changes: 13 additions & 4 deletions build/axiom-std-cli-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,25 +118,34 @@ var require_utils = __commonJS({
if (structDefinition === null) {
throw new Error(`Could not find struct definition in file ${jsonFile}`);
}
const abi = [];
const abiComponents = [];
for (const member of structDefinition.members) {
const type = member.typeDescriptions.typeString;
if (type === void 0) {
throw new Error(`Could not find type for member ${member.name}`);
}
abi.push({ name: member.name, type });
abiComponents.push({ name: member.name, type });
}
const abi = [{
"name": "circuit",
"type": "tuple",
"components": abiComponents
}];
return abi;
};
exports2.getAbi = getAbi;
var getInputs = (inputs2, inputSchema) => {
const inputSchemaJson = JSON.parse(inputSchema);
const keys = Object.keys(inputSchemaJson);
const abi = (0, exports2.getAbi)();
const rawInputs = (0, viem_1.decodeAbiParameters)(abi, inputs2);
const rawInputs = (0, viem_1.decodeAbiParameters)(abi, inputs2)[0];
const circuitInputs2 = {};
for (let i = 0; i < keys.length; i++) {
circuitInputs2[keys[i]] = rawInputs[i].toString();
if (Array.isArray(rawInputs[keys[i]])) {
circuitInputs2[keys[i]] = rawInputs[keys[i]].map((x) => x.toString());
} else {
circuitInputs2[keys[i]] = rawInputs[keys[i]].toString();
}
}
return circuitInputs2;
};
Expand Down
21 changes: 15 additions & 6 deletions cli/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const findStructDefinition = (jsonFile: string): any | null => {
return traverseObject(jsonData);
}

export const getAbi = (): { name: string; type: string; }[] => {
export const getAbi = (): any => {
const jsonFile = findFilesWithAxiomInput(process.cwd());

if (jsonFile === null) {
Expand All @@ -81,16 +81,21 @@ export const getAbi = (): { name: string; type: string; }[] => {
throw new Error(`Could not find struct definition in file ${jsonFile}`);
}

const abi: { name: string; type: string; }[] = [];
const abiComponents: { name: string; type: string; }[] = [];

for (const member of structDefinition.members) {
const type = member.typeDescriptions.typeString;
if (type === undefined) {
throw new Error(`Could not find type for member ${member.name}`);
}
abi.push({ name: member.name, type });
abiComponents.push({ name: member.name, type });
}

const abi = [{
"name": "circuit",
"type": "tuple",
"components": abiComponents,
}];
return abi;

}
Expand All @@ -99,13 +104,17 @@ export const getInputs = (inputs: string, inputSchema: string): any => {
const inputSchemaJson = JSON.parse(inputSchema);
const keys = Object.keys(inputSchemaJson);
const abi = getAbi();
const rawInputs: any[] = decodeAbiParameters(abi, inputs as `0x${string}`);

const rawInputs: any = decodeAbiParameters(abi, inputs as `0x${string}`)[0];

const circuitInputs: any = {};
for (let i = 0; i < keys.length; i++) {
// if (keys[i] !== abi[i].name) throw new Error(`Input key ${keys[i]} does not match ABI name ${abi[i].name}`);
circuitInputs[keys[i]] = rawInputs[i].toString();
if (Array.isArray(rawInputs[keys[i]])) {
circuitInputs[keys[i]] = rawInputs[keys[i]].map((x: any) => x.toString());
} else {
circuitInputs[keys[i]] = rawInputs[keys[i]].toString();
}
}

return circuitInputs;
}
2 changes: 1 addition & 1 deletion src/AxiomCli.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ pragma solidity ^0.8.0;
library AxiomCli {

/// @dev The SHA256 hash of the Axiom CLI binary
bytes public constant CLI_SHASUM = hex"4ee15c16a8d9354fc886f0ad85956e2e130d1aa3110fca277976b4682b24f184";
bytes public constant CLI_SHASUM = hex"27c283de43c8d73b186776da5374f57964a053df0ae49b09c5de696a2d30d9c2";
}
14 changes: 10 additions & 4 deletions src/AxiomVm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ library Axiom {
/// @title AxiomVm
/// @dev A contract that provides cheatcodes for testing the AxiomV2Query contract
contract AxiomVm is Test {

/// @dev Path to the Axiom CLI
string CLI_PATH;

Expand Down Expand Up @@ -155,14 +154,21 @@ contract AxiomVm is Test {
checkCli[1] = "-c";
checkCli[2] = string(abi.encodePacked("shasum -a 256 ", CLI_PATH, " | awk '{print $1}'"));
bytes memory sha = vm.ffi(checkCli);
require(keccak256(abi.encodePacked(sha)) == keccak256(abi.encodePacked(AxiomCli.CLI_SHASUM)), "Wrong CLI shasum. Make sure that there are no conflicting axiom-vm-cli.bin files in your folder.");
require(
keccak256(abi.encodePacked(sha)) == keccak256(abi.encodePacked(AxiomCli.CLI_SHASUM)),
"Wrong CLI shasum. Make sure that there are no conflicting axiom-vm-cli.bin files in your folder."
);

string[] memory checkAxiomInputStruct = new string[](3);
checkAxiomInputStruct[0] = "sh";
checkAxiomInputStruct[1] = "-c";
checkAxiomInputStruct[2] = "grep -rl \"AxiomInput\\\"\" . --include \\*.json >/dev/null 2>&1 && echo 1 || echo 0";
checkAxiomInputStruct[2] =
"grep -rl \"AxiomInput\\\"\" . --include \\*.json >/dev/null 2>&1 && echo 1 || echo 0";
bytes memory axiomInputStruct = vm.ffi(checkAxiomInputStruct);
require(_parseBoolean(string(axiomInputStruct)), "AxiomInput struct not found. Make sure that your circuit input struct is named AxiomInput in your test file.");
require(
_parseBoolean(string(axiomInputStruct)),
"AxiomInput struct not found. Make sure that your circuit input struct is named AxiomInput in your test file."
);
}

/**
Expand Down
11 changes: 5 additions & 6 deletions test/AverageBalance.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ contract AverageBalanceTest is AxiomTest {
function setUp() public {
_createSelectForkAndSetupAxiom("sepolia", 5_103_100);

input =
AxiomInput({ blockNumber: 4_205_938, _address: address(0x8018fe32fCFd3d166E8b4c4E37105318A84BA11b) });
input = AxiomInput({ blockNumber: 4_205_938, _address: address(0x8018fe32FCFd3d166e8B4c4e37105318a84ba11d) });

querySchema = axiomVm.readCircuit("test/circuit/average.circuit.ts");
averageBalance = new AverageBalance(axiomV2QueryAddress, uint64(block.chainid), querySchema);
}
Expand All @@ -34,7 +34,7 @@ contract AverageBalanceTest is AxiomTest {
// send the query to Axiom
q.send();

// prank fulfillment of the query, returning the Axiom results
// prank fulfillment of the query, returning the Axiom results
bytes32[] memory results = q.prankFulfill();

// parse Axiom results and verify length is as expected
Expand All @@ -57,9 +57,8 @@ contract AverageBalanceTest is AxiomTest {
overrideAxiomQueryFee: 0
});

// create a query into Axiom with custom `callbackExtraData` and `feeData`
Query memory q =
query(querySchema, abi.encode(input), address(averageBalance), callbackExtraData, feeData);
// create a query into Axiom with custom `callbackExtraData` and `feeData`
Query memory q = query(querySchema, abi.encode(input), address(averageBalance), callbackExtraData, feeData);

// send the query to Axiom
q.send();
Expand Down
8 changes: 4 additions & 4 deletions test/circuit/average.circuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import {
/// These should be the _variable_ inputs to your circuit. Constants can be hard-coded into the circuit itself.
export interface CircuitInputs {
blockNumber: CircuitValue;
address: CircuitValue;
_address: CircuitValue;
}

/// Default inputs used for compilation.
export const defaultInputs = {
"blockNumber": 4205938,
"address": "0x8018fe32fCFd3d166E8b4c4E37105318A84BA11b"
"_address": "0x8018fe32fCFd3d166E8b4c4E37105318A84BA11c"
}

// The function name `circuit` is searched for by default by our Axiom CLI; if you decide to
Expand All @@ -48,7 +48,7 @@ export const circuit = async (inputs: CircuitInputs) => {
let sampledAccounts = new Array(samples);
for (let i = 0; i < samples; i++) {
const sampleBlockNumber: CircuitValue = sub(inputs.blockNumber, mul(spacing, i));
const account = getAccount(sampleBlockNumber, inputs.address);
const account = getAccount(sampleBlockNumber, inputs._address);
sampledAccounts[i] = account;
}

Expand All @@ -65,6 +65,6 @@ export const circuit = async (inputs: CircuitInputs) => {
// We call `addToCallback` on all values that we would like to be passed to our contract after the circuit has
// been proven in ZK. The values can then be handled by our contract once the prover calls the callback function.
addToCallback(inputs.blockNumber);
addToCallback(inputs.address);
addToCallback(inputs._address);
addToCallback(average);
};

0 comments on commit 089c09a

Please sign in to comment.