Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/check trusted hash #20

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
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
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
ETH_PRIVATE_KEY=0x
ETH_PUBLIC_KEY=0x
ETHERSCAN_API_KEY=

SUCCINCT_API_KEY=

# Aurora Eth RPC
#ETH_RPC=https://testnet.aurora.dev
#SKIP_BROADCAST=y
#SKIP_VERIFY=true
#IS_LEGACY=true

2 changes: 1 addition & 1 deletion .github/workflows/on_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,5 @@ jobs:
echo "## Build result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
- name: "Run tests"
run: forge test -vv
run: forge test --gas-report -vv

27 changes: 2 additions & 25 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,5 @@ test:
beefy-test:
RUST_LOG=debug cargo test --workspace --ignored --release

# TODO: these should be configurable and need updating
SYNC_FUNCTION_ID=0x38a03ba7ecace39a1c7315d798cc9689418eceba384e154c01d6e2897bf000a9
VERIFY_FUNCTION_ID=0x76918ea14fc7b8d8e4919c970be635e1d0ed57576771cdc1f6fa581bce7fd418
GATEWAY_ID=0x6c7a05e0ae641c6559fd76ac56641778b6ecd776
NEAR_CHECKPOINT_HEADER_HASH=0x63b87190ffbaa36d7dab50f918fe36f70ab26910a0e9d797161e2356561598e3
ETH_RPC=https://rpc.goerli.eth.gateway.fm
CHAIN_ID=5

FORGE=cd ./nearx/contract && forge
FORGEREST= --rpc-url $(ETH_RPC) --private-key $$ETH_PRIVATE_KEY --broadcast --verify --verifier etherscan -vv

build-contracts:
$(FORGE) build

deploy: build-contracts
$(FORGE) script Deploy $(FORGEREST)

initialise:
$(FORGE) script Initialise $(FORGEREST)

upgrade:
$(FORGE) script Upgrade $(FORGEREST)

verify:
$(FORGE) script Verify $(FORGEREST)
slither:
cd nearx/contracts && slither . --foundry-compile-all
11 changes: 11 additions & 0 deletions api/NEAR Light Client/Succinct/Get Deployments.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
meta {
name: Get Deployments
type: http
seq: 5
}

get {
url: {{succintBaseUrl}}/deployments/near/near-light-client
body: none
auth: none
}
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

nodejs
solc
slither-analyzer

];
buildInputs = with pkgs; [
Expand Down
20 changes: 15 additions & 5 deletions nearx/contract/foundry.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
[profile.default]
fs_permissions = [ { access = "read", path = "./broadcast" } ]
libs = [ "lib" ]
optimizer = false # This was breaking verification for some reason
optimizer-runs = 100_000
out = "out"
gas_reports = [ "*" ]
libs = [ "lib" ]
optimizer = true # This was breaking verification for some reason
optimizer-runs = 1000 # TODO: change when we properly release this
out = "out"
solc_version = "0.8.19"
src = "src"

remappings = [
"forge-std=lib/forge-std/src",
"@openzeppelin/contracts=lib/openzeppelin-contracts/contracts",
"@openzeppelin/contracts-upgradeable=lib/openzeppelin-contracts-upgradeable/contracts",
"@openzeppelin/[email protected]=lib/openzeppelin-contracts/contracts",
"@openzeppelin/[email protected]=lib/openzeppelin-contracts-upgradeable/contracts",
]
src = "src"

[profile.optimizer-details]
constant_optimizer = true
cse = true
deduplicate = true
2 changes: 1 addition & 1 deletion nearx/contract/lib/openzeppelin-contracts
2 changes: 1 addition & 1 deletion nearx/contract/script/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
pragma solidity ^0.8.19;

import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {NearX} from "../src/NearX.sol";
Expand Down
22 changes: 22 additions & 0 deletions nearx/contract/script/RequestSync.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Script} from "forge-std/Script.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {DevOpsTools} from "lib/foundry-devops/src/DevOpsTools.sol";
import {NearX, decodePackedIds, TransactionOrReceiptId} from "../src/NearX.sol";

// TODO: refactor for 128, taking the input fixture
contract RequestSync is Script {
function run() external {
address mostRecentlyDeployedProxy = DevOpsTools
.get_most_recent_deployment("ERC1967Proxy", block.chainid);

vm.startBroadcast();

NearX proxy = NearX(payable(mostRecentlyDeployedProxy));
proxy.requestSync();

vm.stopBroadcast();
}
}
26 changes: 26 additions & 0 deletions nearx/contract/script/RequestVerify.s.sol

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions nearx/contract/script/UpdateParams.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {NearX} from "../src/NearX.sol";
import {Script} from "forge-std/Script.sol";
import {DevOpsTools} from "lib/foundry-devops/src/DevOpsTools.sol";

