generated from PaulRBerg/hardhat-template
-
Notifications
You must be signed in to change notification settings - Fork 52
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
added Router Protocol adapter to the Hashi's pool of adapters #49
Merged
Merged
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
pragma solidity ^0.8.20; | ||
|
||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import { IDapp } from "@routerprotocol/evm-gateway-contracts/contracts/IDapp.sol"; | ||
import { IGateway } from "@routerprotocol/evm-gateway-contracts/contracts/IGateway.sol"; | ||
import { BlockHashAdapter } from "../BlockHashAdapter.sol"; | ||
|
||
contract RouterAdapter is BlockHashAdapter, Ownable, IDapp { | ||
string public constant PROVIDER = "router"; | ||
|
||
IGateway public immutable ROUTER_GATEWAY; | ||
|
||
mapping(bytes32 => bytes32) public enabledReporters; | ||
mapping(bytes32 => uint256) public chainIds; | ||
|
||
error UnauthorizedRouterReceive(); | ||
error RouterIAckNotSupported(); | ||
|
||
event ReporterSet(uint256 indexed chainId, string name, string indexed reporter); | ||
|
||
constructor(address routerGateway) { | ||
ROUTER_GATEWAY = IGateway(routerGateway); | ||
} | ||
|
||
function setReporterByChain( | ||
uint256 chainId, | ||
string calldata chainIdStr, | ||
string calldata reporter | ||
) external onlyOwner { | ||
bytes32 chainIdHash = keccak256(bytes(chainIdStr)); | ||
enabledReporters[chainIdHash] = keccak256(bytes(reporter)); | ||
chainIds[chainIdHash] = chainId; | ||
emit ReporterSet(chainId, chainIdStr, reporter); | ||
} | ||
|
||
function iReceive( | ||
string calldata requestSender, | ||
bytes calldata packet, | ||
string calldata srcChainId | ||
) external override returns (bytes memory) { | ||
bytes32 chainIdHash = keccak256(bytes(srcChainId)); | ||
uint256 sourceChainId = chainIds[chainIdHash]; | ||
|
||
if ( | ||
msg.sender != address(ROUTER_GATEWAY) || | ||
enabledReporters[chainIdHash] != keccak256(bytes(requestSender)) || | ||
sourceChainId == 0 | ||
) revert UnauthorizedRouterReceive(); | ||
|
||
(uint256[] memory ids, bytes32[] memory hashes) = abi.decode(packet, (uint256[], bytes32[])); | ||
_storeHashes(sourceChainId, ids, hashes); | ||
|
||
return hex""; | ||
} | ||
|
||
function iAck(uint256, bool, bytes memory) external override { | ||
revert RouterIAckNotSupported(); | ||
} | ||
} |
119 changes: 119 additions & 0 deletions
119
packages/evm/contracts/adapters/Router/RouterReporter.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
pragma solidity ^0.8.20; | ||
|
||
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; | ||
import { Reporter } from "../Reporter.sol"; | ||
import { IGateway } from "@routerprotocol/evm-gateway-contracts/contracts/IGateway.sol"; | ||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; | ||
|
||
interface IRouterGateway is IGateway { | ||
function iSendDefaultFee() external view returns (uint256); | ||
|
||
function currentVersion() external view returns (uint256); | ||
} | ||
|
||
interface IRouterGasStation { | ||
function payFee(string memory destChainId, uint256 destGasLimit) external payable returns (uint256); | ||
function getNativeFees( | ||
string memory destChainId, | ||
uint256 destGasLimit | ||
) external view returns (uint256) ; | ||
} | ||
|
||
contract RouterReporter is Reporter, Ownable { | ||
using Strings for uint256; | ||
|
||
string public constant PROVIDER = "router"; | ||
bytes32 private constant NULL_STRING = keccak256(""); | ||
IRouterGateway public immutable ROUTER_GATEWAY; | ||
IRouterGasStation public immutable ROUTER_GAS_STATION; | ||
uint256 public immutable CURRENT_GATEWAY_VERSION; | ||
string public feePayer; | ||
|
||
mapping(uint256 => string) public chainIds; | ||
|
||
error ChainIdNotSupported(uint256 chainId); | ||
error InsufficientFeePassed(); | ||
|
||
event ChainIdSet(uint256 indexed chainId, string indexed chainIdString); | ||
event FeePayerSet(string oldFeePayer, string feePayer); | ||
|
||
constructor( | ||
address headerStorage, | ||
address yaho, | ||
address routerGateway, | ||
address routerGasStation, | ||
string memory routerFeePayer | ||
) Reporter(headerStorage, yaho) { | ||
ROUTER_GATEWAY = IRouterGateway(routerGateway); | ||
ROUTER_GAS_STATION = IRouterGasStation(routerGasStation); | ||
|
||
feePayer = routerFeePayer; | ||
|
||
CURRENT_GATEWAY_VERSION = ROUTER_GATEWAY.currentVersion(); | ||
ROUTER_GATEWAY.setDappMetadata(routerFeePayer); | ||
} | ||
|
||
function setRouterFeePayer(string memory routerFeePayer) external onlyOwner { | ||
string memory oldFeePayer = feePayer; | ||
feePayer = routerFeePayer; | ||
ROUTER_GATEWAY.setDappMetadata(routerFeePayer); | ||
|
||
emit FeePayerSet(oldFeePayer, routerFeePayer); | ||
} | ||
|
||
function setChainIdStringByChainId(uint256 chainId, string calldata chainIdString) external onlyOwner { | ||
chainIds[chainId] = chainIdString; | ||
emit ChainIdSet(chainId, chainIdString); | ||
} | ||
|
||
function getRequestMetadata() internal pure returns (bytes memory) { | ||
bytes memory requestMetadata = abi.encodePacked( | ||
uint64(200_000), | ||
uint64(0), | ||
uint64(0), | ||
uint64(0), | ||
uint128(0), | ||
uint8(0), | ||
false, | ||
string("") | ||
); | ||
return requestMetadata; | ||
} | ||
|
||
function _dispatch( | ||
uint256 targetChainId, | ||
address adapter, | ||
uint256[] memory ids, | ||
bytes32[] memory hashes | ||
) internal override returns (bytes32) { | ||
string memory targetChainIdStr = chainIds[targetChainId]; | ||
if (keccak256(abi.encode(targetChainIdStr)) == NULL_STRING) revert ChainIdNotSupported(targetChainId); | ||
|
||
bytes memory payload = abi.encode(ids, hashes); | ||
string memory stringAdapter = uint256(uint160(adapter)).toHexString(20); | ||
bytes memory requestPacket = abi.encode(stringAdapter, payload); | ||
bytes memory requestMetadata = getRequestMetadata(); | ||
|
||
uint256 iSendFee = ROUTER_GATEWAY.iSendDefaultFee(); | ||
uint256 crosstalkFee = ROUTER_GAS_STATION.getNativeFees(targetChainIdStr, 200_000); | ||
|
||
if (address(this).balance < (iSendFee + crosstalkFee)) revert InsufficientFeePassed(); | ||
|
||
ROUTER_GAS_STATION.payFee{ value: crosstalkFee }(targetChainIdStr, 200_000); | ||
|
||
ROUTER_GATEWAY.iSend{ value: iSendFee }( | ||
CURRENT_GATEWAY_VERSION, | ||
0, | ||
string(""), | ||
targetChainIdStr, | ||
requestMetadata, | ||
requestPacket | ||
); | ||
|
||
return bytes32(0); | ||
} | ||
|
||
receive() external payable {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -99,6 +99,7 @@ | |
"@hyperlane-xyz/core": "^3.1.10", | ||
"@openzeppelin/contracts-upgradeable": "^4.8.1", | ||
"@polytope-labs/solidity-merkle-trees": "^0.2.1", | ||
"@routerprotocol/evm-gateway-contracts": "^1.1.13", | ||
"hardhat-change-network": "^0.0.7", | ||
"hardhat-deploy": "^0.11.31", | ||
"openzeppelin": "npm:@openzeppelin/[email protected]", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,3 +14,4 @@ import "./sygma" | |
import "./telepathy" | ||
import "./wormhole" | ||
import "./zetachain" | ||
import "./router" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" | ||
import { task, types } from "hardhat/config" | ||
import type { TaskArguments } from "hardhat/types" | ||
import type { RouterAdapter } from "../../../types/contracts/adapters/Router/RouterAdapter.sol/RouterAdapter" | ||
import type { RouterAdapter__factory } from "../../../types/factories/contracts/adapters/Router/RouterAdapter.sol/RouterAdapter__factory" | ||
import type { RouterReporter } from "../../../types/contracts/adapters/Router/RouterReporter.sol/RouterReporter" | ||
import type { RouterReporter__factory } from "../../../types/factories/contracts/adapters/Router/RouterReporter.sol/RouterReporter__factory" | ||
import { verify } from "../index" | ||
|
||
task("deploy:adapter:RouterAdapter") | ||
.addParam("routerGateway", "address of the Router gateway contract") | ||
.addFlag("verify", "whether to verify the contract on Etherscan") | ||
.setAction(async function (taskArguments: TaskArguments, hre) { | ||
console.log("Deploying RouterAdapter...") | ||
const signers: SignerWithAddress[] = await hre.ethers.getSigners() | ||
const routerAdapterFactory: RouterAdapter__factory = <RouterAdapter__factory>( | ||
await hre.ethers.getContractFactory("RouterAdapter") | ||
) | ||
const constructorArguments = [ | ||
taskArguments.routerGateway, | ||
] as const | ||
const routerAdapter: RouterAdapter = <RouterAdapter>( | ||
await routerAdapterFactory.connect(signers[0]).deploy(...constructorArguments) | ||
) | ||
await routerAdapter.deployed() | ||
console.log("RouterAdapter deployed to:", routerAdapter.address) | ||
if (taskArguments.verify) await verify(hre, routerAdapter, constructorArguments) | ||
}) | ||
|
||
task("deploy:adapter:RouterReporter") | ||
.addParam("headerStorage", "address of the header storage contract") | ||
.addParam("yaho", "address of the Yaho contract", undefined, types.string) | ||
.addParam("routerGateway", "address of the Router gateway contract") | ||
.addParam("routerGasStation", "address of the Router gas station contract") | ||
.addParam( | ||
"routerFeePayer", | ||
"address of the fee payer for this contract (https://docs.routerprotocol.com/develop/message-transfer-via-crosstalk/evm-guides/iDapp-functions/setDappMetadata)", | ||
) | ||
.addFlag("verify", "whether to verify the contract on Etherscan") | ||
.setAction(async function (taskArguments: TaskArguments, hre) { | ||
console.log("Deploying RouterReporter...") | ||
const signers: SignerWithAddress[] = await hre.ethers.getSigners() | ||
const routerReporterFactory: RouterReporter__factory = <RouterReporter__factory>( | ||
await hre.ethers.getContractFactory("RouterReporter") | ||
) | ||
const constructorArguments = [ | ||
taskArguments.headerStorage, | ||
taskArguments.yaho, | ||
taskArguments.routerGateway, | ||
taskArguments.routerGasStation, | ||
taskArguments.routerFeePayer, | ||
] as const | ||
const routerReporter: RouterReporter = <RouterReporter>( | ||
await routerReporterFactory.connect(signers[0]).deploy(...constructorArguments) | ||
) | ||
await routerReporter.deployed() | ||
console.log("RouterReporter deployed to:", routerReporter.address) | ||
if (taskArguments.verify) await verify(hre, routerReporter, constructorArguments) | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fx can be restricted to
pure