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

Set up Axelar router #55

Merged
merged 7 commits into from
Mar 22, 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
33 changes: 33 additions & 0 deletions script/Connector-Axelar.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.18;

import {ConnectorAxelarRouter} from "src/routers/axelar/Router.sol";
import {CentrifugeConnector} from "src/Connector.sol";
import {ConnectorEscrow} from "src/Escrow.sol";
import {RestrictedTokenFactory, MemberlistFactory} from "src/token/factory.sol";
import "forge-std/Script.sol";

// Script to deploy Connectors with an Axelar router.
contract ConnectorAxelarScript is Script {
// address(0)[0:20] + heccak("Centrifuge")[21:32]
bytes32 SALT = 0x000000000000000000000000000000000000000075eb27011b69f002dc094d05;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we have a constant SALT? And what why the encoded meaning behind it is significant here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah there's no documentation on this right now: foundry-rs/book#782

The salt itself leads to deploying contracts to the same address on different chains.


function setUp() public {}

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

address escrow_ = address(new ConnectorEscrow{ salt: SALT }());
address tokenFactory_ = address(new RestrictedTokenFactory{ salt: SALT }());
address memberlistFactory_ = address(new MemberlistFactory{ salt: SALT }());
CentrifugeConnector connector =
new CentrifugeConnector{ salt: SALT }(escrow_, tokenFactory_, memberlistFactory_);

ConnectorAxelarRouter router = new ConnectorAxelarRouter{ salt: SALT }(
address(connector),
address(vm.envAddress("AXELAR_GATEWAY"))
);
connector.file("router", address(router));
vm.stopBroadcast();
}
}
101 changes: 101 additions & 0 deletions src/routers/axelar/Router.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.18;
pragma abicoder v2;

import {TypedMemView} from "memview-sol/TypedMemView.sol";
import {ConnectorMessages} from "../../Messages.sol";

interface ConnectorLike {
function addPool(uint64 poolId) external;
function addTranche(
uint64 poolId,
bytes16 trancheId,
string memory tokenName,
string memory tokenSymbol,
uint128 price
) external;
function updateMember(uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) external;
function updateTokenPrice(uint64 poolId, bytes16 trancheId, uint128 price) external;
function handleTransfer(uint64 poolId, bytes16 trancheId, address destinationAddress, uint128 amount) external;
}

interface AxelarExecutableLike {
function execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external;
}

interface AxelarGatewayLike {
function callContract(string calldata destinationChain, string calldata contractAddress, bytes calldata payload)
external;
}

contract ConnectorAxelarRouter is AxelarExecutableLike {
using TypedMemView for bytes;
// why bytes29? - https://github.com/summa-tx/memview-sol#why-bytes29
using TypedMemView for bytes29;
using ConnectorMessages for bytes29;

ConnectorLike public immutable connector;
AxelarGatewayLike public immutable axelarGateway;

string public constant axelarCentrifugeChainId = "Centrifuge";
string public constant axelarCentrifugeChainAddress = "";

constructor(address connector_, address axelarGateway_) {
connector = ConnectorLike(connector_);
axelarGateway = AxelarGatewayLike(axelarGateway_);
}

modifier onlyCentrifugeChainOrigin(string memory sourceChain) {
require(
msg.sender == address(axelarGateway)
&& keccak256(bytes(axelarCentrifugeChainId)) == keccak256(bytes(sourceChain)),
"ConnectorAxelarRouter/invalid-origin"
);
_;
}

modifier onlyConnector() {
require(msg.sender == address(connector), "ConnectorAxelarRouter/only-connector-allowed-to-call");
_;
}

// --- Incoming ---
function execute(bytes32, string calldata sourceChain, string calldata, bytes calldata payload)
external
onlyCentrifugeChainOrigin(sourceChain)
{
bytes29 _msg = payload.ref(0);

if (ConnectorMessages.isAddPool(_msg)) {
uint64 poolId = ConnectorMessages.parseAddPool(_msg);
connector.addPool(poolId);
} else if (ConnectorMessages.isAddTranche(_msg)) {
(uint64 poolId, bytes16 trancheId, string memory tokenName, string memory tokenSymbol, uint128 price) =
ConnectorMessages.parseAddTranche(_msg);
connector.addTranche(poolId, trancheId, tokenName, tokenSymbol, price);
} else if (ConnectorMessages.isUpdateMember(_msg)) {
(uint64 poolId, bytes16 trancheId, address user, uint64 validUntil) =
ConnectorMessages.parseUpdateMember(_msg);
connector.updateMember(poolId, trancheId, user, validUntil);
} else if (ConnectorMessages.isUpdateTokenPrice(_msg)) {
(uint64 poolId, bytes16 trancheId, uint128 price) = ConnectorMessages.parseUpdateTokenPrice(_msg);
connector.updateTokenPrice(poolId, trancheId, price);
} else if (ConnectorMessages.isTransfer(_msg)) {
(uint64 poolId, bytes16 trancheId,, address destinationAddress, uint128 amount) =
ConnectorMessages.parseTransfer20(_msg);
connector.handleTransfer(poolId, trancheId, destinationAddress, amount);
} else {
require(false, "invalid-message");
}
NunoAlexandre marked this conversation as resolved.
Show resolved Hide resolved
}

// --- Outgoing ---
function send(bytes memory message) public onlyConnector {
axelarGateway.callContract(axelarCentrifugeChainId, axelarCentrifugeChainAddress, message);
}
}
2 changes: 1 addition & 1 deletion src/routers/xcm/Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ contract ConnectorXCMRouter {
uint8 public immutable centrifugeChainConnectorsPalletIndex;
uint8 public immutable centrifugeChainConnectorsPalletHandleIndex;

/// --- Events ---
// --- Events ---
event Rely(address indexed user);
event Deny(address indexed user);
event File(bytes32 indexed what, XcmWeightInfo xcmWeightInfo);
Expand Down
2 changes: 1 addition & 1 deletion src/token/restricted.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ interface RestrictedTokenLike is ERC20Like {
contract RestrictedToken is ERC20 {
MemberlistLike public memberlist;

/// --- Events ---
// --- Events ---
event File(bytes32 indexed what, address data);

constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_, decimals_) {}
Expand Down