Skip to content

Commit

Permalink
Merge branch 'main' into alistair/add-max-destination-fee
Browse files Browse the repository at this point in the history
  • Loading branch information
vgeddes committed Apr 14, 2024
2 parents 5aaef50 + e266aab commit f574f36
Show file tree
Hide file tree
Showing 54 changed files with 2,800 additions and 468 deletions.
14 changes: 14 additions & 0 deletions contracts/src/Assets.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ library Assets {
ParaID destinationChain,
MultiAddress calldata destinationAddress,
uint128 destinationChainFee,
uint128 maxDestinationChainFee,
uint128 amount
) external returns (Ticket memory ticket) {
AssetsStorage.Layout storage $ = AssetsStorage.layout();
Expand All @@ -88,6 +89,19 @@ library Assets {
revert TokenNotRegistered();
}

// Reduce the ability for users to perform arbitrage by exploiting a
// favourable exchange rate. For example supplying Ether
// and gaining a more valuable amount of DOT on the destination chain.
//
// For safety, `maxDestinationChainFee` should be less valuable
// than the gas cost to send tokens.
//
// Also prevents users from mistakenly sending more fees than would be required
// which has negative effects like draining AssetHub's sovereign account.
if (destinationChainFee > maxDestinationChainFee) {
revert InvalidDestinationFee();
}

// Lock the funds into AssetHub's agent contract
_transferToAgent($.assetHubAgent, token, sender, amount);

Expand Down
9 changes: 9 additions & 0 deletions contracts/src/BeefyClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ contract BeefyClient {
*/
event NewMMRRoot(bytes32 mmrRoot, uint64 blockNumber);

/**
* @dev Emitted when a new ticket has been created
* @param relayer The relayer who created the ticket
* @param blockNumber the parent block number of the candidate MMR root
*/
event NewTicket(address relayer, uint64 blockNumber);

/* Types */

/**
Expand Down Expand Up @@ -289,6 +296,8 @@ contract BeefyClient {
prevRandao: 0,
bitfieldHash: keccak256(abi.encodePacked(bitfield))
});

emit NewTicket(msg.sender, commitment.blockNumber);
}

/**
Expand Down
1 change: 1 addition & 0 deletions contracts/src/DeployGatewayLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ contract DeployGatewayLogic is Script {
uint128 destinationMaxTransferFee = uint128(vm.envUint("RESERVE_TRANSFER_MAX_DESTINATION_FEE"));

AgentExecutor executor = new AgentExecutor();

new Gateway(
address(beefyClient),
address(executor),
Expand Down
3 changes: 0 additions & 3 deletions contracts/src/DeployScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {BeefyClient} from "./BeefyClient.sol";
import {IGateway} from "./interfaces/IGateway.sol";
import {GatewayProxy} from "./GatewayProxy.sol";
import {Gateway} from "./Gateway.sol";
import {GatewayUpgradeMock} from "../test/mocks/GatewayUpgradeMock.sol";
import {Agent} from "./Agent.sol";
import {AgentExecutor} from "./AgentExecutor.sol";
import {ChannelID, ParaID, OperatingMode} from "./Types.sol";
Expand Down Expand Up @@ -105,8 +104,6 @@ contract DeployScript is Script {
payable(bridgeHubAgent).safeNativeTransfer(initialDeposit);
payable(assetHubAgent).safeNativeTransfer(initialDeposit);

new GatewayUpgradeMock();

vm.stopBroadcast();
}
}
1 change: 0 additions & 1 deletion contracts/src/FundAgent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {BeefyClient} from "./BeefyClient.sol";
import {IGateway} from "./interfaces/IGateway.sol";
import {GatewayProxy} from "./GatewayProxy.sol";
import {Gateway} from "./Gateway.sol";
import {GatewayUpgradeMock} from "../test/mocks/GatewayUpgradeMock.sol";
import {Agent} from "./Agent.sol";
import {AgentExecutor} from "./AgentExecutor.sol";
import {ParaID} from "./Types.sol";
Expand Down
54 changes: 14 additions & 40 deletions contracts/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import {
Ticket,
Costs
} from "./Types.sol";
import {Upgrade} from "./Upgrade.sol";
import {IGateway} from "./interfaces/IGateway.sol";
import {IInitializable} from "./interfaces/IInitializable.sol";
import {IUpgradable} from "./interfaces/IUpgradable.sol";
import {ERC1967} from "./utils/ERC1967.sol";
import {Address} from "./utils/Address.sol";
import {SafeNativeTransfer} from "./utils/SafeTransfer.sol";
Expand All @@ -46,7 +48,7 @@ import {AssetsStorage} from "./storage/AssetsStorage.sol";

import {UD60x18, ud60x18, convert} from "prb/math/src/UD60x18.sol";

contract Gateway is IGateway, IInitializable {
contract Gateway is IGateway, IInitializable, IUpgradable {
using Address for address;
using SafeNativeTransfer for address payable;

Expand All @@ -69,8 +71,12 @@ contract Gateway is IGateway, IInitializable {
// 2. Calling implementation function
uint256 DISPATCH_OVERHEAD_GAS = 10_000;

// The maximum fee that can be sent to a destination parachain to pay for execution (DOT)
uint128 internal immutable MAX_DESTINATION_TRANSFER_FEE;
// The maximum fee that can be sent to a destination parachain to pay for execution (DOT).
// Has two functions:
// * Reduces the ability of users to perform arbitrage using a favourable exchange rate
// * Prevents users from mistakenly providing too much fees, which would drain AssetHub's
// sovereign account here on Ethereum.
uint128 internal immutable MAX_DESTINATION_FEE;

uint8 internal immutable FOREIGN_TOKEN_DECIMALS;

Expand All @@ -87,11 +93,9 @@ contract Gateway is IGateway, IInitializable {
error InvalidChannelUpdate();
error AgentExecutionFailed(bytes returndata);
error InvalidAgentExecutionPayload();
error InvalidCodeHash();
error InvalidConstructorParams();
error AlreadyInitialized();

// handler functions are privileged
// Message handlers can only be dispatched by the gateway itself
modifier onlySelf() {
if (msg.sender != address(this)) {
revert Unauthorized();
Expand All @@ -105,7 +109,7 @@ contract Gateway is IGateway, IInitializable {
ParaID bridgeHubParaID,
bytes32 bridgeHubAgentID,
uint8 foreignTokenDecimals,
uint128 destinationMaxTransferFee
uint128 maxDestinationFee
) {
if (bridgeHubParaID == ParaID.wrap(0) || bridgeHubAgentID == 0) {
revert InvalidConstructorParams();
Expand All @@ -117,7 +121,7 @@ contract Gateway is IGateway, IInitializable {
BRIDGE_HUB_PARA_ID = bridgeHubParaID;
BRIDGE_HUB_AGENT_ID = bridgeHubAgentID;
FOREIGN_TOKEN_DECIMALS = foreignTokenDecimals;
MAX_DESTINATION_TRANSFER_FEE = destinationMaxTransferFee;
MAX_DESTINATION_FEE = maxDestinationFee;
}

/// @dev Submit a message from Polkadot for verification and dispatch
Expand Down Expand Up @@ -336,29 +340,7 @@ contract Gateway is IGateway, IInitializable {
/// @dev Perform an upgrade of the gateway
function upgrade(bytes calldata data) external onlySelf {
UpgradeParams memory params = abi.decode(data, (UpgradeParams));

// Verify that the implementation is actually a contract
if (!params.impl.isContract()) {
revert InvalidCodeHash();
}

// As a sanity check, ensure that the codehash of implementation contract
// matches the codehash in the upgrade proposal
if (params.impl.codehash != params.implCodeHash) {
revert InvalidCodeHash();
}

// Update the proxy with the address of the new implementation
ERC1967.store(params.impl);

// Apply the initialization function of the implementation only if params were provided
if (params.initParams.length > 0) {
(bool success, bytes memory returndata) =
params.impl.delegatecall(abi.encodeCall(IInitializable.initialize, params.initParams));
Call.verifyResult(success, returndata);
}

emit Upgraded(params.impl);
Upgrade.upgrade(params.impl, params.implCodeHash, params.initParams);
}

// @dev Set the operating mode of the gateway
Expand Down Expand Up @@ -433,12 +415,8 @@ contract Gateway is IGateway, IInitializable {
uint128 destinationFee,
uint128 amount
) external payable {
if (destinationFee > MAX_DESTINATION_TRANSFER_FEE) {
revert Assets.InvalidDestinationFee();
}

_submitOutbound(
Assets.sendToken(token, msg.sender, destinationChain, destinationAddress, destinationFee, amount)
Assets.sendToken(token, msg.sender, destinationChain, destinationAddress, destinationFee, MAX_DESTINATION_FEE, amount)
);
}

Expand Down Expand Up @@ -596,10 +574,6 @@ contract Gateway is IGateway, IInitializable {

CoreStorage.Layout storage core = CoreStorage.layout();

if (core.channels[PRIMARY_GOVERNANCE_CHANNEL_ID].agent != address(0)) {
revert AlreadyInitialized();
}

Config memory config = abi.decode(data, (Config));

core.mode = config.mode;
Expand Down
29 changes: 29 additions & 0 deletions contracts/src/Shell.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

import {Upgrade} from "./Upgrade.sol";
import {IInitializable} from "./interfaces/IInitializable.sol";
import {IUpgradable} from "./interfaces/IUpgradable.sol";
import {IShell} from "./interfaces/IShell.sol";

// address recoveryOperator = vm.envOr("RECOVERY_OPERATOR", address(0));

contract Shell is IShell, IUpgradable, IInitializable {
address public immutable operator;

error Unauthorised();

constructor(address _operator) {
operator = _operator;
}

function upgrade(address impl, bytes32 implCodeHash, bytes calldata initializerParams) external {
if (msg.sender != operator) {
revert Unauthorised();
}
Upgrade.upgrade(impl, implCodeHash, initializerParams);
}

function initialize(bytes memory params) external {}
}
37 changes: 37 additions & 0 deletions contracts/src/Upgrade.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

import {ERC1967} from "./utils/ERC1967.sol";
import {Call} from "./utils/Call.sol";
import {Address} from "./utils/Address.sol";
import {IInitializable} from "./interfaces/IInitializable.sol";
import {IUpgradable} from "./interfaces/IUpgradable.sol";

/// @dev Upgrades implementation contract
library Upgrade {
using Address for address;

function upgrade(address impl, bytes32 implCodeHash, bytes memory initializerParams) internal {
// Verify that the implementation is actually a contract
if (!impl.isContract()) {
revert IUpgradable.InvalidContract();
}

// As a sanity check, ensure that the codehash of implementation contract
// matches the codehash in the upgrade proposal
if (impl.codehash != implCodeHash) {
revert IUpgradable.InvalidCodeHash();
}

// Update the proxy with the address of the new implementation
ERC1967.store(impl);

// Call the initializer
(bool success, bytes memory returndata) =
impl.delegatecall(abi.encodeCall(IInitializable.initialize, initializerParams));
Call.verifyResult(success, returndata);

emit IUpgradable.Upgraded(impl);
}
}
3 changes: 0 additions & 3 deletions contracts/src/interfaces/IGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ interface IGateway {
// Emitted when a channel has been updated
event ChannelUpdated(ChannelID indexed channelID);

// Emitted when the gateway is upgraded
event Upgraded(address indexed implementation);

// Emitted when the operating mode is changed
event OperatingModeChanged(OperatingMode mode);

Expand Down
8 changes: 8 additions & 0 deletions contracts/src/interfaces/IShell.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

interface IShell {
// Upgrade gateway shell to a new implementation
function upgrade(address impl, bytes32 implCodeHash, bytes calldata initializerParams) external;
}
13 changes: 13 additions & 0 deletions contracts/src/interfaces/IUpgradable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
pragma solidity 0.8.23;

interface IUpgradable {
// The new implementation address is a not a contract
error InvalidContract();
// The supplied codehash does not match the new implementation codehash
error InvalidCodeHash();

// The implementation contract was upgraded
event Upgraded(address indexed implementation);
}
5 changes: 1 addition & 4 deletions contracts/src/upgrades/rococo/GatewayV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {PricingStorage} from "../../storage/PricingStorage.sol";

contract GatewayV2 is Gateway {
constructor(
address recoveryOperator,
address beefyClient,
address agentExecutor,
ParaID bridgeHubParaID,
Expand All @@ -34,10 +35,6 @@ contract GatewayV2 is Gateway {

PricingStorage.Layout storage pricing = PricingStorage.layout();

if (pricing.multiplier != convert(0)) {
revert AlreadyInitialized();
}

pricing.multiplier = abi.decode(data, (UD60x18));
}
}
Loading

0 comments on commit f574f36

Please sign in to comment.