Probably due to an update issue, there is a formatting error or constant printing of garbled code when calling Zokrates' verifier contract using ether.js. If you refer to the official documentation for Zokrates, you will see that it doesn't actually work. Thanks to the help of Alberto Viera, we found a solution. The key point here is that the content of the proof parsed directly from the JSON file does not match the input format on the Ethereum contract, which is what leads to the garbled output. Our solution is to repackage the proof into a new object in the format after parsing the JSON file. The sample code is shown below: ```javascript= proof = JSON.parse(proof_source); // console.log(proof); // console.log(abi); const inputStruct = { a: { X: ethers.BigNumber.from(proof.proof.a[0]), Y: ethers.BigNumber.from(proof.proof.a[1]), }, b: { X: [ethers.BigNumber.from(proof.proof.b[0][0]), ethers.BigNumber.from(proof.proof.b[0][1])], Y: [ethers.BigNumber.from(proof.proof.b[1][0]), ethers.BigNumber.from(proof.proof.b[1][1])], }, c: { X: ethers.BigNumber.from(proof.proof.c[0]), Y: ethers.BigNumber.from(proof.proof.c[1]), } } ``` Using the BigNumber method is also an easy place to go wrong. Proof content tends to be big numbers, so it needs to be converted using that method. The complete sample code is below. The developer only needs to define the providerRPC in it as the network he/she is using, set the privateKey and contractAddress and then he/she can use the template. Another thing to keep in mind when verifying is that the input to verifyTx wraps the object inputStruct of the proof in addition to a list of public input values, which needs to be adjusted here depending on the differences in the public inputs for each proof. ```javascript= const createReceipt = await contract.verifyTx(inputStruct, [ethers.BigNumber.from(proof.inputs[0])]); ``` The full example template is below: ```javascript= const ethers = require('ethers'); const { abi } = require('./compile'); const fs = require('fs'); // Configuring the Blockchain Network const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9944', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://moonbase-alpha.public.blastapi.io', chainId: 1287, }, }; const provider = new ethers.providers.JsonRpcProvider(providerRPC.moonbase.rpc, { chainId: providerRPC.moonbase.chainId, name: providerRPC.moonbase.name, }); // Change to correct network // Configure wallet accounts and contracts const account_from = { privateKey: 'YOUR_KEY_DO_NOT_UPLOAD_ONLINE', }; const contractAddress = 'YOUR_CONTRACT'; const _value = 3; // Read in the proof JSON file const proof_source = fs.readFileSync('proof.json', 'utf8'); // Create a wallet let wallet = new ethers.Wallet(account_from.privateKey, provider); // Build a contract instance. const contract = new ethers.Contract(contractAddress, abi, wallet); // Invocation proof const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); proof = JSON.parse(proof_source); // console.log(proof); // console.log(abi); // Constructing the proof object, this part does not need to be changed in most cases and is generic const inputStruct = { a: { X: ethers.BigNumber.from(proof.proof.a[0]), Y: ethers.BigNumber.from(proof.proof.a[1]), }, b: { X: [ethers.BigNumber.from(proof.proof.b[0][0]), ethers.BigNumber.from(proof.proof.b[0][1])], Y: [ethers.BigNumber.from(proof.proof.b[1][0]), ethers.BigNumber.from(proof.proof.b[1][1])], }, c: { X: ethers.BigNumber.from(proof.proof.c[0]), Y: ethers.BigNumber.from(proof.proof.c[1]), } } // Call the verification const createReceipt = await contract.verifyTx(inputStruct, [ethers.BigNumber.from(proof.inputs[0])]); console.log(createReceipt); // await createReceipt.wait(); // console.log(`Tx successful with hash: ${createReceipt.hash}`); }; increment(); ``` The main issue addressed here is access and type matching. [1] [Github Repo](https://github.com/only4sim/zk-base-Moonbeam/tree/main)