Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
SecretSaturn committed Jan 12, 2024
1 parent 04961dd commit 557d9aa
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 231 deletions.
33 changes: 5 additions & 28 deletions TNLS-Clients/VRFDemo/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,15 @@ import { setupSubmit } from './submit'

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<header>
<h1>Atbash Labs</h1>
<div id="links">
<a href="">
<div class="card">
Whitepaper
</div>
</a>
<a href="">
<div class="card">
GitHub
</div>
</a>
<a href="">
<div class="card">
Docs
</div>
</a>
</div>
<h1>Secret VRF on Ethereum</h1>
</header>
<div>
<h2>Sample Application: Random Number Generation using Secret VRF</h2>
<h2>Sample Application: Roll the Dice!</h2>
<h2>Random Number Generation using Secret VRF, bridged into EVM.</h2>
<h3>This demo generates 2000 verifiable random numbers in just one transaction.</h3>
<div id="form">
<button id="submit">Submit</button>
<button id="submit">Roll the dice </button>
<form name="inputForm">
<br>
<label for="input1">Number of Random Words (up to 50)</label>
<input type="number" placeholder="$" id="input1" name="input1" />
<br>
<br>
<label for="input2">Callback gas limit</label>
<input type="text" placeholder="$" id="input2" name="input2" />
<br>
</div>
<div id="preview" style="word-wrap: break-word;">
Expand Down
93 changes: 49 additions & 44 deletions TNLS-Clients/VRFDemo/src/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement>('#preview')!.innerHTML = `
<h2>Raw Payload</h2>
<p>${thePayload}</p>
<h2>TNLS Payload</h2>
<p>${ciphertext.toString('base64')}</p>
<h2>Payload Hash</h2>
<p>${payloadHash}<p>

<h2>Payload Signature</h2>
<p>${payloadSignature}<p>
// 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<HTMLDivElement>('#preview')!.innerHTML = `
</p>
<h2>Transaction Parameters</h2>
<p><b>Request ID: ${requestId} </b></p>
<p><b>Random Words: ${randomWords} </b></p>
<p style="font-size: 0.8em;">${JSON.stringify(tx_params)}</p>
`
}
});
});

<h2>Other Info</h2>
<p>
<b>Public key used during encryption:</b> ${userPublicKey} <br>
<b>Nonce used during encryption:</b> ${nonce} <br>
document.querySelector<HTMLDivElement>('#preview')!.innerHTML = `
</p>
<h2>Transaction Parameters</h2>
<p><b>Tx Hash: </b><a href="https://polygonscan.com/tx/${txHash}" target="_blank">${txHash}</a></p>
<p><b>Gateway Address (to check the postExecution callback) </b><a href="https://polygonscan.com/address/${publicClientAddress}" target="_blank">${publicClientAddress}</a></p>
<p><b>Tx Hash: </b><a href="https://sepolia.etherscan.io/tx/${txHash}" target="_blank">${txHash}</a></p>
<p><b>Gateway Address (to check the postExecution callback) </b><a href="https://sepolia.etherscan.io/address/${randomnessContract}" target="_blank">${randomnessContract}</a></p>
<p style="font-size: 0.8em;">${JSON.stringify(tx_params)}</p>
`

})
}
// <p><b>Tx Hash: </b><a href="https://sepolia.etherscan.io/tx/${txHash}" target="_blank">${txHash}</a></p>
//<p><b>Gateway Address (to check the postExecution callback) </b><a href="https://sepolia.etherscan.io/address/${publicClientAddress}" target="_blank">${publicClientAddress}</a></p>
//<p style="font-size: 0.8em;">${JSON.stringify(tx_params)}</p>
}
3 changes: 2 additions & 1 deletion TNLS-Gateways/public-gateway/script/DeployScript.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ contract DeployScript is Script {
TransparentUpgradeableProxy gatewayProxy;
RandomnessReciever randomnessAddress;

address verificationAddress = 0x5b5274c2ae6aA29B6e94048878a61814594D3409;

uint256 privKey = vm.envUint("ETH_PRIVATE_KEY");


Expand Down Expand Up @@ -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";
Expand Down
23 changes: 7 additions & 16 deletions TNLS-Gateways/public-gateway/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -73,7 +66,6 @@ contract Gateway is Initializable {
/// @dev mapping of chain name string to the verification address
mapping(string => address) public route;


/*//////////////////////////////////////////////////////////////
Errors
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -249,6 +242,7 @@ contract Gateway is Initializable {
//////////////////////////////////////////////////////////////*/

/// @notice Replaces the constructor for upgradeable contracts

function initialize() public initializer {
owner = msg.sender;
taskId = 1;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions TNLS-Gateways/public-gateway/src/RandomnessReciever.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 557d9aa

Please sign in to comment.