Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion _SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Continue with [Run Services](#run-services).

* Run the following to start the Secret Development Node docker container, the Ethereum Development Node systemd service, and the Relayer systemd service.
```bash
export PROJECT_ROOT="/root/nunya"
export PROJECT_ROOT="/root/nunya" # or ~/nunya
export USE_NETWORK="localhost" # alternatively "testnet" or "mainnet"
cd $PROJECT_ROOT
$PROJECT_ROOT/scripts/run.sh | tee $PROJECT_ROOT/run.log
Expand Down Expand Up @@ -433,3 +433,30 @@ Further changes:
* Edit smart contracts such as `NunyaBusiness.sol` in `packages/hardhat/contracts`
* Edit frontend homepage at `packages/nextjs/app/page.tsx`. For guidance on [routing](https://nextjs.org/docs/app/building-your-application/routing/defining-routes) and configuring [pages/layouts](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts) checkout the Next.js documentation.
* Edit deployment scripts in `packages/hardhat/deploy`

### WIP - Pop!

### Build and deploy contract

* Build
```bash
cd $PROJECT_ROOT/packages/pop/NunyaBusiness
pop build

* Deploy
```bash
pop up contract
```

### Archive - Create Template
```bash
pop new contract --contract-type examples --template cross-contract-calls NunyaBusiness

mkdir -p packages/pop
mv $PWD/NunyaBusiness $PWD/packages/pop
```

* Resources:
* https://learn.onpop.io
* https://github.com/use-ink/ink-examples
* https://polkadot.stackexchange.com/
4 changes: 2 additions & 2 deletions deployed.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"gatewayContractAddress": "secret1mfk7n6mc2cg6lznujmeckdh4x0a5ezf6hx6y8q",
"gatewayContractCodeHash": "be3db4b4c42d33300eee7801769a4176ed3046f23c08812fc2a85bc76075e1d5",
"gatewayContractAdminAddress": "secret1glfedwlusunwly7q05umghzwl6nf2vj6wr38fg",
"gatewayContractPublicKey": "0x047c4f7a52a10c051639ec0edd3e2d44fef02d993de6b8412273a78ca67f9c10c66069161d67278de0c74c501de435335163d6b7c5a22abae70e49d83a2b3debbd",
"gatewayContractEncryptionKeyForChaChaPoly1305": "A3xPelKhDAUWOewO3T4tRP7wLZk95rhBInOnjKZ/nBDG"
"gatewayContractPublicKey": "0x04b3078a5c4d56f7190b9cd03f0e359725588d2d2eb68e0db91998b76dd93f5e6fef2233f78020b2c8b464a1eeff1f565cc4983ff8f0b6e425ca793454b3aaba33",
"gatewayContractEncryptionKeyForChaChaPoly1305": "A7MHilxNVvcZC5zQPw41lyVYjS0uto4NuRmYt23ZP15v"
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion packages/hardhat/contracts/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -456,10 +456,13 @@ contract Gateway is Ownable, Utils, Base64 {
// persisting the task
tasks[_taskId] = Task(bytes31(_payloadHash), false);

string memory sourceNetwork = getChainId(chain_id_1, chain_id_2, chain_id_3, chain_id_length);
console.log("------ Gateway.send - sourceNetwork: ", sourceNetwork);

//emit the task to be picked up by the relayer
emit logNewTask(
_taskId,
getChainId(chain_id_1, chain_id_2, chain_id_3, chain_id_length),
sourceNetwork,
_userAddress,
_routingInfo,
_payloadHash,
Expand Down
102 changes: 53 additions & 49 deletions packages/hardhat/contracts/JSONParser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,69 +11,73 @@
pragma solidity ^0.8.26;

contract JSONParser {
// Custom error to save gas
error InvalidJSONFormat();
// Custom error for invalid data format
error InvalidDataFormat();

function extractKeyArray(bytes calldata data) public pure returns (uint8[] memory) {
// Skip the base64 decoding as the data is already decoded in this case
function extractKeyArray(bytes calldata data) public pure returns (uint256) {
// Skip the callback selector (4 bytes) and taskId (32 bytes)
// The actual JSON data starts after the ABI encoding overhead

// Find the "_key" property - we know it comes after "_request_id"
// Search for "[" after "_key":" pattern
// Find the position of "_key":[
bytes memory searchKey = '"_key":[';
uint256 startPos;
uint256 endPos;
bool found = false;

for (uint i = 0; i < data.length - 6; i++) {
// Look for "_key":" pattern
if (data[i] == '_' &&
data[i+1] == 'k' &&
data[i+2] == 'e' &&
data[i+3] == 'y' &&
data[i+4] == '"' &&
data[i+5] == ':') {

// Find the opening bracket
while (i < data.length && data[i] != '[') {
i++;
}
startPos = i + 1;

// Find the closing bracket
while (i < data.length && data[i] != ']') {
i++;
// Search for the key in chunks to save gas
for (uint i = 0; i < data.length - searchKey.length; i += 32) {
// Load 32 bytes at a time
bytes32 chunk;
assembly {
chunk := calldataload(add(data.offset, i))
}

// Check if our search key starts in this chunk
bool matchFound = true;
for (uint j = 0; j < searchKey.length && i + j < data.length; j++) {
if (uint8(chunk[j]) != uint8(searchKey[j])) {
matchFound = false;
break;
}
endPos = i;
}

if (matchFound) {
startPos = i + searchKey.length;
found = true;
break;
}
}

if (startPos == 0 || endPos == 0) revert InvalidJSONFormat();

// Count the numbers (commas + 1)
uint256 count = 1;
for (uint256 i = startPos; i < endPos; i++) {
if (data[i] == ',') count++;
}
if (!found) revert InvalidDataFormat();

// Create array to store results
uint8[] memory result = new uint8[](count);
uint256 resultIndex = 0;
uint256 currentNum = 0;
// Extract the array values
uint256 result;
uint256 currentNumber = 0;
uint256 arrayIndex = 0;

// Parse numbers
for (uint256 i = startPos; i < endPos; i++) {
bytes1 char = data[i];
// Process only until we hit the closing bracket or exceed 5 numbers
for (uint i = startPos; i < data.length && arrayIndex < 5; i++) {
uint8 char = uint8(data[i]);

if (char >= '0' && char <= '9') {
currentNum = currentNum * 10 + uint8(uint8(char) - 48);
}

if (char == ',' || i == endPos - 1) {
result[resultIndex] = uint8(currentNum);
currentNum = 0;
resultIndex++;
if (char >= 48 && char <= 57) { // If character is a digit
currentNumber = currentNumber * 10 + (char - 48);
} else if (char == 44 || char == 93) { // If comma or closing bracket
// Pack the number into the result
result = (result << 8) | uint8(currentNumber);
currentNumber = 0;
arrayIndex++;

if (char == 93) break; // Exit if closing bracket
}
}

return result;
}
}

function unpackArray(uint256 packed) public pure returns (uint8[5] memory) {
uint8[5] memory result;
for (uint i = 0; i < 5; i++) {
result[4-i] = uint8((packed >> (i * 8)) & 0xFF);
}
return result;
}
}
17 changes: 14 additions & 3 deletions packages/hardhat/contracts/NunyaBusiness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import "./Utils.sol";

import "./Ownable.sol";

import "@openzeppelin/contracts/utils/Strings.sol";

/**
* @notice Gateway Receiver
* @author
Expand Down Expand Up @@ -47,7 +49,7 @@ contract NunyaBusiness is Ownable, Utils {

IGateway secretContract;

uint256 public secretContractPubkey;
uint8[] public secretContractPubkey;

mapping (uint256 => FunctionCallType) expectedResult;

Expand Down Expand Up @@ -212,8 +214,17 @@ contract NunyaBusiness is Ownable, Utils {
// To prevent it from out of gas errors then try sending it as the first key and converting the value into a fixed-length hash using Keccak256
// so it is easy to find the start and end of the `result` by index.

// JSONParser parser = new JSONParser();
// secretContractPubkey = parser.extractKeyArray(data);

// Note: If I change `value: parseUnits("10000000", "ether").toString(),` to instead be
// `value: parseUnits("10000000", "ether").toString(),` in 01_deploy_your_contracts.ts and use the below
// to parse using JSONParser, it says it needs gas of 10000000010500000000000000 but the sender's balance is:
// only 10000000000000000000000. Definately can't parse JSON.
JSONParser parser = new JSONParser();
uint256 secretContractPubkeyPackedArray = parser.extractKeyArray(data);
string memory secretContractPubkeyStr = Strings.toString(secretContractPubkeyPackedArray);
uint8[5] memory secretContractPubkey = parser.unpackArray(secretContractPubkeyPackedArray);
console.log("------ NunyaBusiness - fulfilledSecretContractPubkeyCallback - secretContractPubkey: ", secretContractPubkeyStr);

// // https://github.com/NomicFoundation/hardhat/issues/2043
// for (uint i=0; i<secretContractPubkey.length; i++) {
// console.log("------ NunyaBusiness - fulfilledSecretContractPubkeyCallback - secretContractPubkey: ", i);
Expand Down
2 changes: 1 addition & 1 deletion packages/hardhat/deploy/01_deploy_your_contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const deployYourContract: DeployFunction = async function (hre: HardhatRuntimeEn
args: [],
log: true,
gasLimit: 3000000,
value: parseUnits("0.0005", "ether").toString(), // to fund the gateway in the constructor, use when setGatewayAddress is called
value: parseUnits("10000000", "ether").toString(), // to fund the gateway in the constructor, use when setGatewayAddress is called
// autoMine: can be passed to the deploy function to make the deployment process faster on local networks by
// automatically mining the contract deployment transaction. There is no effect on live networks.
autoMine: true,
Expand Down
9 changes: 9 additions & 0 deletions packages/pop/NunyaBusiness/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Ignore build artifacts from the local tests sub-crate.
/target/

# Ignore backup files creates by cargo fmt.
**/*.rs.bk

# Remove Cargo.lock when creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
32 changes: 32 additions & 0 deletions packages/pop/NunyaBusiness/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "NunyaBusiness"
version = "5.1.0"
authors = ["Use Ink <[email protected]>"]
edition = "2021"
publish = false

[dependencies]
ink = { version = "5.1.0", default-features = false }

# Note: We **need** to specify the `ink-as-dependency` feature.
#
# If we don't we will end up with linking errors!
other-contract = { path = "other-contract", default-features = false, features = ["ink-as-dependency"] }

[dev-dependencies]
ink_e2e = { version = "5.1.0" }

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",

# Note: The metadata generation step requires `std`. If we don't specify this the metadata
# generation for our contract will fail!
"other-contract/std",
]
ink-as-dependency = []
e2e-tests = []
Loading
Loading