diff --git a/TNLS-Clients/VRFDemo/src/main.ts b/TNLS-Clients/VRFDemo/src/main.ts index fa2a58f..c5fc98e 100644 --- a/TNLS-Clients/VRFDemo/src/main.ts +++ b/TNLS-Clients/VRFDemo/src/main.ts @@ -4,38 +4,15 @@ import { setupSubmit } from './submit' document.querySelector('#app')!.innerHTML = `
-

Atbash Labs

- +

Secret VRF on Ethereum

-

Sample Application: Random Number Generation using Secret VRF

+

Sample Application: Roll the Dice!

+

Random Number Generation using Secret VRF, bridged into EVM.

+

This demo generates 2000 verifiable random numbers in just one transaction.

- +
-
- - -
-
- - -
diff --git a/TNLS-Clients/VRFDemo/src/submit.ts b/TNLS-Clients/VRFDemo/src/submit.ts index dd8d7f7..1b47928 100644 --- a/TNLS-Clients/VRFDemo/src/submit.ts +++ b/TNLS-Clients/VRFDemo/src/submit.ts @@ -3,82 +3,87 @@ import { arrayify, hexlify, SigningKey, keccak256, recoverPublicKey, computeAddr import { Buffer } from "buffer"; import secureRandom from "secure-random"; -export function setupSubmit(element: HTMLButtonElement) { +export async function setupSubmit(element: HTMLButtonElement) { - const publicClientAddress = '0x62A76e4fFB2fa4b4FecA249cD1646C7fD1469319' - const routing_contract = "secret1zash9uk88y3sr8sjf0jdrlfsdsyuk6szvj99k6" - const routing_code_hash = "d94d2cd7d22f0509c7ca0b80d6576ecfebf2618c6026204c30a35f6624cb3230" + const randomnessContract = '0x57182a1b08e34Fc7eCdF33B4775E8a560443a6bF' // @ts-ignore const provider = new ethers.providers.Web3Provider(window.ethereum); + // Create a contract instance + const randomnessAbi = [{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"VRFGateway","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"fulfillRandomWords","inputs":[{"name":"requestId","type":"uint256","internalType":"uint256"},{"name":"randomWords","type":"uint256[]","internalType":"uint256[]"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"requestRandomnessTest","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setGatewayAddress","inputs":[{"name":"_VRFGateway","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"fulfilledRandomWords","inputs":[{"name":"requestId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"randomWords","type":"uint256[]","indexed":false,"internalType":"uint256[]"}],"anonymous":false},{"type":"event","name":"requestRandomness","inputs":[{"name":"requestId","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false}] + const randomnessContractInterface = new ethers.Contract(randomnessContract, randomnessAbi, provider); + element.addEventListener("click", async function(event: Event){ event.preventDefault() const [myAddress] = await provider.send("eth_requestAccounts", []); - const data = JSON.stringify({ - numWords:20 - }) - // create the abi interface and encode the function data - const abi = [{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"callback","inputs":[{"name":"_taskId","type":"uint256","internalType":"uint256"},{"name":"_result","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"postExecution","inputs":[{"name":"_taskId","type":"uint256","internalType":"uint256"},{"name":"_sourceNetwork","type":"string","internalType":"string"},{"name":"_info","type":"tuple","internalType":"struct Gateway.PostExecutionInfo","components":[{"name":"payload_hash","type":"bytes32","internalType":"bytes32"},{"name":"result_hash","type":"bytes32","internalType":"bytes32"},{"name":"packet_hash","type":"bytes32","internalType":"bytes32"},{"name":"callback_address","type":"bytes20","internalType":"bytes20"},{"name":"callback_selector","type":"bytes4","internalType":"bytes4"},{"name":"callback_gas_limit","type":"bytes4","internalType":"bytes4"},{"name":"packet_signature","type":"bytes","internalType":"bytes"},{"name":"result_signature","type":"bytes","internalType":"bytes"},{"name":"result","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"requestRandomWords","inputs":[{"name":"_numWords","type":"uint32","internalType":"uint32"},{"name":"_callbackGasLimit","type":"uint32","internalType":"uint32"}],"outputs":[{"name":"requestId","type":"uint256","internalType":"uint256"}],"stateMutability":"payable"},{"type":"function","name":"send","inputs":[{"name":"_payloadHash","type":"bytes32","internalType":"bytes32"},{"name":"_userAddress","type":"address","internalType":"address"},{"name":"_routingInfo","type":"string","internalType":"string"},{"name":"_info","type":"tuple","internalType":"struct Gateway.ExecutionInfo","components":[{"name":"user_key","type":"bytes","internalType":"bytes"},{"name":"user_pubkey","type":"bytes","internalType":"bytes"},{"name":"routing_code_hash","type":"string","internalType":"string"},{"name":"handle","type":"string","internalType":"string"},{"name":"nonce","type":"bytes12","internalType":"bytes12"},{"name":"payload","type":"bytes","internalType":"bytes"},{"name":"payload_signature","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setContractAddressAndCodeHash","inputs":[{"name":"_contractAddress","type":"string","internalType":"string"},{"name":"_contractCodeHash","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setMasterVerificationAddress","inputs":[{"name":"_masterVerificationAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"updateRoute","inputs":[{"name":"_route","type":"string","internalType":"string"},{"name":"_verificationAddress","type":"address","internalType":"address"},{"name":"_signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"ComputedResult","inputs":[{"name":"taskId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"result","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"logCompletedTask","inputs":[{"name":"task_id","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"payload_hash","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"result_hash","type":"bytes32","indexed":false,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"logNewTask","inputs":[{"name":"task_id","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"source_network","type":"string","indexed":false,"internalType":"string"},{"name":"user_address","type":"address","indexed":false,"internalType":"address"},{"name":"routing_info","type":"string","indexed":false,"internalType":"string"},{"name":"payload_hash","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"info","type":"tuple","indexed":false,"internalType":"struct Gateway.ExecutionInfo","components":[{"name":"user_key","type":"bytes","internalType":"bytes"},{"name":"user_pubkey","type":"bytes","internalType":"bytes"},{"name":"routing_code_hash","type":"string","internalType":"string"},{"name":"handle","type":"string","internalType":"string"},{"name":"nonce","type":"bytes12","internalType":"bytes12"},{"name":"payload","type":"bytes","internalType":"bytes"},{"name":"payload_signature","type":"bytes","internalType":"bytes"}]}],"anonymous":false},{"type":"error","name":"CallbackError","inputs":[]},{"type":"error","name":"InvalidPacketSignature","inputs":[]},{"type":"error","name":"InvalidPayloadHash","inputs":[]},{"type":"error","name":"InvalidResultSignature","inputs":[]},{"type":"error","name":"InvalidSignature","inputs":[]},{"type":"error","name":"InvalidSignatureLength","inputs":[]},{"type":"error","name":"InvalidSignatureSValue","inputs":[]},{"type":"error","name":"TaskAlreadyCompleted","inputs":[]}] - const iface= new ethers.utils.Interface( abi ) + const iface= new ethers.utils.Interface( randomnessAbi ) const FormatTypes = ethers.utils.FormatTypes; console.log(iface.format(FormatTypes.full)) - const functionData = iface.encodeFunctionData("send", - [ - _payloadHash, - _userAddress, - _routingInfo, - _info, - ] - ) + const functionData = iface.encodeFunctionData("requestRandomnessTest") console.log(functionData) + await window.ethereum.request({ + "method": "wallet_switchEthereumChain", + "params": [ + { + "chainId": "0xAA36A7" + } + ] + }); + const tx_params = [ { gas: '0x249F0', // 150000 - to: publicClientAddress, + to: randomnessContract, from: myAddress, value: '0x00', // 0 - data: functionData, // TODO figure out what this data is meant to be + data: functionData, }, ]; const txHash = await provider.send("eth_sendTransaction", tx_params); - console.log(txHash) - - document.querySelector('#preview')!.innerHTML = ` -

