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(evm): Add darwinia adapter #17

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
32 changes: 32 additions & 0 deletions packages/evm/contracts/adapters/Darwinia/DarwiniaAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

import { IDarwiniaRouter, ILightClient } from "./interfaces/IDarwinia.sol";
import { BlockHashOracleAdapter } from "../BlockHashOracleAdapter.sol";

contract DarwiniaAdapter is BlockHashOracleAdapter {
error NoLightClientOnChain(uint256 chainId);
error BlockHeaderNotAvailable(uint256 blockNumber);

/// @dev The Darwinia Router contains a mapping of ChainIds to Light Clients.
address public immutable router;

constructor(address _router) {
router = _router;
}

/// @dev Stores the block header for a given block only if it is imported in the Darwinia Light Client
/// @param chainId Identifier for the chain to fetch header hash
/// @param blockNumber Block number for the block for which to store the header hash.
function storeBlockHeader(uint256 chainId, uint256 blockNumber) external {
ILightClient lightClient = IDarwiniaRouter(router).lightClientOf(chainId);
if (address(lightClient) == address(0)) {
revert NoLightClientOnChain(chainId);
}
bytes32 blockHeadHash = lightClient.headerOf(blockNumber);
if (blockHeadHash == bytes32(0)) {
revert BlockHeaderNotAvailable(blockNumber);
}
_storeHash(chainId, blockNumber, blockHeadHash);
}
}
16 changes: 16 additions & 0 deletions packages/evm/contracts/adapters/Darwinia/interfaces/IDarwinia.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

interface ILightClient {
/// @dev Fetch block hash of the block number
/// @param blockNumber Block number of the block hash to fetch
/// @return block header hash
function headerOf(uint256 blockNumber) external view returns (bytes32);
}

interface IDarwiniaRouter {
/// @dev Fetch Light Client contract addrees by chain id
/// @param chainId Chain Id of the light client contract address to fetch
/// @return Light Client contract address
function lightClientOf(uint256 chainId) external view returns(ILightClient);
}
26 changes: 26 additions & 0 deletions packages/evm/contracts/adapters/Darwinia/test/MockDarwinia.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;

import "../interfaces/IDarwinia.sol";

contract MockLightClient is ILightClient {
function headerOf(uint256 blockNumber) external view returns(bytes32) {
this;
if (blockNumber == 0) {
return 0x0000000000000000000000000000000000000000000000000000000000000000;
} else {
return 0x0000000000000000000000000000000000000000000000000000000000000001;
}
}
}

contract MockDarwiniaRouter is IDarwiniaRouter {
ILightClient lc;
constructor() {
lc = new MockLightClient();
}

function lightClientOf(uint256) external view returns(ILightClient) {
return ILightClient(lc);
}
}
47 changes: 47 additions & 0 deletions packages/evm/test/adapters/Darwinia/01_DarwiniaAdapter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { expect } from "chai"
import { ethers, network } from "hardhat"

const DOMAIN_ID = "0x0000000000000000000000000000000000000000000000000000000000000001"
const ID_ZERO = 0
const ID_ONE = 1
const HASH_ONE = "0x0000000000000000000000000000000000000000000000000000000000000001"
const HASH_ZERO = "0x0000000000000000000000000000000000000000000000000000000000000000"

const setup = async () => {
await network.provider.request({ method: "hardhat_reset", params: [] })
const [wallet] = await ethers.getSigners()
const MockDarwiniaRouter = await ethers.getContractFactory("MockDarwiniaRouter")
const router = await MockDarwiniaRouter.deploy()
const DarwiniaAdapter = await ethers.getContractFactory("DarwiniaAdapter")
const adapter = await DarwiniaAdapter.deploy(router.address)
return {
wallet,
router,
adapter,
}
}

describe("DarwiniaAdapter", function () {
describe("Constructor", function () {
it("Successfully deploys contract with correct state", async function () {
const { wallet, router, adapter } = await setup()
expect(await adapter.deployed())
expect(await adapter.router()).to.equal(router.address)
})
})

describe("StoreBlockHeader()", function () {
it("StoreBlockHeader", async function () {
const { adapter } = await setup()
await adapter.storeBlockHeader(DOMAIN_ID, ID_ONE)
expect(await adapter.getHashFromOracle(DOMAIN_ID, ID_ONE)).to.equal(HASH_ONE)
})
})

describe("GetHashFromOracle()", function () {
it("Returns 0 if no header is stored", async function () {
const { adapter } = await setup()
expect(await adapter.getHashFromOracle(DOMAIN_ID, ID_ZERO)).to.equal(HASH_ZERO)
})
})
})