// TODO: scripts need to support multiple envs
contract UpdateParams is Script {
function setUp() public {}

function run() external {
address proxyAddress = DevOpsTools.get_most_recent_deployment(
"ERC1967Proxy",
block.chainid
);
vm.startBroadcast();
NearX lightClient = NearX(payable(proxyAddress));

// Succinct's goerli gateway
address initialGateway = vm.envAddress("GATEWAY_ID");
lightClient.updateGateway(initialGateway);

bytes32 syncFunctionId = vm.envBytes32("SYNC_FUNCTION_ID");
lightClient.updateSyncId(syncFunctionId);

bytes32 verifyFunctionId = vm.envBytes32("VERIFY_FUNCTION_ID");
lightClient.updateVerifyId(verifyFunctionId);

vm.stopBroadcast();
}
}
15 changes: 2 additions & 13 deletions nearx/contract/script/Upgrade.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,11 @@ contract Upgrade is Script {
function run() external returns (address) {
address mostRecentlyDeployedProxy = DevOpsTools
.get_most_recent_deployment("ERC1967Proxy", block.chainid);
vm.startBroadcast();

NearX newAddress = new NearX();

vm.stopBroadcast();
address proxy = upgrade(mostRecentlyDeployedProxy, address(newAddress));
return proxy;
}

function upgrade(address proxyAddress, address newAddress)
public
returns (address)
{
vm.startBroadcast();
NearX newAddress = new NearX();

NearX proxy = NearX(payable(proxyAddress));
NearX proxy = NearX(payable(mostRecentlyDeployedProxy));
proxy.upgradeToAndCall(address(newAddress), "");

vm.stopBroadcast();
Expand Down
40 changes: 0 additions & 40 deletions nearx/contract/script/Verify.s.sol

This file was deleted.

3 changes: 3 additions & 0 deletions nearx/contract/slither.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"filter_paths": "lib"
}
63 changes: 49 additions & 14 deletions nearx/contract/src/NearX.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
pragma solidity <0.8.20;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable@4.9.5/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable@4.9.5/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable@4.9.5/proxy/utils/UUPSUpgradeable.sol";
import {ISuccinctGateway} from "./interfaces/ISuccinctGateway.sol";
import {INearX, TransactionOrReceiptId, ProofVerificationResult, encodePackedIds, decodePackedIds, decodePackedResults} from "./interfaces/INearX.sol";
import {DoubleEndedQueue} from "@openzeppelin/[email protected]/utils/structs/DoubleEndedQueue.sol";

/// @notice The NearX contract is a light client for Near.
contract NearX is INearX, Initializable, OwnableUpgradeable, UUPSUpgradeable {
using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
constructor() payable {
_disableInitializers();
}

function initialize() public initializer {
__Ownable_init(msg.sender);
__Ownable_init();
__UUPSUpgradeable_init();
}

Expand All @@ -39,6 +42,8 @@ contract NearX is INearX, Initializable, OwnableUpgradeable, UUPSUpgradeable {
/// @notice The latest header that has been committed.
bytes32 public latestHeader;

DoubleEndedQueue.Bytes32Deque public lastKnownHeaders;

function updateGateway(address _gateway) external onlyOwner {
gateway = _gateway;
}
Expand Down Expand Up @@ -84,20 +89,27 @@ contract NearX is INearX, Initializable, OwnableUpgradeable, UUPSUpgradeable {
emit SyncRequested(latestHeader);
}

function handleSync(bytes memory _output, bytes memory _context) external {
function handleSync(bytes calldata _output, bytes calldata) external {
if (msg.sender != gateway || !ISuccinctGateway(gateway).isCallback()) {
revert NotFromSuccinctGateway(msg.sender);
}
// TODO: this does mean we trust the gateway, potentially we add a check here

bytes32 targetHeader = abi.decode(_output, (bytes32));

latestHeader = targetHeader;

// TODO: check if we can pop back
uint256 length = DoubleEndedQueue.length(lastKnownHeaders);
if (length > 0 && length < 64) {
DoubleEndedQueue.popBack(lastKnownHeaders);
}

DoubleEndedQueue.pushFront(lastKnownHeaders, targetHeader);

emit HeadUpdate(targetHeader);
}

function requestVerify(TransactionOrReceiptId[] memory ids)
function requestVerify(TransactionOrReceiptId[] calldata ids)
external
payable
{
Expand All @@ -119,13 +131,36 @@ contract NearX is INearX, Initializable, OwnableUpgradeable, UUPSUpgradeable {
emit VerifyRequested(latestHeader, ids);
}

function handleVerify(bytes calldata _output, bytes memory _context)
external
{
function handleVerify(bytes calldata _output, bytes calldata) external {
if (msg.sender != gateway || !ISuccinctGateway(gateway).isCallback()) {
revert NotFromSuccinctGateway(msg.sender);
}
ProofVerificationResult[] memory results = decodePackedResults(_output);
emit VerifyResult(results);

bytes32 trustedHeader = abi.decode(_output[:32], (bytes32));
bytes memory results = _output[32:];

uint256 length = DoubleEndedQueue.length(lastKnownHeaders);
require(length < 255);
bytes32 header;
uint8 i = 0;
for (i; i < length; i++) {
header = DoubleEndedQueue.at(lastKnownHeaders, i);
if (header == trustedHeader) {
break;
}
if (i == length - 1) {
revert("Trusted header not found");
}
}

emit VerifyResult(trustedHeader, results);
}

function decodeResults(bytes calldata _output)
external
pure
returns (ProofVerificationResult[] memory)
{
return decodePackedResults(_output);
}
}
4 changes: 2 additions & 2 deletions nearx/contract/src/interfaces/INearX.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
pragma solidity >=0.8.0;

import "./Bytes.sol";

Expand Down Expand Up @@ -33,7 +33,7 @@ interface INearX {
error FunctionIdsNotInitialised();

/// @notice The result of the verification request
event VerifyResult(ProofVerificationResult[] results);
event VerifyResult(bytes32 trustedHeader, bytes results);
}

uint256 constant MAX_LEN = 64;
Expand Down
Loading
Loading