Raw Payload

-

${thePayload}

- -

TNLS Payload

-

${ciphertext.toString('base64')}

- -

Payload Hash

-

${payloadHash}

-

Payload Signature

-

${payloadSignature}

+ // Set up an event listener for the 'logNewTask' event + randomnessContractInterface.on('requestRandomness', (originalRequestId) => { + // This code is executed when the event is emitted + console.log(`Request ID: ${originalRequestId}`); + // Additional data from the event can be accessed if needed + // You can also access other properties of the event object, like event.blockNumber + // Set up an event listener for the 'fulfilledRandomWords' event + randomnessContractInterface.on('fulfilledRandomWords', (requestId, randomWords, event) => { + // This code is executed when the event is emitted + if (originalRequestId == requestId) { + console.log(`Request ID: ${requestId}`); + console.log(`Random Words: ${randomWords}`); + // You can access other event properties like event.blockNumber if needed + document.querySelector('#preview')!.innerHTML = ` + +

+ +

Transaction Parameters

+

Request ID: ${requestId}

+

Random Words: ${randomWords}

+

${JSON.stringify(tx_params)}

+ ` + } + }); + }); -

Other Info

-

- - Public key used during encryption: ${userPublicKey}
- Nonce used during encryption: ${nonce}
+ document.querySelector('#preview')!.innerHTML = `

Transaction Parameters

-

Tx Hash: ${txHash}

-

Gateway Address (to check the postExecution callback) ${publicClientAddress}

+

Tx Hash: ${txHash}

+

Gateway Address (to check the postExecution callback) ${randomnessContract}

${JSON.stringify(tx_params)}

