Created
March 17, 2024 19:13
-
-
Save valeryz/bdced86266a81cd36c7d917872d32f10 to your computer and use it in GitHub Desktop.
Sending a Safe transaction in typescript (taken from Hardhat Unit test)
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
it("Should succeed verification of a basic transaction", async function () { | |
const nonce = await safe.getNonce(); | |
const threshold = await safe.getThreshold(); | |
const safeTransactionData : SafeTransactionData = { | |
to: ethers.ZeroAddress, | |
value: "0x0", | |
data: "0x", | |
operation: 0, | |
// default fields below | |
safeTxGas: "0x0", | |
baseGas: "0x0", | |
gasPrice: "0x0", | |
gasToken: ethers.ZeroAddress, | |
refundReceiver: ethers.ZeroAddress, | |
nonce, | |
} | |
console.log("transaction", safeTransactionData); | |
const transaction = await safe.createTransaction({ transactions: [safeTransactionData] }); | |
const txHash = await safe.getTransactionHash(transaction); | |
console.log("txHash", txHash); | |
// Let's generate three signatures for the owners of the Safe. | |
// ok, our siganture is a EIP-712 signature, so we need to sign the hash of the transaction. | |
let safeTypedData = { | |
safeAddress: await safe.getAddress(), | |
safeVersion: await safe.getContractVersion(), | |
chainId: await ownerAdapters[0].getChainId(), | |
safeTransactionData: safeTransactionData, | |
}; | |
const sig1 = await ownerAdapters[0].signTypedData(safeTypedData); | |
const sig2 = await ownerAdapters[1].signTypedData(safeTypedData); | |
const sig3 = await ownerAdapters[2].signTypedData(safeTypedData); | |
const nil_pubkey = { | |
x: Array.from(ethers.getBytes("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")), | |
y: Array.from(ethers.getBytes("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")) | |
}; | |
// Our Nil signature is a signature with r and s set to | |
const nil_signature = Array.from( | |
ethers.getBytes("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")); | |
const zero_address = new Array(20).fill(0); | |
const signatures = [sig2, sig3]; // sig1 is not included, threshold of 2 should be enough. | |
// Sort signatures by address - this is how the Safe contract does it. | |
signatures.sort((sig1, sig2) => ethers.recoverAddress(txHash, sig1).localeCompare(ethers.recoverAddress(txHash, sig2))); | |
const input = { | |
threshold: await safe.getThreshold(), | |
signers: padArray(signatures.map((sig) => extractCoordinates(ethers.SigningKey.recoverPublicKey(txHash, sig))), 10, nil_pubkey), | |
signatures: padArray(signatures.map(extractRSFromSignature), 10, nil_signature), | |
txn_hash: Array.from(ethers.getBytes(txHash)), | |
owners: padArray((await safe.getOwners()).map(addressToArray), 10, zero_address), | |
}; | |
correctProof = await noir.generateFinalProof(input); | |
console.log("correctProof", correctProof); | |
const verification = await noir.verifyFinalProof(correctProof); | |
expect(verification).to.be.true; | |
console.log("verification in JS succeeded"); | |
const safeAddress = await safe.getAddress(); | |
const directVerification = await verifierContract.verify(correctProof["proof"], [...correctProof["publicInputs"].values()]); | |
console.log("directVerification", directVerification); | |
const contractVerification = await zkSafeModule.verifyZkSafeTransaction(safeAddress, txHash, correctProof["proof"]); | |
console.log("contractVerification", contractVerification); | |
console.log("safe: ", safe); | |
console.log("transaction: ", transaction); | |
const txn = await zkSafeModule.sendZkSafeTransaction( | |
safeAddress, | |
{ to: transaction["data"]["to"], | |
value: BigInt(transaction["data"]["value"]), | |
data: transaction["data"]["data"], | |
operation: transaction["data"]["operation"], | |
}, | |
correctProof["proof"], | |
{ gasLimit: 2000000 } | |
); | |
let receipt = txn.wait(); | |
expect(txn).to.not.be.reverted; | |
let newNonce = await safe.getNonce(); | |
expect(newNonce).to.equal(nonce + 1); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment