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/axelar proxy #118

Merged
merged 15 commits into from
Jun 5, 2023
Merged
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: 29 additions & 0 deletions script/test/Arbitrum/DeployProxy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import { AxelarProxy } from "src/AxelarProxy.sol";

import "forge-std/Script.sol";
import { Math } from "src/utils/Math.sol";

/**
* @dev Run
* `source .env && forge script script/test/Arbitrum/DeployProxy.s.sol:DeployProxyScript --rpc-url $ARBITRUM_RPC_URL --private-key $PRIVATE_KEY —optimize —optimizer-runs 200 --verify --etherscan-api-key $ARBISCAN_KEY --slow --broadcast`
* @dev Optionally can change `--with-gas-price` to something more reasonable
*/
contract DeployProxyScript is Script {
address private devOwner = 0x552acA1343A6383aF32ce1B7c7B1b47959F7ad90;

address private gateway = 0xe432150cce91c13a887f7D836923d5597adD8E31;

string private sourceChain = "Polygon";
string private sourceAddress = "0x552acA1343A6383aF32ce1B7c7B1b47959F7ad90";

function run() external {
vm.startBroadcast();

AxelarProxy proxy = new AxelarProxy(gateway);

vm.stopBroadcast();
}
}
41 changes: 41 additions & 0 deletions script/test/Polygon/SendMessageToArbitrum.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import { ERC20 } from "src/base/Cellar.sol";
import { AxelarProxy } from "src/AxelarProxy.sol";
import { MockSommelier } from "src/mocks/MockSommelier.sol";

import "forge-std/Script.sol";
import { Math } from "src/utils/Math.sol";

interface Gateway {
function callContract(string memory dest, string memory destAddress, bytes memory payload) external;
}

/**
* @dev Run
* `source .env && forge script script/test/Polygon/SendMessageToArbitrum.s.sol:SendMessageToArbitrumScript --rpc-url $MATIC_RPC_URL --private-key $PRIVATE_KEY —optimize —optimizer-runs 200 --verify --etherscan-api-key $POLYGONSCAN_KEY --slow --broadcast`
* @dev Optionally can change `--with-gas-price` to something more reasonable
*/
contract SendMessageToArbitrumScript is Script {
address private devOwner = 0x552acA1343A6383aF32ce1B7c7B1b47959F7ad90;

Gateway private gateway = Gateway(0x6f015F16De9fC8791b234eF68D486d2bF203FBA8);

string private destChain = "arbitrum";
string private destAddress = "0x2aF45D06C3d06af1E6B8Bc3f90c5a8DB0E5aa729";

address private usdcOnArb = 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8;

MockSommelier private mockSomm;

function run() external {
vm.startBroadcast();

mockSomm = new MockSommelier();

mockSomm.sendMessage{ value: 10 ether }(destAddress, usdcOnArb, devOwner, 777);
0xEinCodes marked this conversation as resolved.
Show resolved Hide resolved

vm.stopBroadcast();
}
}
55 changes: 55 additions & 0 deletions src/AxelarProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import { AxelarExecutable } from "lib/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";

crispymangoes marked this conversation as resolved.
Show resolved Hide resolved
/**
* @title Axelar Proxy
* @notice Allows for Cellars deployed on L2s to be controlled by the Sommelier Chain using Axelar messages.
* @dev This contract will be deployed on some L2, then to run a Cellar on that L2,
* deploy the Cellar, and make this contract the owner.
* @author crispymangoes
*/
contract AxelarProxy is AxelarExecutable {
0xEinCodes marked this conversation as resolved.
Show resolved Hide resolved
using Address for address;

event LogicCallEvent(address target, bytes callData);

error AxelarProxy__WrongSource();
error AxelarProxy__NoTokens();

bytes32 public constant SOMMELIER_CHAIN_HASH = keccak256(bytes("sommelier"));

constructor(address gateway_) AxelarExecutable(gateway_) {}

/**
* @notice Execution logic.
* @dev Verifies message is from Sommelier, otherwise reverts.
0xEinCodes marked this conversation as resolved.
Show resolved Hide resolved
* @dev Verifies message is a valid Axelar message, otherwise reverts.
* See `AxelarExecutable.sol`.
*/
function _execute(string calldata sourceChain, string calldata, bytes calldata payload) internal override {
crispymangoes marked this conversation as resolved.
Show resolved Hide resolved
// Validate Source Chain
if (keccak256(bytes(sourceChain)) != SOMMELIER_CHAIN_HASH) revert AxelarProxy__WrongSource();

// Execute function call.
(address target, bytes memory callData) = abi.decode(payload, (address, bytes));
0xEinCodes marked this conversation as resolved.
Show resolved Hide resolved
target.functionCall(callData);

emit LogicCallEvent(target, callData);
}

/**
* @notice This contract is not setup to handle ERC20 tokens, so execution with token calls will revert.
*/
function _executeWithToken(
string calldata,
string calldata,
bytes calldata,
string calldata,
uint256
) internal pure override {
revert AxelarProxy__NoTokens();
}
}
38 changes: 38 additions & 0 deletions src/mocks/MockSommelier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { ERC20 } from "src/base/Cellar.sol";
import { IAxelarGateway } from "lib/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol";
import { IAxelarGasService } from "lib/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol";

/**
* @notice This mock contract provides a method to send an Axelar message from one chain to another.
* It is called MockSommelier because it is mimicking what the Sommelier chain would do
* to send an Axelar message.
* @dev NOTE for actual Axelar messages from Sommelier, the Cosmos to EVM messaging logic will be used, not EVM to EVM.
*/
contract MockSommelier {
0xEinCodes marked this conversation as resolved.
Show resolved Hide resolved
using Address for address;

address constant ARB_USDC = 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8;
IAxelarGateway private axelarGateway = IAxelarGateway(0x6f015F16De9fC8791b234eF68D486d2bF203FBA8);
IAxelarGasService private axelarGasService = IAxelarGasService(0x2d5d7d31F671F86C782533cc367F14109a082712);
string private destChain = "arbitrum";

function sendMessage(string memory target, address token, address spender, uint256 amount) external payable {
bytes memory payload = abi.encodeWithSelector(ERC20.approve.selector, spender, amount);
payload = abi.encode(token, payload);

// Pay gas.
axelarGasService.payNativeGasForContractCall{ value: msg.value }(
msg.sender,
destChain,
target,
payload,
msg.sender
);
// Send GMP.
axelarGateway.callContract(destChain, target, payload);
}
}