Skip to content

Commit 7c040db

Browse files
committed
wip: Impossible to get requestValue to work so documented reasons why, use send function instead
1 parent 47fa5ec commit 7c040db

File tree

5 files changed

+128
-145
lines changed

5 files changed

+128
-145
lines changed

packages/hardhat/contracts/Gateway.sol

+53-88
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ contract Gateway is Ownable, Utils, Base64 {
5858

5959
bytes public owner_public_key;
6060

61-
bytes28 public gatewayAddressBase64 = encodeAddressToBase64(address(this));
61+
bytes28 public nunyaAddressBase64 = encodeAddressToBase64(address(owner));
6262

6363
/*//////////////////////////////////////////////////////////////
6464
Structs
@@ -111,7 +111,9 @@ contract Gateway is Ownable, Utils, Base64 {
111111
Helpers
112112
//////////////////////////////////////////////////////////////*/
113113

114-
function ethSignedPayloadHash(bytes memory payload) public pure returns (bytes32 payloadHash) {
114+
// Note: Why isn't a random nonce used to generate this, similar to how that
115+
// is done in encryptPayload.ts to generate the payloadHash there?
116+
function ethSignedPayloadHash(bytes memory payload) public pure returns (bytes32 payloadHash) {
115117
assembly {
116118
// Take scratch memory for the data to hash
117119
let data := mload(0x40)
@@ -230,13 +232,17 @@ contract Gateway is Ownable, Utils, Base64 {
230232
console.log("------ Gateway.prepareResultBytesToCallbackData - _taskId: ", _taskId);
231233
console.log("------ Gateway.prepareResultBytesToCallbackData - data.length: ", data.length);
232234
assembly {
233-
result := mload(0x40)
234-
mstore(result, add(100, data.length))
235-
mstore(add(result, 32), callback_selector)
236-
mstore(add(result, 36), _taskId)
237-
mstore(add(result, 68), 0x40)
238-
mstore(add(result, 100), data.length)
235+
result := mload(0x40) // Set `result` to point to the free memory pointer
236+
mstore(result, add(100, data.length)) // Update the free memory pointer
237+
mstore(add(result, 32), callback_selector) // Load `callback_selector` and store at `result` + 32
238+
mstore(add(result, 36), _taskId) // Load `_taskId` and store at `result` + 36
239+
mstore(add(result, 68), 0x40) // Load `0x40` (free memory pointer) and store at `result` + 68
240+
mstore(add(result, 100), data.length) // Load `data.length` and store at `result` + 100
241+
// Directly copy data from the transaction's call data (read only)
242+
// that was the input data sent with the call into memory
239243
calldatacopy(add(result, 132), data.offset, data.length)
244+
// Update the free memory pointer with that
245+
// loaded from `data.length` and stored at `result` + 132 bytes
240246
mstore(0x40, add(add(result, 132), data.length))
241247
}
242248
}
@@ -549,88 +555,45 @@ contract Gateway is Ownable, Utils, Base64 {
549555
// Hex value of `owner_public_key` is: 0x038318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75
550556
// In base64 it is A4MYU1tUEF1Keq5gwI/EX5aHGBtP38YlvRp1P6c5f+11
551557
// bytes memory userKey = bytes.concat(owner_public_key);
552-
//
553-
// INFO [enclave_contract_engine::wasm3] debug_print: "Decryption failed: GenericErr {\n msg: \"malformed public key\",\n}"
554-
// INFO [enclave_contract_engine::wasm3] debug_print: "verify the internal verification key matches the user address"
555-
// INFO [enclave_contract_engine::wasm3] debug_print: "msg.user_key: Binary(41344d59553174554546314b6571356777492f4558356148474274503338596c7652703150366335662b3131)"
556-
// INFO [enclave_contract_engine::wasm3] debug_print: "payload.user_key: Binary(038318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75)"
557-
558+
558559
// secret1glfedwlusunwly7q05umghzwl6nf2vj6wr38fg
559560
// note: used as the 'admin' when instantiating the Secret Gateway
560561
// hex equivalent: 0382be33224d9cd71db7bf129dc8e102b2d63670d11daa64645b1e9a399ff7fec0
561562
bytes memory userKey = bytes.concat("A4K+MyJNnNcdt78SncjhArLWNnDRHapkZFsemjmf9/7A");
562563

563-
// 04d0ce1bd101c1a2a130185e4c63d1d7091db9ab0dca3c651998d314a1550323c02649b0960b00bb1fac896aaf4056abb605e87d55ec1805a91ddb3e32c6b89c36
564-
// base64 value: BNDOG9EBwaKhMBheTGPR1wkduasNyjxlGZjTFKFVAyPAJkmwlgsAux+siWqvQFartgXofVXsGAWpHds+Msa4nDY=
565-
// bytes memory userKey = bytes.concat(encode(hex"04d0ce1bd101c1a2a130185e4c63d1d7091db9ab0dca3c651998d314a1550323c02649b0960b00bb1fac896aaf4056abb605e87d55ec1805a91ddb3e32c6b89c36"));
566-
// bytes memory userKey = bytes.concat("BNDOG9EBwaKhMBheTGPR1wkduasNyjxlGZjTFKFVAyPAJkmwlgsAux+siWqvQFartgXofVXsGAWpHds+Msa4nDY=");
567-
568-
// 04d0ce1bd101c1a2a130185e4c63d1d7091db9ab0dca3c651998d314a1550323c02649b0960b00bb1fac896aaf4056abb605e87d55ec1805a91ddb3e32c6b89c36
569-
// bytes memory gatewayContractPubkey = hex"04d0ce1bd101c1a2a130185e4c63d1d7091db9ab0dca3c651998d314a1550323c02649b0960b00bb1fac896aaf4056abb605e87d55ec1805a91ddb3e32c6b89c36";
570-
571-
// 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
572-
// Hex value of `owner_public_key` is: 0x038318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75
573-
// bytes memory userPubkey = hex"038318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed75";
574-
575-
// FIXME: Probably wrong, it should be generated like this https://docs.scrt.network/secret-network-documentation/confidential-computing-layer/ethereum-evm-developer-toolkit/usecases/vrf/using-encrypted-payloads-for-vrf#signing-the-payload-with-metamask
576-
// and likely different from `userKey`
577564
// Output of encodePayload.ts `user_pubkey`
578565
// 0x048318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5
579566
// base64: BIMYU1tUEF1Keq5gwI/EX5aHGBtP38YlvRp1P6c5f+11NUfxHKhpZkby86ywjjEBavrCPmMMXRH1n2H+9XsNKqU=
580567
bytes memory userPubkey = bytes.concat("BIMYU1tUEF1Keq5gwI/EX5aHGBtP38YlvRp1P6c5f+11NUfxHKhpZkby86ywjjEBavrCPmMMXRH1n2H+9XsNKqU=");
581568

582-
// Gateway contract public key
583-
// Generated from ./packages/secret-contracts-scripts/src/functions/secretpath/generateKeys.ts
584-
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
585-
// converted to base64: QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=
586-
587-
// INFO [enclave_contract_engine::wasm3] debug_print: "Decryption failed: GenericErr {\n msg: \"malformed public key\",\n}"
588-
// INFO [enclave_contract_engine::wasm3] debug_print: "verify the internal verification key matches the user address"
589-
// INFO [enclave_contract_engine::wasm3] debug_print: "msg.user_key: Binary(4141414141414141414141414141414141414141414141414141414141414141414141414141414141414141)"
590-
// INFO [enclave_contract_engine::wasm3] debug_print: "payload.user_key: Binary(000000000000000000000000000000000000000000000000000000000000000000)"
591-
// bytes memory userKey = bytes.concat("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); // malformed public key
592-
593569
// Note: Since contracts only have an address, but not public keys, where the
594570
// addresses are derived from the address of the user (or other contract) that
595571
// created them, which are in turn are derived from the public key of a normal
596572
// user's keypair. So we will use the public key of the `owner` that created the
597573
// Gateway contract.
598574
//
599-
// TODO: We will use the base64 value for both the value of the `user_key` and
600-
// the `user_pubkey`, but they should be different and `user_key` suggested to
601-
// be base64 (e.g. `AAA=`)
602-
//
603575
// Note: In this custom Gateway.sol, the NunyaBusiness contract address is provided as an argument in its
604576
// constructor and set to be the `owner` in storage. Furthermore, we apply `onlyOwner` modifier to this
605577
// function that restricts calls to only be allowed to come from a `msg.sender` that is the same as the `owner`.
606578
// If it is `msg.sender` then it would allow a call to be made from anyone, even a "fake" NunyaBusiness contract
607579
// if `onlyOwner` was removed.
608580
// If the Gateway contract by the Secret team was used instead then we would need a way to upgrade that contract
609581
// to allow us to set an `owner`-like value that could be used to restrict calls to functions like this.
610-
// FIXME: Error parsing into type secret_gateway::types::Payload: Invalid unicode code point.: execute contract failed
611-
// TODO: Try changing to `"user_address":"0x0000","user_key":"AAA="`
612582
bytes memory payload_info = abi.encodePacked(
613583
'}","routing_info":"',routing_info,
614584
'","routing_code_hash":"',routing_code_hash,
615585
// '","user_address":"',address(owner), // Invalid unicode code point.
616-
'","user_address":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
586+
'","user_address":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // What is `address(msg.sender)`?
617587
// '","user_key":"',owner_public_key,
618588
// https://github.com/SecretSaturn/SecretPath/blob/main/TNLS-Gateways/secret/tests/integration.ts#L340
589+
// Note: `user_key` must be base64 value
619590
'","user_key":"',userKey,
591+
// Note: `callback_address` must be base64 value
620592
'","callback_address":"'
621593
// '","user_address":"0x0000","user_key":"AAA=","callback_address":"'
622594
);
623-
624-
//
625-
// // Generic error: verification key mismatch
626-
// bytes memory payload_info = abi.encodePacked(
627-
// '}","routing_info":"',routing_info,
628-
// '","routing_code_hash":"',routing_code_hash,
629-
// '","user_address":"',address(msg.sender),
630-
// '","user_key":"',senderAddressBase64,
631-
// '","callback_address":"'
632-
// );
633-
// console.log("------ Gateway.requestValue - payload_info: ", payload_info);
595+
console.log("------ Gateway.requestValue - msg.sender: ", msg.sender);
596+
console.log("------ Gateway.requestValue - payload_info: ", payload_info);
634597

635598
// uint32 _myArg = 123;
636599
//construct the payload that is sent into the Secret Gateway
@@ -640,63 +603,67 @@ contract Gateway is Ownable, Utils, Base64 {
640603
'{"data":"{\\"myArg\\":',
641604
uint256toBytesString(123),
642605
payload_info,
643-
// callback_address should be this EVM Gateway address, the `publicClientAddress` in this example
606+
// callback_address in this example is the EVM Gateway address (the `publicClientAddress`)
607+
// but our callback_selector is in NunyaBusiness.sol so we need to use that instead.
644608
// https://docs.scrt.network/secret-network-documentation/confidential-computing-layer/ethereum-evm-developer-toolkit/usecases/vrf/using-encrypted-payloads-for-vrf#defining-variables
645-
gatewayAddressBase64, //callback_address
609+
// Note: `callback_address` must be base64 value
610+
nunyaAddressBase64, //callback_address
646611
// callback selector should be a hex value already converted into base64 to be used
647612
// as callback_selector of the request_value function in the Secret contract
648613
// FIXME: Error parsing into type secret_gateway::types::Payload: invalid base64: 259716626: execute contract failed
649614
// '","callback_selector":"',uint256toBytesString(_callbackSelector),
615+
// Note: `callback_address` must be base64 value
650616
// Note: fulfilledValueCallback - 0x0f7af612 hex, D3r2Eg== base64. Example: fulfillRandomWords - 0x38ba4614 hex, OLpGFA== base64
651617
'","callback_selector":"D3r2Eg==","callback_gas_limit":',uint256toBytesString(_callbackGasLimit),
652618
'}'
653619
);
654-
//
655-
// // Generic error: verification key mismatch
656-
// bytes memory payload = bytes.concat(
657-
// '{"data":"{\\"myArg\\":',
658-
// uint256toBytesString(123),
659-
// payload_info,
660-
// senderAddressBase64, //callback_address
661-
// '","callback_selector":"OLpGFA==","callback_gas_limit":', // 0x38ba4614 hex value already converted into base64, callback_selector of the fullfillRandomWords function
662-
// uint256toBytesString(_callbackGasLimit),
663-
// '}'
664-
// );
665-
// console.log("------ Gateway.requestValue - payload: ", payload);
666620

621+
// FIXME: This should be a random nonce and generated similar to
622+
// how it is generated in encryptPayload.ts using `window.crypto.getRandomValues(bytes(12))`
667623
uint256 _newNonce = nonce + 1;
668624
increaseNonce(_newNonce);
669625
console.log("------ Gateway.requestValue - _newNonce: ", _newNonce);
670626

671627
//generate the payload hash using the ethereum hash format for messages
672628
bytes32 payloadHash = ethSignedPayloadHash(payload);
673-
// console.log("------ Gateway.requestValue - payloadHash: ", payloadHash);
629+
console.log("------ Gateway.requestValue - payloadHash: ", payloadHash);
630+
631+
// FIXME: Even though we have generated the payloadHash, we haven't done it using the
632+
// `sharedKey` that would be generated using generateKeys.ts, the same way we have done that
633+
// in encryptPayload.ts, but neither of those TypeScript files are being used to provide inputs
634+
// to this `requestValue` function, as they are only being used in the submitReqestValue.ts
635+
// script that calls the `send` function in the Gateway.sol directly and does the encryption
636+
// in TypeScript before sending the transaction to call `send`.
637+
// It may be necessary to provide the `sharedKey` and `nonce` encrypted into this `requestValue` function
638+
// and use them to generate the payload, but then we may as well just prepare all the
639+
// relevant information in TypeScript and send it via NunyaBusiness to `send`.
640+
641+
// FIXME: How to generate payloadSignature??
642+
// We should be providing it to the smart contract and verifying it is valid here
643+
// https://ethereum.stackexchange.com/questions/24367/is-it-possible-to-sign-a-message-in-solidity
644+
const payloadSignature = ...
674645

675-
bytes memory emptyBytes = hex"0000";
646+
// FIXME: Do not know how to recover public key using Solidity this way,
647+
// only know how to do it in TypeScript.
648+
uint256 userPubkeyRecovered = recoverPublicKey(payloadHash, payloadSignature);
676649

677-
// TODO - make `user_key` a unique key different from `user_pubkey`
678-
// bytes memory userKey = bytes.concat(senderAddressBase64); // equals AAA= in base64
650+
bytes memory emptyBytes = hex"0000"; // equals AAA= in base64
679651

680652
// ExecutionInfo struct
681653
ExecutionInfo memory executionInfo = ExecutionInfo({
682-
// user_key: gatewayContractPubkey,
683-
user_key: userKey,
684-
// user_key: userKey, // FIXME - use this instead when resolve issue
685-
// user_key: emptyBytes, // equals AAA= in base64
686-
// FIXME: use of `secret_gateway_signer_pubkey` does not compile, what alternative to use?
687-
// user_pubkey: uint256toBytesString(secret_gateway_signer_pubkey),
654+
// Note: `user_key` and `user_pubkey` here are in bytes, NOT base64 like in the `payload`
655+
user_key: userKey, // emptyBytes,
656+
// user_pubkey: uint256toBytesString(userPubkeyRecovered),
688657
// Refer to ./packages/secret-contracts/secret-gateway/src/msg.rs that shows
689658
// what to use for `user_key` and `user_pubkey`, as they are different
690-
user_pubkey: userPubkey,
691-
// user_pubkey: userKey,
692-
// user_pubkey: emptyBytes, // Fill with 0 bytes
659+
user_pubkey: userPubkey, // emptyBytes,
693660
routing_code_hash: routing_code_hash, // custom contract codehash on Secret
694661
task_destination_network: task_destination_network,
695662
handle: "request_value",
696663
nonce: bytes12(toBytes(_newNonce)),
697664
callback_gas_limit: _callbackGasLimit,
698665
payload: payload,
699-
// TODO: add a payload signature
666+
// FIXME: add a payload signature, as it `payloadHash` is incorrect
700667
// Signature of hash of encrypted input values
701668
// payload_signature: emptyBytes // empty signature, fill with 0 bytes
702669
payload_signature: bytes32ToBytes(payloadHash)
@@ -770,9 +737,7 @@ contract Gateway is Ownable, Utils, Base64 {
770737
'{"data":"{\\"callbackSelector\\":',
771738
uint256toBytesString(_callbackSelector),
772739
payload_info,
773-
// callback_address should be this EVM Gateway address, the `publicClientAddress` in this example
774-
// https://docs.scrt.network/secret-network-documentation/confidential-computing-layer/ethereum-evm-developer-toolkit/usecases/vrf/using-encrypted-payloads-for-vrf#defining-variables
775-
gatewayAddressBase64, //callback_address
740+
nunyaAddressBase64, //callback_address
776741
'","callback_selector":"OLpGFA==","callback_gas_limit":', // 0x38ba4614 hex value already converted into base64, callback_selector of the fulfillRandomWords function
777742
uint256toBytesString(_callbackGasLimit),
778743
'}'

packages/hardhat/contracts/NunyaBusiness.sol

+2-9
Original file line numberDiff line numberDiff line change
@@ -155,18 +155,11 @@ contract NunyaBusiness is Ownable, Utils {
155155

156156
/// @notice Callback by the CustomGateway with the requested value
157157
/// @param _requestId requestId of the request that was initally called
158-
/// @param data Value in bytes
158+
/// @param data Value in bytes in base64 representation
159159
function fulfilledValueCallback(uint256 _requestId, bytes calldata data) external onlyGateway {
160160
console.log("fulfilledValueCallback - _requestId: ", _requestId);
161161
console.log("fulfilledValueCallback - data.length: ", data.length);
162-
163-
// TODO: Obtain the following from the `data`
164-
// uint256 _request_id: task.clone(), uint256 _value (or _key), uint16 _code, address _nunya_business_contract_address
165-
166-
// console.log("fulfilledValueCallback - requestId", _requestId);
167-
// console.log("fulfilledValueCallback - value", _value);
168-
// console.log("fulfilledValueCallback - code", _code);
169-
// console.log("fulfilledValueCallback - nunya_business_contract_address", _nunya_business_contract_address);
162+
// Example `data` value: {"_request_id":{"network":"31337","task_id":"10"},"_key":[78,85,78,89,65],"_code":0,"_nunya_business_contract_address":"0xAFFF311821C3F3AF863C7103BB17BDC1Ba04603D"}
170163

171164
// emit FulfilledValue(_requestId, _value, _code, _nunya_business_contract_address);
172165
emit FulfilledValue(_requestId, data);

0 commit comments

Comments
 (0)