` + }) -} -//

Tx Hash: ${txHash}

-//

Gateway Address (to check the postExecution callback) ${publicClientAddress}

-//

${JSON.stringify(tx_params)}

\ No newline at end of file +} \ No newline at end of file diff --git a/TNLS-Gateways/public-gateway/script/DeployScript.s.sol b/TNLS-Gateways/public-gateway/script/DeployScript.s.sol index 02904f2..4cae103 100644 --- a/TNLS-Gateways/public-gateway/script/DeployScript.s.sol +++ b/TNLS-Gateways/public-gateway/script/DeployScript.s.sol @@ -20,6 +20,8 @@ contract DeployScript is Script { TransparentUpgradeableProxy gatewayProxy; RandomnessReciever randomnessAddress; + address verificationAddress = 0x5b5274c2ae6aA29B6e94048878a61814594D3409; + uint256 privKey = vm.envUint("ETH_PRIVATE_KEY"); @@ -74,7 +76,6 @@ contract DeployScript is Script { // Initialize master verification Address gateway.setMasterVerificationAddress(deployer); // Replace gatewayAddress with gateway - address verificationAddress = 0x09362bF5bbA88948f8B9fCDbB5B56C8CdD2403ad; /// ------ Update Routes Param Setup ------- /// string memory route = "secret-4"; diff --git a/TNLS-Gateways/public-gateway/src/Gateway.sol b/TNLS-Gateways/public-gateway/src/Gateway.sol index ed03b11..a630d0c 100644 --- a/TNLS-Gateways/public-gateway/src/Gateway.sol +++ b/TNLS-Gateways/public-gateway/src/Gateway.sol @@ -40,13 +40,6 @@ contract Gateway is Initializable { bytes payload_signature; } - struct VRFSecretContract { - bytes32 contract_address_1; - bytes13 contract_address_2; - bytes32 contract_code_hash_1; - bytes32 contract_code_hash_2; - } - struct PostExecutionInfo { bytes32 payload_hash; bytes32 result_hash; @@ -73,7 +66,6 @@ contract Gateway is Initializable { /// @dev mapping of chain name string to the verification address mapping(string => address) public route; - /*////////////////////////////////////////////////////////////// Errors //////////////////////////////////////////////////////////////*/ @@ -111,6 +103,7 @@ contract Gateway is Initializable { /// @return r The r component of the signature /// @return s The s component of the signature /// @return v The recovery byte of the signature + function splitSignature(bytes memory _sig) private pure returns (bytes32 r, bytes32 s, uint8 v) { require(_sig.length == 65, "invalid signature length"); @@ -138,6 +131,7 @@ contract Gateway is Initializable { /// @param _routeInput The route name /// @param _verificationAddressInput The verification address /// @return The calculated hash + function getRouteHash(string calldata _routeInput, address _verificationAddressInput) private pure returns (bytes32) { return keccak256(abi.encode(_routeInput, _verificationAddressInput)); } @@ -204,9 +198,8 @@ contract Gateway is Initializable { } } - function bytesToUint256Array(bytes memory data) public pure returns (uint256[] memory) { + function bytesToUint256Array(bytes memory data) private pure returns (uint256[] memory) { require(data.length % 32 == 0, "Data length must be a multiple of 32 bytes"); - uint256[] memory uintArray; assembly { // Cast the bytes array to a uint256[] array by setting the appropriate length @@ -249,6 +242,7 @@ contract Gateway is Initializable { //////////////////////////////////////////////////////////////*/ /// @notice Replaces the constructor for upgradeable contracts + function initialize() public initializer { owner = msg.sender; taskId = 1; @@ -260,6 +254,7 @@ contract Gateway is Initializable { /// @notice Initialize the verification address /// @param _masterVerificationAddress The input address + function setMasterVerificationAddress(address _masterVerificationAddress) external onlyOwner { masterVerificationAddress = _masterVerificationAddress; } @@ -344,7 +339,7 @@ contract Gateway is Initializable { //use hard coded contract values instead of storage variables, saves around 8,500 in gas per TX. //Since contract is upgradeable, we can update these values as well with it. - bytes memory _routing_info = "secret10hwq375veu49khx9dkcl6249n6fc2u5tft50jp"; + bytes memory _routing_info = "secret1jyu2qaentmvwvejm8wzghr8qms0yehukxmp75f"; bytes memory _routing_code_hash = "d94d2cd7d22f0509c7ca0b80d6576ecfebf2618c6026204c30a35f6624cb3230"; bytes memory payload = bytes.concat( @@ -406,17 +401,13 @@ contract Gateway is Initializable { revert TaskAlreadyCompleted(); } + // Check if the payload hashes match if (sliceLastByte(_info.payload_hash) != task.payload_hash_reduced) { revert InvalidPayloadHash(); } address checkerAddress = route[_sourceNetwork]; - // Result signature verification - if (recoverSigner(_info.result_hash, _info.result_signature) != checkerAddress) { - revert InvalidResultSignature(); - } - // Concatenate data elements bytes memory data = bytes.concat( bytes(_sourceNetwork), diff --git a/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol b/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol index 079831e..97e8263 100644 --- a/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol +++ b/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol @@ -23,12 +23,14 @@ contract RandomnessReciever { VRFGateway = _VRFGateway; } + event requestRandomness(uint256 requestId); function requestRandomnessTest() external { uint32 numWords = 2000; // can be up to 2000 words uint32 callbackGasLimit = 2000000; ISecretVRF vrfContract = ISecretVRF(VRFGateway); uint256 requestId = vrfContract.requestRandomness(numWords, callbackGasLimit); + emit requestRandomness(requestId); } event fulfilledRandomWords(uint256 requestId, uint256[] randomWords); diff --git a/TNLS-Gateways/public-gateway/test/Contract.t.sol b/TNLS-Gateways/public-gateway/test/Contract.t.sol index 26607c6..1027ad2 100644 --- a/TNLS-Gateways/public-gateway/test/Contract.t.sol +++ b/TNLS-Gateways/public-gateway/test/Contract.t.sol @@ -5,6 +5,8 @@ import "forge-std/Test.sol"; import "forge-std/Vm.sol"; import "forge-std/console2.sol"; import {Gateway} from "../src/Gateway.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; contract ContractTest is Test { /*////////////////////////////////////////////////////////////// @@ -13,7 +15,10 @@ contract ContractTest is Test { Gateway internal gateway; address deployer; + address gatewayOwner; address notOwner; + ProxyAdmin proxyAdmin; + TransparentUpgradeableProxy gatewayProxy; event logNewTask( uint256 indexed task_id, @@ -36,9 +41,30 @@ contract ContractTest is Test { function setUp() public { deployer = vm.addr(3); + gatewayOwner = vm.addr(9); notOwner = vm.addr(4); vm.prank(deployer); - gateway = new Gateway(); + // Deploy ProxyAdmin + proxyAdmin = new ProxyAdmin(msg.sender); + + // Deploy Gateway Logic Contract + Gateway gatewayLogic = new Gateway(); + + // Prepare initializer data for Gateway + bytes memory initializerData = abi.encodeWithSelector( + Gateway.initialize.selector + ); + + vm.prank(gatewayOwner); + // Deploy TransparentUpgradeableProxy + gatewayProxy = new TransparentUpgradeableProxy( + address(gatewayLogic), + address(proxyAdmin), + initializerData + ); + + // Cast the proxy address to the Gateway interface + gateway = Gateway(address(gatewayProxy)); } /*////////////////////////////////////////////////////////////// @@ -78,17 +104,21 @@ contract ContractTest is Test { return keccak256(abi.encode(_routeInput, _verificationAddressInput)); } + function sliceLastByte(bytes32 data) private pure returns (bytes31) { + return bytes31(data & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00); + } + /*////////////////////////////////////////////////////////////// Helper Functions //////////////////////////////////////////////////////////////*/ function getPayloadHash(bytes memory _payload) public pure returns (bytes32) { - return keccak256(abi.encode(_payload)); + return keccak256(abi.encodePacked(_payload)); // return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes32(_payload.length), _payload)); } function getResultHash(bytes memory _result) public pure returns (bytes32) { - return keccak256(abi.encode(_result)); + return keccak256(abi.encodePacked(_result)); } function getRouteInfoHash(string memory _routingInfo) public pure returns (bytes32) { @@ -136,7 +166,7 @@ contract ContractTest is Test { function test_OwnerCanInitialize() public { - vm.prank(deployer); + vm.prank(gatewayOwner); address tempAddress = vm.addr(5); gateway.setMasterVerificationAddress(tempAddress); @@ -152,8 +182,8 @@ contract ContractTest is Test { } function test_OwnerCanUpdateRouteWithValidSignature() public { - // Set the Master Verrification Key below - vm.prank(deployer); + // Set the Master Verification Key below + vm.prank(gatewayOwner); address masterVerificationKey = vm.addr(2); gateway.setMasterVerificationAddress(masterVerificationKey); @@ -168,7 +198,7 @@ contract ContractTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(2, ethSignedMessageHash); bytes memory sig = abi.encodePacked(r, s, v); - vm.prank(deployer); + vm.prank(gatewayOwner); gateway.updateRoute(sampleRoute, SampleVerificationAddress, sig); assertEq(gateway.route("secret-4"), SampleVerificationAddress); @@ -176,7 +206,7 @@ contract ContractTest is Test { function testFail_OwnerCannotUpdateRouteWithoutValidSignature() public { // Set the Master Verrification Key below - vm.prank(deployer); + vm.prank(gatewayOwner); address masterVerificationKey = vm.addr(5); gateway.setMasterVerificationAddress(masterVerificationKey); @@ -191,7 +221,6 @@ contract ContractTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(7, ethSignedMessageHash); bytes memory sig = abi.encodePacked(r, s, v); - vm.prank(deployer); gateway.updateRoute(sampleRoute, SampleVerificationAddress, sig); vm.expectRevert(abi.encodeWithSignature("InvalidSignature()")); @@ -199,7 +228,7 @@ contract ContractTest is Test { function testFail_NonOwnerCannotUpdateRouteWithValidSignature() public { // Set the Master Verrification Key below - vm.prank(deployer); + vm.prank(gatewayOwner); address masterVerificationKey = vm.addr(5); gateway.setMasterVerificationAddress(masterVerificationKey); @@ -219,7 +248,7 @@ contract ContractTest is Test { function testFail_NonOwnerCannotUpdateRouteWithoutValidSignature() public { // Set the Master Verrification Key below - vm.prank(deployer); + vm.prank(gatewayOwner); address masterVerificationKey = vm.addr(5); gateway.setMasterVerificationAddress(masterVerificationKey); @@ -241,9 +270,6 @@ contract ContractTest is Test { // USER ADDRESS -----> vm.addr(5); // CALLBACK ADDRESS -----> vm.addr(7); - bytes4 callbackSelector = bytes4(abi.encodeWithSignature("callback(uint256 _taskId,bytes memory _result)")); - string memory sourceNetwork = "ethereum"; - string memory routingInfo = "secret"; // bytes32 string encoding of "add a bunch of stuff" @@ -265,21 +291,16 @@ contract ContractTest is Test { payload_signature: getPayloadSignature(payload, 5) }); - gateway.send(vm.addr(5), sourceNetwork,routingInfo, payloadHash, assembledInfo, vm.addr(7), callbackSelector, 300000 ); + gateway.send(payloadHash, vm.addr(5), routingInfo, assembledInfo); - (bytes31 tempPayloadHash,,,,) = gateway.tasks(1); - assertEq(tempPayloadHash, payloadHash, "payloadHash failed"); + (bytes31 tempPayloadHash,) = gateway.tasks(1); + assertEq(tempPayloadHash, sliceLastByte(payloadHash), "payloadHash failed"); (,bool tempCompleted) = gateway.tasks(1); assertEq(tempCompleted, false, "tempCompleted failed"); } function testFail_CannotPreExecutionWithoutValidPayloadSig() public { - // USER ADDRESS -----> vm.addr(5); - // CALLBACK ADDRESS -----> vm.addr(6); - - bytes4 callbackSelector = bytes4(abi.encodeWithSignature("callback(uint256 _taskId,bytes memory _result)")); - string memory sourceNetwork = "ethereum"; string memory routingInfo = "secret"; @@ -292,7 +313,6 @@ contract ContractTest is Test { bytes memory userKey = hex"736f6d65207075626c6963206b65790000000000000000000000000000000000"; bytes memory userPublicKey = hex"040b8d42640a7eded641dd42ad91d7c9ae3644a2412bdff174790012774e5528a30f9f0a630977d53e7a862eb2fb89207fe4fafc824992d281ba0180c6a1fddb4c"; - Gateway.ExecutionInfo memory assembledInfo = Gateway.ExecutionInfo({ user_key: userKey, user_pubkey:userPublicKey, @@ -303,7 +323,7 @@ contract ContractTest is Test { payload_signature: getPayloadSignature(payload, 7) }); - gateway.send(vm.addr(5), sourceNetwork,routingInfo, payloadHash, assembledInfo, vm.addr(6), callbackSelector, 300000 ); + gateway.send(payloadHash, vm.addr(5), routingInfo, assembledInfo); vm.expectRevert(abi.encodeWithSignature("InvalidSignature()")); } @@ -313,6 +333,7 @@ contract ContractTest is Test { test_PreExecution(); string memory sourceNetwork = "secret"; + uint256 taskId = 1; // bytes32 string encoding of "add a bunch of stuff" @@ -329,14 +350,17 @@ contract ContractTest is Test { payload_hash: payloadHash, result: result, result_hash: resultHash, - result_signature: getResultSignature(result, 6), + result_signature: getResultSignature(result, 2), packet_hash: resultHash, - packet_signature: getResultSignature(result, 6) + packet_signature: getResultSignature(result, 2), + callback_address: bytes20(address(gateway)), + callback_selector: hex"faef40fe", + callback_gas_limit: bytes4(uint32(300000)) }); gateway.postExecution(taskId, sourceNetwork, assembledInfo); - (,,,, bool tempCompleted) = gateway.tasks(1); + (,bool tempCompleted) = gateway.tasks(1); assertEq(tempCompleted, true); } @@ -363,7 +387,10 @@ contract ContractTest is Test { result_hash: resultHash, result_signature: getResultSignature(result, 6), packet_hash: resultHash, - packet_signature: getResultSignature(result, 6) + packet_signature: getResultSignature(result, 6), + callback_address: bytes20(address(gateway)), + callback_selector: hex"faef40fe", + callback_gas_limit: bytes4(uint32(300000)) }); gateway.postExecution(taskId, sourceNetwork, assembledInfo); @@ -376,19 +403,16 @@ contract ContractTest is Test { //////////////////////////////////////////////////////////////*/ function test_PreExecutionSetupForExplicitCase() public { - // CALLBACK ADDRESS -----> vm.addr(7); - bytes4 callbackSelector = bytes4(0xb2bcfb71); - string memory sourceNetwork = "ethereum"; - address userAddress = 0x49F7552065228e5abF44e144cc750aEA4F711Dc3; + address userAddress = 0x50FcF0c327Ee4341313Dd5Cb987f0Cd289Be6D4D; string memory routingInfo = "secret"; // bytes32 string encoding of "add a bunch of stuff" - bytes memory payload = hex"61646420612062756e6368206f66207374756666000000000000000000000000"; - bytes32 payloadHash = hex"ea57f8cfce0dca7528ff349328b9a524dbbd49fe724026da575aed40cd3ac2c4"; + bytes memory payload = hex"0e9cff93bb71eb6eaabb1d64dba1841ba9202784af250812f7588a42c53d7ff1866cc2c682fd8968a2a36a9a7b5f1721c69d761a6bd4a26ef6b1c2f82cd35a7d29369fbeab8ad35c9ce162560e9a5cf2a271d30bb5b3e86206396bc6973f30ecb87959d5310688cb5283cf6eec57d86bb3c0bcd2d29d341d686f66208d90f65223cc988ce5b8923bed3225847ddc5859eef515ffb8ea77e8faafc891c2bcf8c1898ad53081367c052c866444536972c58672a1994cfc0ed174eea0ec7b324f2c4214c658fd75d06180e0984546a838559b890220d41d1ee4882f6371b7352c49f10ce45c360c4a98f9c5bf988bc49392ac005edb8c8683258163acb87e989dee647fcbf4e94b7bb320525c054dadad82764c34d82fa3b10bfd9edf260224eb86275f5ad390ce42fd423689cbe45f42350ed23465112554857d25f12a00f33e1c202cd419f512ad842f1fef95fa5bfd4898a810e9f0ab4354453aca9bb516c49c8a88bc1134cc8f2fa1d7e5cb65ff23ffbc7727d091c0b1e18c7c6647a49e3e951c2e8ec87ca3cdeb3bedb5d5b1650d4b622bfc3e6ca7c3d5afa6cbe4f0d80ac8dbd966359d"; + bytes32 payloadHash = hex"fa6ec6995359ca7c7ea6602443f212e8295b9407cfa9f1f04c4651df345453fa"; bytes memory payloadSignature = - hex"293fb5fe48d81aadd26574aca54509804f628a851d7df4e3356b0e191ef5b11c33f07e7eeb0494384df6f3f636e2fc0fcf64ee3fb0d5e3d6f3302a81325bd06f1c"; + hex"a6c728c5307ec4a84f15805f55d3827c6e58eb661fa5633956b500540e6b0b376cba788ef8ad19024ecc5c769cdd917ae07423f0724709e10fce0e3d7510da7c1c"; // encoding bytes of "some public key" bytes memory userKey = hex"736f6d65207075626c6963206b65790000000000000000000000000000000000"; @@ -404,24 +428,18 @@ contract ContractTest is Test { payload_signature: payloadSignature }); - gateway.send(userAddress, sourceNetwork,routingInfo, payloadHash, assembledInfo, address(gateway), callbackSelector, 300000 ); - - (bytes32 tempPayloadHash,,,,) = gateway.tasks(1); - assertEq(tempPayloadHash, payloadHash); + gateway.send(payloadHash, userAddress,routingInfo, assembledInfo ); - (,address tempCallbackAddress,,,) = gateway.tasks(1); - assertEq(tempCallbackAddress, address(gateway)); + (bytes31 tempPayloadHash,) = gateway.tasks(1); + assertEq(tempPayloadHash, sliceLastByte(payloadHash)); - (,,bytes4 tempCallbackSelector,,) = gateway.tasks(1); - assertEq(tempCallbackSelector, callbackSelector); - - (,,,, bool tempCompleted) = gateway.tasks(1); + (,bool tempCompleted) = gateway.tasks(1); assertEq(tempCompleted, false); } function test_addressKeySetupForPostExecutionExplicitValues() public { // Set the Master Verrification Key below - vm.prank(deployer); + vm.prank(gatewayOwner); address masterVerificationKey = vm.addr(2); gateway.setMasterVerificationAddress(masterVerificationKey); @@ -436,7 +454,7 @@ contract ContractTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(2, ethSignedMessageHash); bytes memory sig = abi.encodePacked(r, s, v); - vm.prank(deployer); + vm.prank(gatewayOwner); gateway.updateRoute(sampleRoute, SampleVerificationAddress, sig); assertEq(gateway.route("secret"), SampleVerificationAddress); @@ -449,8 +467,13 @@ contract ContractTest is Test { string memory sourceNetwork = "secret"; uint256 taskId = 1; + // callback + bytes20 callback_address = hex"7b226d795f76616c7565223a327d"; + bytes4 callback_selector = hex"faef40fe"; + bytes4 callback_gas_limit = bytes4(uint32(300000)); + // payload - bytes32 payloadHash = hex"ea57f8cfce0dca7528ff349328b9a524dbbd49fe724026da575aed40cd3ac2c4"; + bytes32 payloadHash = hex"fa6ec6995359ca7c7ea6602443f212e8295b9407cfa9f1f04c4651df345453fa"; // result bytes memory result = hex"7b226d795f76616c7565223a327d"; @@ -469,12 +492,15 @@ contract ContractTest is Test { result_hash: resultHash, result_signature: resultSignature, packet_hash: packetHash, - packet_signature: packetSignature + packet_signature: packetSignature, + callback_address: callback_address, + callback_selector: callback_selector, + callback_gas_limit: callback_gas_limit }); gateway.postExecution(taskId, sourceNetwork, assembledInfo); - (,,,,bool tempCompleted) = gateway.tasks(1); + (,bool tempCompleted) = gateway.tasks(1); assertEq(tempCompleted, true); } } \ No newline at end of file diff --git a/TNLS-Gateways/secret/contract.wasm.gz b/TNLS-Gateways/secret/contract.wasm.gz index e746e6b..798ed1a 100644 Binary files a/TNLS-Gateways/secret/contract.wasm.gz and b/TNLS-Gateways/secret/contract.wasm.gz differ diff --git a/TNLS-Gateways/secret/src/contract.rs b/TNLS-Gateways/secret/src/contract.rs index ba4e735..12e4fd2 100644 --- a/TNLS-Gateways/secret/src/contract.rs +++ b/TNLS-Gateways/secret/src/contract.rs @@ -164,12 +164,7 @@ fn pre_execution(deps: DepsMut, _env: Env, msg: PreExecutionMsg) -> StdResult StdResult StdResult StdResult< .get(deps.storage, &msg.task_id) .ok_or_else(|| StdError::generic_err("task id not found"))?; - // this panics in unit tests - #[cfg(target_arch = "wasm32")] - TASK_MAP.remove(deps.storage, &msg.task_id)?; - // verify that input hash is correct one for Task ID if msg.input_hash.as_slice() != task_info.input_hash.to_vec() { return Err(StdError::generic_err("input hash does not match task id")); @@ -287,17 +297,8 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult< // used in production to create signatures // NOTE: api.secp256k1_sign() will perform an additional sha_256 hash operation on the given data #[cfg(target_arch = "wasm32")] - let result_signature = { - // let sk = PrivateKey::parse(&signing_key_bytes)?; - // let result_signature = sk.sign(&result_hash, deps.api).serialize().to_vec(); - - let result_signature = deps - .api - .secp256k1_sign(&result_hash, &signing_key_bytes) - .map_err(|err| StdError::generic_err(err.to_string()))?; - - result_signature - }; + let result_signature = deps.api.secp256k1_sign(&result_hash, &signing_key_bytes) + .map_err(|err| StdError::generic_err(err.to_string()))?; // used only in unit testing to create signatures #[cfg(not(target_arch = "wasm32"))] @@ -344,12 +345,6 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult< .secp256k1_sign(&packet_hash, &signing_key_bytes) .map_err(|err| StdError::generic_err(err.to_string()))? }; - // let packet_signature = { - // PrivateKey::parse(&signing_key_bytes)? - // .sign(&packet_hash, deps.api) - // .serialize() - // .to_vec() - // }; // used only in unit testing to create signature #[cfg(not(target_arch = "wasm32"))] diff --git a/TNLS-Relayers/eth_abi.json b/TNLS-Relayers/eth_abi.json deleted file mode 100644 index 539113f..0000000 --- a/TNLS-Relayers/eth_abi.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallbackError","type":"error"},{"inputs":[],"name":"InvalidPacketSignature","type":"error"},{"inputs":[],"name":"InvalidPayloadHash","type":"error"},{"inputs":[],"name":"InvalidResultSignature","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureLength","type":"error"},{"inputs":[],"name":"InvalidSignatureSValue","type":"error"},{"inputs":[],"name":"TaskAlreadyCompleted","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"taskId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"result","type":"bytes"}],"name":"ComputedResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"task_id","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"result_hash","type":"bytes32"}],"name":"logCompletedTask","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"task_id","type":"uint256"},{"indexed":false,"internalType":"string","name":"source_network","type":"string"},{"indexed":false,"internalType":"address","name":"user_address","type":"address"},{"indexed":false,"internalType":"string","name":"routing_info","type":"string"},{"indexed":false,"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"components":[{"internalType":"bytes","name":"user_key","type":"bytes"},{"internalType":"bytes","name":"user_pubkey","type":"bytes"},{"internalType":"string","name":"routing_code_hash","type":"string"},{"internalType":"string","name":"handle","type":"string"},{"internalType":"bytes12","name":"nonce","type":"bytes12"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"bytes","name":"payload_signature","type":"bytes"}],"indexed":false,"internalType":"struct Gateway.ExecutionInfo","name":"info","type":"tuple"}],"name":"logNewTask","type":"event"},{"inputs":[{"internalType":"uint256","name":"_taskId","type":"uint256"},{"internalType":"bytes","name":"_result","type":"bytes"}],"name":"callback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_masterVerificationAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"masterVerificationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_taskId","type":"uint256"},{"internalType":"string","name":"_sourceNetwork","type":"string"},{"components":[{"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"internalType":"bytes32","name":"result_hash","type":"bytes32"},{"internalType":"bytes32","name":"packet_hash","type":"bytes32"},{"internalType":"bytes20","name":"callback_address","type":"bytes20"},{"internalType":"bytes4","name":"callback_selector","type":"bytes4"},{"internalType":"bytes4","name":"callback_gas_limit","type":"bytes4"},{"internalType":"bytes","name":"packet_signature","type":"bytes"},{"internalType":"bytes","name":"result_signature","type":"bytes"},{"internalType":"bytes","name":"result","type":"bytes"}],"internalType":"struct Gateway.PostExecutionInfo","name":"_info","type":"tuple"}],"name":"postExecution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_payloadHash","type":"bytes32"},{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"string","name":"_sourceNetwork","type":"string"},{"internalType":"string","name":"_routingInfo","type":"string"},{"components":[{"internalType":"bytes","name":"user_key","type":"bytes"},{"internalType":"bytes","name":"user_pubkey","type":"bytes"},{"internalType":"string","name":"routing_code_hash","type":"string"},{"internalType":"string","name":"handle","type":"string"},{"internalType":"bytes12","name":"nonce","type":"bytes12"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"bytes","name":"payload_signature","type":"bytes"}],"internalType":"struct Gateway.ExecutionInfo","name":"_info","type":"tuple"}],"name":"send","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_route","type":"string"},{"internalType":"address","name":"_verificationAddress","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"updateRoute","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/TNLS-Relayers/relayer.py b/TNLS-Relayers/relayer.py index d066452..151e612 100644 --- a/TNLS-Relayers/relayer.py +++ b/TNLS-Relayers/relayer.py @@ -39,58 +39,12 @@ def __init__(self, dict_of_names_to_interfaces: Dict[str, Tuple[BaseChainInterface, BaseContractInterface, str, str]], num_loops=None): - # Load .env file - load_dotenv() - - # Read variables from .env - gatewayAddress = os.getenv('GATEWAY_ADDRESS') - eth_private_key = os.getenv('ETH_PRIVATE_KEY') - eth_address = os.getenv('ETH_ADDRESS') - scrt_private_key = os.getenv('SCRT_PRIVATE_KEY') - scrt_address = os.getenv('SCRT_ADDRESS') - scrt_contract_address = os.getenv('SCRT_CONTRACT_ADDRESS') - scrt_api_url = os.getenv('SCRT_API_URL') - scrt_chain_id = os.getenv('SCRT_CHAIN_ID') - verification_key = os.getenv('VERIFICATION_KEY') - encryption_key = os.getenv('ENCRYPTION_KEY') - - # Load ABI files - eth_abi = json.load(open("eth_abi.json", 'r')) - scrt_abi = json.dumps(json.load(open("secret_abi.json", 'r'))) - - # Initialize Ethereum Interface and Contract - eth_base_interface = EthInterface(private_key=eth_private_key, address=eth_address, - contract_address=gatewayAddress) - eth_contract_interface = EthContract(interface=eth_base_interface, address=gatewayAddress, abi=eth_abi) - - # Initialize Secret Interface and Contract - scrt_base_interface = SCRTInterface(private_key=scrt_private_key, address=scrt_address, api_url=scrt_api_url, - chain_id=scrt_chain_id, provider=None) - scrt_contract_interface = SCRTContract(interface=scrt_base_interface, - address=scrt_contract_address, abi=scrt_abi) - - # Setup keys dictionary - keys_dict = { - 'secret-4': { - 'verification': verification_key, - 'encryption': encryption_key - } - } """ - Encryption key: AjvNv1VH/B96I4vi6jdhS3vHsjxvXK4VS6tylhpW7keg - Public key: 0x043bcdbf5547fc1f7a238be2ea37614b7bc7b23c6f5cae154bab72961a56ee47a0b711ae0f62f0a6955045fa9e424379c296085cd8f1511caf33685f430ab15dde - Eth Address: 0x3211F7521F9d0eD3c4E45e4e7989df2652f2c0EC - Implementation of the BaseChainInterface standard for the Secret Network - NOTE: the below default private key is for testing only, and does not correspond to any real account/wallet """ - # Create the tuple - eth_tuple = (eth_base_interface, eth_contract_interface, 'logNewTask', 'postExecution') - scrt_tuple = (scrt_base_interface, scrt_contract_interface, 'wasm', 'inputs') - # Create the dictionary and add the tuple - self.dict_of_names_to_interfaces = {'11155111': eth_tuple,'secret-4': scrt_tuple} + self.dict_of_names_to_interfaces = dict_of_names_to_interfaces """ Args: @@ -136,11 +90,10 @@ def process_transaction(self, transaction, name, contract_interface, evt_name): def poll_for_transactions(self): for name, (chain_interface, contract_interface, evt_name, _) in self.dict_of_names_to_interfaces.items(): - if name == 'secret-4' or name == 'pulsar-3': + if name == 'secret-4' or name == 'pulsar-3' or name == 'secret': continue prev_height = self.dict_of_names_to_blocks[name] curr_height = chain_interface.get_last_block() - #curr_height = 5029638 if prev_height is None: prev_height = curr_height - 1 diff --git a/TNLS-Relayers/web_app.py b/TNLS-Relayers/web_app.py index 96869bc..3335117 100644 --- a/TNLS-Relayers/web_app.py +++ b/TNLS-Relayers/web_app.py @@ -9,9 +9,10 @@ from eth_interface import EthInterface, EthContract from relayer import Relayer from scrt_interface import SCRTInterface, SCRTContract +from dotenv import load_dotenv base_map = {'Ethereum': (EthInterface, EthContract), 'Secret': (SCRTInterface, SCRTContract)} - +load_dotenv() def generate_eth_config(config_dict, provider=None): """ diff --git a/config.yml b/config.yml index 905c14e..ef0b108 100644 --- a/config.yml +++ b/config.yml @@ -1,10 +1,10 @@ ethereum: - contract_address: "INSERT_ETHEREUM_CONTRACT_ADDRESS_HERE" - contract_schema: '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidPayloadHash","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"task_id","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"result_hash","type":"bytes32"}],"name":"logCompletedTask","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"task_id","type":"uint256"},{"indexed":false,"internalType":"string","name":"source_network","type":"string"},{"indexed":false,"internalType":"address","name":"user_address","type":"address"},{"indexed":false,"internalType":"string","name":"routing_info","type":"string"},{"indexed":false,"internalType":"string","name":"routing_code_hash","type":"string"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"payload_signature","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"user_key","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"user_pubkey","type":"bytes"},{"indexed":false,"internalType":"string","name":"handle","type":"string"},{"indexed":false,"internalType":"bytes12","name":"nonce","type":"bytes12"}],"name":"logNewTask","type":"event"},{"inputs":[{"internalType":"address","name":"_masterVerificationAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"masterVerificationAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_taskId","type":"uint256"},{"internalType":"string","name":"_sourceNetwork","type":"string"},{"components":[{"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"internalType":"bytes","name":"result","type":"bytes"},{"internalType":"bytes32","name":"result_hash","type":"bytes32"},{"internalType":"bytes","name":"result_signature","type":"bytes"},{"internalType":"bytes32","name":"packet_hash","type":"bytes32"},{"internalType":"bytes","name":"packet_signature","type":"bytes"}],"internalType":"struct Util.PostExecutionInfo","name":"_info","type":"tuple"}],"name":"postExecution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"callback_address","type":"address"},{"internalType":"bytes4","name":"callback_selector","type":"bytes4"},{"internalType":"address","name":"user_address","type":"address"},{"internalType":"string","name":"source_network","type":"string"},{"internalType":"string","name":"routing_info","type":"string"},{"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"internalType":"bool","name":"completed","type":"bool"}],"internalType":"struct Util.Task","name":"_task","type":"tuple"},{"components":[{"internalType":"bytes","name":"user_key","type":"bytes"},{"internalType":"bytes","name":"user_pubkey","type":"bytes"},{"internalType":"string","name":"routing_code_hash","type":"string"},{"internalType":"string","name":"handle","type":"string"},{"internalType":"bytes12","name":"nonce","type":"bytes12"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"bytes","name":"payload_signature","type":"bytes"}],"internalType":"struct Util.ExecutionInfo","name":"_info","type":"tuple"}],"name":"preExecution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"route","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taskId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tasks","outputs":[{"internalType":"address","name":"callback_address","type":"address"},{"internalType":"bytes4","name":"callback_selector","type":"bytes4"},{"internalType":"address","name":"user_address","type":"address"},{"internalType":"string","name":"source_network","type":"string"},{"internalType":"string","name":"routing_info","type":"string"},{"internalType":"bytes32","name":"payload_hash","type":"bytes32"},{"internalType":"bool","name":"completed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_route","type":"string"},{"internalType":"address","name":"_verificationAddress","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"updateRoute","outputs":[],"stateMutability":"nonpayable","type":"function"}]' - wallet_address: "0xCe89F0FFa695865d8EbaE7e544541a23FE7f6674" + contract_address: "0x95D5404f0b750F7904D1a1087f696E8Dcd8223aD" + contract_schema: '[{"type":"function","name":"callback","inputs":[{"name":"_taskId","type":"uint256","internalType":"uint256"},{"name":"_result","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"initialize","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"masterVerificationAddress","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"postExecution","inputs":[{"name":"_taskId","type":"uint256","internalType":"uint256"},{"name":"_sourceNetwork","type":"string","internalType":"string"},{"name":"_info","type":"tuple","internalType":"struct Gateway.PostExecutionInfo","components":[{"name":"payload_hash","type":"bytes32","internalType":"bytes32"},{"name":"result_hash","type":"bytes32","internalType":"bytes32"},{"name":"packet_hash","type":"bytes32","internalType":"bytes32"},{"name":"callback_address","type":"bytes20","internalType":"bytes20"},{"name":"callback_selector","type":"bytes4","internalType":"bytes4"},{"name":"callback_gas_limit","type":"bytes4","internalType":"bytes4"},{"name":"packet_signature","type":"bytes","internalType":"bytes"},{"name":"result_signature","type":"bytes","internalType":"bytes"},{"name":"result","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"requestRandomness","inputs":[{"name":"_numWords","type":"uint32","internalType":"uint32"},{"name":"_callbackGasLimit","type":"uint32","internalType":"uint32"}],"outputs":[{"name":"requestId","type":"uint256","internalType":"uint256"}],"stateMutability":"payable"},{"type":"function","name":"route","inputs":[{"name":"","type":"string","internalType":"string"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"send","inputs":[{"name":"_payloadHash","type":"bytes32","internalType":"bytes32"},{"name":"_userAddress","type":"address","internalType":"address"},{"name":"_routingInfo","type":"string","internalType":"string"},{"name":"_info","type":"tuple","internalType":"struct Gateway.ExecutionInfo","components":[{"name":"user_key","type":"bytes","internalType":"bytes"},{"name":"user_pubkey","type":"bytes","internalType":"bytes"},{"name":"routing_code_hash","type":"string","internalType":"string"},{"name":"handle","type":"string","internalType":"string"},{"name":"nonce","type":"bytes12","internalType":"bytes12"},{"name":"payload","type":"bytes","internalType":"bytes"},{"name":"payload_signature","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"setMasterVerificationAddress","inputs":[{"name":"_masterVerificationAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"taskId","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"tasks","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"payload_hash_reduced","type":"bytes31","internalType":"bytes31"},{"name":"completed","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"updateRoute","inputs":[{"name":"_route","type":"string","internalType":"string"},{"name":"_verificationAddress","type":"address","internalType":"address"},{"name":"_signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"ComputedResult","inputs":[{"name":"taskId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"result","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"name":"version","type":"uint64","indexed":false,"internalType":"uint64"}],"anonymous":false},{"type":"event","name":"logCompletedTask","inputs":[{"name":"task_id","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"payload_hash","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"result_hash","type":"bytes32","indexed":false,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"logNewTask","inputs":[{"name":"task_id","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"source_network","type":"string","indexed":false,"internalType":"string"},{"name":"user_address","type":"address","indexed":false,"internalType":"address"},{"name":"routing_info","type":"string","indexed":false,"internalType":"string"},{"name":"payload_hash","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"info","type":"tuple","indexed":false,"internalType":"struct Gateway.ExecutionInfo","components":[{"name":"user_key","type":"bytes","internalType":"bytes"},{"name":"user_pubkey","type":"bytes","internalType":"bytes"},{"name":"routing_code_hash","type":"string","internalType":"string"},{"name":"handle","type":"string","internalType":"string"},{"name":"nonce","type":"bytes12","internalType":"bytes12"},{"name":"payload","type":"bytes","internalType":"bytes"},{"name":"payload_signature","type":"bytes","internalType":"bytes"}]}],"anonymous":false},{"type":"error","name":"CallbackError","inputs":[]},{"type":"error","name":"InvalidInitialization","inputs":[]},{"type":"error","name":"InvalidPacketSignature","inputs":[]},{"type":"error","name":"InvalidPayloadHash","inputs":[]},{"type":"error","name":"InvalidResultSignature","inputs":[]},{"type":"error","name":"InvalidSignature","inputs":[]},{"type":"error","name":"InvalidSignatureLength","inputs":[]},{"type":"error","name":"InvalidSignatureSValue","inputs":[]},{"type":"error","name":"NotInitializing","inputs":[]},{"type":"error","name":"TaskAlreadyCompleted","inputs":[]}]' + wallet_address: "0x50FcF0c327Ee4341313Dd5Cb987f0Cd289Be6D4D" secret: - contract_address: "INSERT_SECRET_CONTRACT_ADDRESS_HERE" - wallet_address: "secret1y47aa30tmezpld4npjpad20zl9v76sn8j2nml2" - contract_encryption_key: "INSERT_SECRET_CONTRACT_ENCRYPTION_KEY_HERE" - contract_eth_address: "INSERT_SECRET_CONTRACT_ETH_ADDRESS_HERE" \ No newline at end of file + contract_address: "secret1vhry3y22sjw46x5aa9hfuzxt7rxnu87sdkz4yy" + wallet_address: "secret1w3s62kcqlhv3l3rplegnyvp0e5hlrsyrw79htv" + contract_encryption_key: "AjvNv1VH/B96I4vi6jdhS3vHsjxvXK4VS6tylhpW7keg" + contract_eth_address: "0x5b5274c2ae6aA29B6e94048878a61814594D3409"