-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
eef919a
commit 713db56
Showing
2 changed files
with
343 additions
and
0 deletions.
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,105 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity ^0.8.12; | ||
|
||
import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; | ||
import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
import "openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol"; | ||
import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol"; | ||
|
||
import "./interfaces/IDaimoPayBridger.sol"; | ||
import "./DaimoFastCCTP.sol"; | ||
import "../vendor/across/V3SpokePoolInterface.sol"; | ||
|
||
/// @title Bridger implementation for Across Protocol | ||
/// @author The Daimo team | ||
/// @custom:security-contact [email protected] | ||
/// | ||
/// Bridges assets from to a destination chain using Across Protocol. | ||
contract DaimoPayAcrossBridger is | ||
IDaimoPayBridger, | ||
Ownable2StepUpgradeable, | ||
UUPSUpgradeable | ||
{ | ||
using SafeERC20 for IERC20; | ||
|
||
// SpokePool contract address for this chain. | ||
V3SpokePoolInterface public immutable spokePool; | ||
|
||
event BridgeInitiated( | ||
address indexed sender, | ||
IERC20 indexed tokenIn, | ||
uint256 amountIn, | ||
uint256 toChainID | ||
); | ||
|
||
constructor() { | ||
_disableInitializers(); | ||
} | ||
|
||
// ----- ADMIN FUNCTIONS ----- | ||
|
||
/// Initialize. Specify owner (not msg.sender) to allow CREATE3 deployment. | ||
function init( | ||
address _initialOwner, | ||
V3SpokePoolInterface _spokePool | ||
) public initializer { | ||
__Ownable_init(_initialOwner); | ||
|
||
spokePool = _spokePool; | ||
} | ||
|
||
/// UUPSUpsgradeable: only allow owner to upgrade | ||
function _authorizeUpgrade(address) internal view override onlyOwner {} | ||
|
||
/// UUPSUpgradeable: expose implementation | ||
function implementation() public view returns (address) { | ||
return ERC1967Utils.getImplementation(); | ||
} | ||
|
||
// ----- PUBLIC FUNCTIONS ----- | ||
|
||
/// Initiates a bridge to a destination chain using Across Protocol. | ||
function sendToChain( | ||
IERC20 tokenIn, | ||
uint256 amountIn, | ||
uint256 toChainID, | ||
bytes calldata extraData | ||
) public { | ||
// Parse remaining arguments from extraData | ||
( | ||
address outputToken, | ||
uint256 outputAmount, | ||
address exclusiveRelayer, | ||
uint32 quoteTimestamp, | ||
uint32 fillDeadline, | ||
uint32 exclusivityDeadline, | ||
bytes memory message | ||
) = abi.decode(extraData, (address, uint256, address, uint32, uint32, uint32, bytes)); | ||
|
||
// Move input token from caller to this contract and approve the | ||
// SpokePool contract. | ||
tokenIn.safeTransferFrom({ | ||
from: msg.sender, | ||
to: address(this), | ||
value: amountIn | ||
}); | ||
tokenIn.forceApprove({spender: address(spokePool), value: amountIn}); | ||
|
||
spokePool.depositV3({ | ||
depositor: address(this), | ||
recipient: msg.sender, | ||
inputToken: address(tokenIn), | ||
outputToken: outputToken, | ||
inputAmount: amountIn, | ||
outputAmount: outputAmount, | ||
destinationChainId: toChainID, | ||
exclusiveRelayer: exclusiveRelayer, | ||
quoteTimestamp: quoteTimestamp, | ||
fillDeadline: fillDeadline, | ||
exclusivityDeadline: exclusivityDeadline, | ||
message: message | ||
}); | ||
|
||
emit BridgeInitiated(msg.sender, tokenIn, amountIn, toChainID); | ||
} | ||
} |
238 changes: 238 additions & 0 deletions
238
packages/contract/vendor/across/V3SpokePoolInterface.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,238 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity ^0.8.0; | ||
|
||
// Contains structs and functions used by SpokePool contracts to facilitate universal settlement. | ||
interface V3SpokePoolInterface { | ||
/************************************** | ||
* ENUMS * | ||
**************************************/ | ||
|
||
// Fill status tracks on-chain state of deposit, uniquely identified by relayHash. | ||
enum FillStatus { | ||
Unfilled, | ||
RequestedSlowFill, | ||
Filled | ||
} | ||
// Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of | ||
// fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess. | ||
enum FillType { | ||
FastFill, | ||
// Fast fills are normal fills that do not replace a slow fill request. | ||
ReplacedSlowFill, | ||
// Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker | ||
// to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used | ||
// for a slow fill execution. | ||
SlowFill | ||
// Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing | ||
// the slow fill is validated. | ||
} | ||
|
||
/************************************** | ||
* STRUCTS * | ||
**************************************/ | ||
|
||
// This struct represents the data to fully specify a **unique** relay submitted on this chain. | ||
// This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against | ||
// replay attacks on other chains. If any portion of this data differs, the relay is considered to be | ||
// completely distinct. | ||
struct V3RelayData { | ||
// The address that made the deposit on the origin chain. | ||
address depositor; | ||
// The recipient address on the destination chain. | ||
address recipient; | ||
// This is the exclusive relayer who can fill the deposit before the exclusivity deadline. | ||
address exclusiveRelayer; | ||
// Token that is deposited on origin chain by depositor. | ||
address inputToken; | ||
// Token that is received on destination chain by recipient. | ||
address outputToken; | ||
// The amount of input token deposited by depositor. | ||
uint256 inputAmount; | ||
// The amount of output token to be received by recipient. | ||
uint256 outputAmount; | ||
// Origin chain id. | ||
uint256 originChainId; | ||
// The id uniquely identifying this deposit on the origin chain. | ||
uint32 depositId; | ||
// The timestamp on the destination chain after which this deposit can no longer be filled. | ||
uint32 fillDeadline; | ||
// The timestamp on the destination chain after which any relayer can fill the deposit. | ||
uint32 exclusivityDeadline; | ||
// Data that is forwarded to the recipient. | ||
bytes message; | ||
} | ||
|
||
// Contains parameters passed in by someone who wants to execute a slow relay leaf. | ||
struct V3SlowFill { | ||
V3RelayData relayData; | ||
uint256 chainId; | ||
uint256 updatedOutputAmount; | ||
} | ||
|
||
// Contains information about a relay to be sent along with additional information that is not unique to the | ||
// relay itself but is required to know how to process the relay. For example, "updatedX" fields can be used | ||
// by the relayer to modify fields of the relay with the depositor's permission, and "repaymentChainId" is specified | ||
// by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay. | ||
struct V3RelayExecutionParams { | ||
V3RelayData relay; | ||
bytes32 relayHash; | ||
uint256 updatedOutputAmount; | ||
address updatedRecipient; | ||
bytes updatedMessage; | ||
uint256 repaymentChainId; | ||
} | ||
|
||
// Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise. | ||
// Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being | ||
// filled so they don't have to be unpacked by all clients. | ||
struct V3RelayExecutionEventInfo { | ||
address updatedRecipient; | ||
bytes updatedMessage; | ||
uint256 updatedOutputAmount; | ||
FillType fillType; | ||
} | ||
|
||
/************************************** | ||
* EVENTS * | ||
**************************************/ | ||
|
||
event V3FundsDeposited( | ||
address inputToken, | ||
address outputToken, | ||
uint256 inputAmount, | ||
uint256 outputAmount, | ||
uint256 indexed destinationChainId, | ||
uint32 indexed depositId, | ||
uint32 quoteTimestamp, | ||
uint32 fillDeadline, | ||
uint32 exclusivityDeadline, | ||
address indexed depositor, | ||
address recipient, | ||
address exclusiveRelayer, | ||
bytes message | ||
); | ||
|
||
event RequestedSpeedUpV3Deposit( | ||
uint256 updatedOutputAmount, | ||
uint32 indexed depositId, | ||
address indexed depositor, | ||
address updatedRecipient, | ||
bytes updatedMessage, | ||
bytes depositorSignature | ||
); | ||
|
||
event FilledV3Relay( | ||
address inputToken, | ||
address outputToken, | ||
uint256 inputAmount, | ||
uint256 outputAmount, | ||
uint256 repaymentChainId, | ||
uint256 indexed originChainId, | ||
uint32 indexed depositId, | ||
uint32 fillDeadline, | ||
uint32 exclusivityDeadline, | ||
address exclusiveRelayer, | ||
address indexed relayer, | ||
address depositor, | ||
address recipient, | ||
bytes message, | ||
V3RelayExecutionEventInfo relayExecutionInfo | ||
); | ||
|
||
event RequestedV3SlowFill( | ||
address inputToken, | ||
address outputToken, | ||
uint256 inputAmount, | ||
uint256 outputAmount, | ||
uint256 indexed originChainId, | ||
uint32 indexed depositId, | ||
uint32 fillDeadline, | ||
uint32 exclusivityDeadline, | ||
address exclusiveRelayer, | ||
address depositor, | ||
address recipient, | ||
bytes message | ||
); | ||
|
||
/************************************** | ||
* FUNCTIONS * | ||
**************************************/ | ||
|
||
function depositV3( | ||
address depositor, | ||
address recipient, | ||
address inputToken, | ||
address outputToken, | ||
uint256 inputAmount, | ||
uint256 outputAmount, | ||
uint256 destinationChainId, | ||
address exclusiveRelayer, | ||
uint32 quoteTimestamp, | ||
uint32 fillDeadline, | ||
uint32 exclusivityDeadline, | ||
bytes calldata message | ||
) external payable; | ||
|
||
function depositV3Now( | ||
address depositor, | ||
address recipient, | ||
address inputToken, | ||
address outputToken, | ||
uint256 inputAmount, | ||
uint256 outputAmount, | ||
uint256 destinationChainId, | ||
address exclusiveRelayer, | ||
uint32 fillDeadlineOffset, | ||
uint32 exclusivityDeadline, | ||
bytes calldata message | ||
) external payable; | ||
|
||
function speedUpV3Deposit( | ||
address depositor, | ||
uint32 depositId, | ||
uint256 updatedOutputAmount, | ||
address updatedRecipient, | ||
bytes calldata updatedMessage, | ||
bytes calldata depositorSignature | ||
) external; | ||
|
||
function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external; | ||
|
||
function fillV3RelayWithUpdatedDeposit( | ||
V3RelayData calldata relayData, | ||
uint256 repaymentChainId, | ||
uint256 updatedOutputAmount, | ||
address updatedRecipient, | ||
bytes calldata updatedMessage, | ||
bytes calldata depositorSignature | ||
) external; | ||
|
||
function requestV3SlowFill(V3RelayData calldata relayData) external; | ||
|
||
function executeV3SlowRelayLeaf( | ||
V3SlowFill calldata slowFillLeaf, | ||
uint32 rootBundleId, | ||
bytes32[] calldata proof | ||
) external; | ||
|
||
/************************************** | ||
* ERRORS * | ||
**************************************/ | ||
|
||
error DisabledRoute(); | ||
error InvalidQuoteTimestamp(); | ||
error InvalidFillDeadline(); | ||
error InvalidExclusiveRelayer(); | ||
error InvalidExclusivityDeadline(); | ||
error MsgValueDoesNotMatchInputAmount(); | ||
error NotExclusiveRelayer(); | ||
error NoSlowFillsInExclusivityWindow(); | ||
error RelayFilled(); | ||
error InvalidSlowFillRequest(); | ||
error ExpiredFillDeadline(); | ||
error InvalidMerkleProof(); | ||
error InvalidChainId(); | ||
error InvalidMerkleLeaf(); | ||
error ClaimedMerkleLeaf(); | ||
error InvalidPayoutAdjustmentPct(); | ||
} |