Skip to content

swaps-io/flash-contracts

Repository files navigation

Flash Contracts

Table of Contents

Description

Flash is a cross-chain asset swap system based on contracts presented in this project.

Actors

The system has four primary actors:

  • User - wants to swap one asset (i.e. any ERC-20 token or native currency in some cases) to another
  • Resolver - offers swap terms for user and then executes user-confirmed orders
  • Service - connects users and resolvers
  • Liquidator - optionally closes orders failed by resolver

The system has no admin roles on the contract level at the moment. Some contracts accept other contract addresses or some sort of security configuration in their constructors, that is designed to be immutable, i.e. cannot be changed by anyone once deployed.

Order Types

Flash supports multiple order structure types:

  • Order - order for swapping one EVM asset to another EVM asset
  • OrderBitcoin - order for swapping EVM asset to Bitcoin

Order

Order that allows user to swap one EVM asset to another EVM asset with resolver.

Order Flow

The swap process is initiated by user. They enter parameters of the swap they are interested in and pass them to the service. The service queries registered resolvers for suitable swap orders they can provide. User reviews collected orders and picks satisfying one (or not).

Once user is satisfied with an order, they sign it with the private key associated with the address they hold asset to swap on. The required signature is of EIP-712 standard for the Order typed data structure. Note that user is "from" actor with "from" asset, swapping to "to" asset of "to" actor, i.e. resolver. See the "Order Structure" section for more details on order structure.

After that, the signature is passed to resolver so it can execute the order via the contracts. In general, good acting resolver does the following:

  • receives user's "from" asset on the "from" chain
  • sends "to" asset on the "to" chain to user

If receive is not performed by resolver (within deadline specified in the order), the swap is considered cancelled. If resolver receives user's "from" asset, but doesn't send "to" asset back (within another deadline) - resolver's collateral becomes a subject to be slashed.

The collateral servers as insurance for orders. Resolver deposits allowed collateral asset (ERC-20 stablecoin token) into collateral manager contract. It's deposited for a specific receive chain. Both chains keep track of collateral usage:

  • "locked" counter in the receive chain: increased by collateral amount specified in the executed order. Order must not be executed if locked amount exceeds unlocked amount passed as field of user-signed order thus considered verified by them
  • "unlocked" counter in the collateral chain: increased each time successful order execution is confirmed by resolver by providing corresponding proofs

In order to withdraw collateral, resolver must provide another proof that verifies counter value in receive chain and that the desired withdraw amount of the collateral asset can be safely returned without hanging any orders uninsured.

Proof verifies that a certain EVM-event with specific data has indeed occurred on some chain. The proof events are used for all swap scenarios are produced on chains where assets are received and sent, and consumed by collateral manager.

To confirm order execution, resolver must provide two proofs:

  • order asset received on "from" chain
  • order asset sent on "to" chain

When resolver fails to send asset to user, the liquidation flow is first activated. In this flow, a liquidator may send their own "to" asset instead of resolver to user. This allows to slash collateral in favor of liquidator when two proofs are provided:

  • order asset received on "from" chain
  • order asset sent on "to" chain by liquidator

When neither resolver nor liquidator send "to" asset, slash by user is activated. In this flow, user gets resolver's collateral instead of "to" asset. For doing that, "no-send" event must be reported on "to" chain (by user or arbitrary liquidator) by calling corresponding method. This allows collateral slash in favor of user when two proofs are provided:

  • order asset received on "from" chain
  • order asset sent not sent on "to" chain

Note that liquidator in this flow may call both report and slash methods. The main share of the order collateral still goes to user in this case, liquidator gets rewarded for performing two transaction with smaller collateral share as specified in the order.

For more order execution details, see info of the following contracts:

Order Structure

The Order structure has the following fields (that must be validated in accordance with their descriptions below at least by user):

  • fromActor (address) - user address that holds the "from" asset
  • fromActorReceiver (address) - user address that will receive "to" asset from resolver
  • fromChain (uint256) - EVM chain ID (i.e. block.chainid) where "from" asset is
  • fromToken (address) - ERC-20 token address of the "from" asset
  • fromAmount (uint256) - amount of the "from" asset user is giving to resolver
  • toActor (address) - resolver address that will send "to" asset to user and receive "from" asset
  • toChain (uint256) - EVM chain ID where "to" asset is
  • toToken (address) - ERC-20 token address of the "to" asset
  • toAmount (uint256) - amount of the "to" asset resolver is giving to user
  • collateralReceiver (address) - user address that will receive "collateral" asset from resolver in case of slash
  • collateralChain (uint256) - EVM chain ID where "collateral" asset is
  • collateralAmount (uint256) - amount of the "collateral" asset allocated for the swap
  • collateralRewardable (uint256) - amount of the "collateral" asset that is allowed to be used from collateralAmount amount as reward for "no-send" report liquidator. Logically expected to be significantly less than collateralAmount, but technically can be as large (which sends 100% of order collateral to "no-send" liquidator - unlikely desired by user)
  • deadline (uint256) - timestamp in seconds (i.e. block.timestamp) after which user's "from" asset can no longer be received by resolver using this order
  • timeToSend (uint256) - time in seconds that is added to deadline to get send deadline. After the send deadline resolver will not be able to send "to" asset to user using method exclusive to them - asset send becomes subject to liquidation by arbitrary liquidator
  • timeToLiqSend (uint256) - time in seconds that is added to deadline and timeToSend to get liquidation send deadline. After the liquidation send deadline no liquidator will be able to send "to" asset to user - order collateral becomes subject to be slashed by user
  • nonce (uint256) - a resolver-assigned value that:
    • makes every order hash (and hence EIP-712 signature) unique
    • prevents order from executing twice - nonce usage is tracked in "from", "to", and "collateral" chains
    • must be unique per toActor - prevents nonce conflicts between resolvers thus allowing each of them to assign nonces sequentially (which has gas benefits due to how nonce usage info is stored)

OrderBitcoin

Order that allows user to swap their EVM asset to Bitcoin with resolver or vise versa.

OrderBitcoin Flow

Similarly to Order flow, swap process is initiated by user entering params and resolvers are queried by the service. For activating the Bitcoin flow, user should select "from" or "to" asset to be Bitcoin, which returns OrderBitcoin structure instead of Order to review by user and provide their EIP-712 signature.

The OrderBitcoin structure extends Order, but some of the fields reflect the Bitcoin part. Bitcoin chain is assigned to a specific constant which is selected during deployment (doesn't conflict with other EVM chain IDs) and number of amount decimals (which is 8 for Bitcoin). This applies to:

  • fromChain, fromToken, fromAmount - when Bitcoin is sent by user in exchange for resolver's EVM asset
  • toChain, toToken, toAmount - when Bitcoin is sent by resolver in exchange for user's EVM asset
  • collateralAmount, collateralRewardable - when WBTC token-based collateral manager is used for the swap (which is currently always true for Bitcoin orders)

When "send" part of the order should be performed on Bitcoin chain (i.e. Bitcoin is "to" asset), related fields should be configured accordingly:

  • timeToSend - deadline to send Bitcoin starting at createdAtBitcoin time
  • timeToLiqSend - unused, since send by liquidator is not supported on Bitcoin chain. Preferred to be 0 for explicitness

When "receive" part of the order is on Bitcoin chain (Bitcoin is "from"), timeToSend role is taken by new timeToReceiveBitcoin field (starting from createdAtBitcoin as well). Note that Bitcoin transactions must be exactly between start and deadline of the period, otherwise they are not possible to submit to proofer and may be considered non-existent.

Last two new fields added to order are fromActorBitcoin and toActorBitcoin. Depending on the order direction, these have the following meanings and rules:

  • User's Bitcoin "from" <-> Resolver's EVM "to"

    • fromActorBitcoin - Bitcoin address of user (fromActor). Can be a special constant indicating that send from any address is allowed for user
    • toActorBitcoin - Bitcoin address of the resolver (toActor). When fromActorBitcoin is the "any" address constant, resolver's address is required to be unique among other orders
  • User's EVM "from" <-> Resolver's Bitcoin "to"

    • fromActorBitcoin - Bitcoin address of the user (fromActor). "Any" address is not allowed
    • toActorBitcoin - Bitcoin address of the resolver (toActor). Not required to be unique among other orders

After order formation, the order execution steps depend on the swap direction:

  • User's Bitcoin "from" <-> Resolver's EVM "to"

    Before user send their Bitcoin, it's important to ensure there is sufficient collateral reserved for the order on resolver side. To do that, user (at least) monitors collateral chain for collateral lock status by resolver in the Bitcoin reserver sub-contract (facet of the main contract). This is done via querying view method with the current order hash as param. Once state changed to "locked", user is safe to send their Bitcoin to resolver.

    Note that locking collateral for Bitcoin order requires signature of the order by user, which is used to verify unlocked collateral amount (included into the signed order).

    After resolver received Bitcoin from user, they call send method specialized for OrderBitcoin orders on "to" chain exactly like it's done for "to" part of Order flow. Note that send by liquidator is available in this case too, as well as "no-send" reporting. The "send" event proofs are delivered to order resolver in order to unlock collateral.

    In order to proof receive event, resolver or any other actor should submit transfer data to Bitcoin proof verifier contract. If not submitted, then "no-receive" is considered to be true after time specified by createdAtBitcoin + timeToReceiveBitcoin + timeToSubmitBitcoin elapsed. With "no-receive" proof on their hands, resolver can unlock previously locked collateral, essentially cancelling the order due to inaction on user part.

    If resolver decides to receive user's Bitcoin and don't perform any send nor report the transfer by user, they risk a third party actor to still report the transfer. It may be at least the user themself (should be warned about "time dependent transaction may be needed" in advance). In case of such a report situation the resolver becomes subject to collateral slash ("receive" + "no-send" proofs available).

    At the same time, resolver is interested in reporting user's Bitcoin transfer on their own when they are conscientious and going to send "to" asset to user. This is due to the fact that otherwise no "receive" proof will be available to successfully unlock order collateral.

  • User's EVM "from" <-> Resolver's Bitcoin "to"

    Reverse Bitcoin flow starts in the same way as for Order, except resolver is using OrderBitcoin-dedicated method for receiving user asset on "from" EVM chain. Once the asset is received, resolver sends their Bitcoin.

    Here resolver is interested in reporting their Bitcoin send transfer on the Bitcoin collateral chain as soon as possible. If time specified by createdAtBitcoin + timeToSend elapsed and no transfer reported, "no-send" proof becomes available, making the order collateral slashable (resolver did receive user's EVM asset on "from" chain).

    Only "send" and "no-send" proofs are available, the liquidation flow is not possible for this direction of the Bitcoin order. All the proofs are delivered to the order resolver sub-contract via OrderBitcoin-specialized methods.

For more Bitcoin order execution details, see info of the following contracts:

OrderBitcoin Structure

The OrderBitcoin structure is used in methods for conducting swaps from EVM chain to Bitcoin and vice versa. The structure extends Order fields providing several new ones:

  • fromActorBitcoin (string) - user address on Bitcoin chain to send Bitcoin from or receive it to (depending on order direction). Can be a special constant indicating that any address is allowed for orders where Bitcoin is sent from user to resolver
  • toActorBitcoin (string) - resolver address on Bitcoin chain where Bitcoin will be sent from or to (depending on order direction). When user Bitcoin address is specified as "any" in the order, this address must be unique (otherwise Bitcoin reserver lock call will fail)
  • createdAtBitcoin (uint256) - creation time of the Bitcoin order. Used in Bitcoin transaction verification, not allowing transactions to be earlier than this time. Transactions also have end time after which they are considered unfulfilled - timeToReceiveBitcoin or timeToSend is added depending on order direction
  • timeToReceiveBitcoin (uint256) - specifies deadline to receive Bitcoin, i.e. time for user to send Bitcoin to specified resolver address
  • timeToSubmitBitcoin (uint256) - specifies time to submit Bitcoin transaction by user after the receive phase, i.e. total time to submit the Bitcoin receive is createdAtBitcoin + timeToReceiveBitcoin + timeToSubmitBitcoin

Contracts

The main contract of Flash project is a ERC-2535 Diamond proxy based on standard author's reference implementation. Besides cut & ownership facets provided by this implementation, Flash adds own facets providing various functionality that are added to the diamond, as well as some standalone contracts that are referenced by the facets. Details for each used contract are down below.

Note: facet contracts can be distinguished by the Facet suffix in their name

OrderReceiverFacet

Description

Serves for receiving user assets. References ICollateralLocker compatible contract for tracking if resolver is eligible for starting the order execution, i.e. if collateral counter is sufficient.

Interface

IOrderReceiver.sol

Implementation

OrderReceiverFacet.sol

Write

  • receiveOrderAsset(Order calldata order, bytes32 fromSigR, bytes32 fromSigVs)

    Receives user's "from" asset in amount and sends it to the "to" actor address as specified in order. Can only be called by "to" actor specified in order. Cannot be called after deadline time specified in order exceeded. Requires valid "from" actor compact signature - fromSigR, fromSigVs params. Sufficiency of collateral is checked via referenced collateral locker using order's collateralAmount & collateralUnlocked fields. When execution is successful, emits the AssetReceive event with first topic being the order hash, which allows to proof "from" asset receive for the order. Receive is marked as performed for order in storage (readable via orderAssetReceived view) and the method cannot be called again with it.

    Errors:

    • OrderReceiveExpired - receive deadline specified by order exceeded
    • ReceiveChainMismatch - receive called on chain that differs from order's "from" chain
    • ReceiveCallerMismatch - receive called by account that differs from order's "to" actor
    • OrderAlreadyReceived - receive operation has already been called for the order
    • InvalidSignature - restored signer of the order signature mismatch the "from" actor
    • UnauthorizedLockAccess - "to" actor hasn't approved collateral locker contract on current chain
    • LockRefusal - order cannot be executed due to insufficient unlocked collateral amount according to order's reported unlocked amount and receive chain locked counter

Read

  • orderAssetReceived(bytes32 orderHash) -> bool

    Returns true if receiveOrderAsset method has been successfully called for order with hash specified by orderHash parameter, or false otherwise.

  • receiverCollateralLocker() -> ICollateralLocker

    Returns address of ICollateralLocker-compatible contract that is being used by this OrderReceiverFacet.

OrderSenderFacet

Description

Serves for sending assets to user. This contract supports both sending by resolver and liquidator, as well as "no-send" reporting in case of complete inaction of both parties.

Interface

IOrderSender.sol

Implementation

OrderSenderFacet.sol

Write

  • sendOrderAsset(Order calldata order)

    Sends resolver's "to" asset in amount and to the "from" actor address as specified in order. Can only be called by "to" actor specified in the order. The method is not allowed to be called after the send deadline, calculated as order's deadline + timeToSend. When succeeds, the AssetSend event is emitted, having hash of the swap as first topic for proofing. The resolver is not interested in modifying the order since otherwise different hash will be produced not matching the original swap hash in the receive proof - which is a requirement for swap confirmation in collateral unlocker. Send is marked as performed for order in storage (readable via orderAssetSent view) and the method cannot be called again with it (along with other send methods).

    Errors:

    • OrderSendExpired - send deadline specified by order exceeded
    • SendChainMismatch - send called on chain that differs from order's "to" chain
    • SendCallerMismatch - send called by account that differs from order's "to" actor
    • OrderAlreadySent - send operation has already been called for the order
  • sendOrderLiqAsset(Order calldata order)

    Sends liquidator's "to" asset in amount and to the "from" actor address as specified in order. Anyone can be the liquidator caller of this method. The method becomes available once send deadline is exceeded and until liquidation send deadline is reached, calculated as order's deadline + timeToSend + timeToLiqSend and sendOrderAsset has not been called by resolver. When succeeds, the AssetLiqSend event is emitted, having hash of the concatenation of the swap hash combined with liquidator address as first topic for proofing. The liquidator is not interested in modifying the order since otherwise a different hash will be produced not matching the original swap hash in the receive proof - which is a requirement for obtaining resolver's slashed collateral in collateral unlocker. Send is marked as performed for order in storage (readable via orderAssetSent view) and the method cannot be called again with it.

    Errors:

    • OrderLiqSendExpired - liquidation send deadline specified by order exceeded
    • OrderLiqSendUnreached - send deadline specified by order is not exceeded yet
    • SendChainMismatch - liquidation send called on chain that differs from order's "to" chain
    • OrderAlreadySent - send operation has already been called for the order
  • reportOrderNoSend(Order calldata order)

    Provides proof of the fact that asset has not been sent by any party of the swap flow. Becomes available once liquidation send deadline is exceeded and neither sendOrderAsset nor sendOrderLiqAsset has been called. When succeeds, the AssetNoSend event is emitted, having hash of the concatenation of the swap hash combined with caller ("reporter" liquidator) address as first topic for proofing. Anyone is allowed to call this method, the calling liquidator is not interested in modifying the order since otherwise different hash will be produced not matching the original wap hash in the receive proof - which is requirement for sending collateral to user and obtaining its reward-designated part for the liquidator.

    Errors:

    • OrderNoSendUnreached - liquidation send deadline specified by order is not exceeded yet
    • SendChainMismatch - no-send report called on chain that differs from order's "to" chain
    • OrderAlreadySent - send (or its liquidation variant) operation has already been called for the order.

Read

  • orderAssetSent(bytes32 orderHash) -> bool

    Returns true if sendOrderAsset or sendOrderLiqAsset method has been successfully called for order with hash specified by orderHash parameter, or false otherwise.

  • orderLiquidator(bytes32 orderHash) -> address

    Returns address of sendOrderLiqAsset caller, i.e. liquidator. Zero address is returned if sendOrderLiqAsset has not been called. Note that this value may only change while orderAssetSent view returns false and order liquidation send call deadline (i.e. deadline + timeToSend + timeToLiqSend and sendOrderAsset) is not reached.

OrderSenderNativeFacet

Description

Extension for OrderSenderFacet contract that allows resolver or liquidator to send native "to" asset to user.

Interface

IOrderSenderNative.sol

Implementation

OrderSenderNativeFacet.sol

Dependencies

Write

  • sendOrderAssetNative(Order calldata order)

    Works in the same way as sendOrderAsset method of OrderSenderFacet, except adds an extra step that unwraps native token received from resolver and sends unwrapped native currency to user. Note that native token address in use can be obtained via nativeToken view method of NativeTokenFacet dependency.

    Errors:

    • OrderSendNotNative - "to" asset address specified in order is not set to special constant reserved for native
  • sendOrderLiqAssetNative(Order calldata order)

    Works in the same way as sendOrderLiqAsset method of OrderSenderFacet, except adds an extra step that unwraps native token received from liquidator and sends unwrapped native currency to user. Note that native token address in use can be obtained via nativeToken view method of NativeTokenFacet dependency.

    Errors:

    • OrderSendNotNative - "to" asset address specified in order is not set to special constant reserved for native

OrderResolverFacet

Description

Serves for finalizing order execution and management of collateral associated with it. Primarily resolver successfully confirms order execution, or its collateral is slashed in favour of order liquidator or user. The collateral management is done via referenced ICollateralUnlocker and IProofVerifier contracts.

Interface

IOrderResolver.sol

Implementation

OrderResolverFacet.sol

Write

  • confirmOrderAssetSend(Order calldata order, bytes calldata receiveProof, bytes calldata sendProof)

    Method primarily used by resolver (but allowed to be called by anyone) to confirm successful order execution. The confirmation releases collateralAmount associated with the order in collateral unlocker making it usable for further orders or withdraw. The order hash is calculated and expected to be presented in both valid proofs for verifying its integrity: receiveProof of AssetReceive event on "from" chain and sendProof of AssetSend event on "to" chain. Marks order resolution in storage (readable via orderResolved view). Emits OrderSendConfirm(bytes32 orderHash) event on success for informational purposes.

    Errors:

    • CollateralChainMismatch - confirm called on chain that differs from order's "collateral" chain
    • OrderAlreadyResolved - confirm called for order that has already been resolved
    • UnauthorizedUnlockAccess - "to" actor hasn't approved collateral unlocker contract on current chain
    • a proof verifier specific error - when proof is not valid
  • slashOrderLiqCollateral(Order calldata order, address liquidator, bytes calldata receiveProof, bytes calldata liqSendProof)

    Method used by liquidator (or any other helper account) to slash resolver collateral allocated for order in liquidator's favor as compensation after sending own "to" asset to user. The order hash is calculated and expected to be presented in valid receiveProof of AssetReceive event on "from" chain. The hash is then combined with liquidator address and hashed again - this time expected to be in valid liqSendProof of AssetLiqSend event on "to" chain. Full amount (as specified in order) of collateral asset is sent to liquidator address. Marks order resolution in storage (readable via orderResolved view). Emits OrderCollateralSlash(bytes32 orderHash) event for informational purposes.

    Errors:

    • CollateralChainMismatch - slash called on chain that differs from order's "collateral" chain
    • OrderAlreadyResolved - slash called for order that has already been resolved
    • UnauthorizedUnlockAccess - "to" actor hasn't approved collateral unlocker contract on current chain
    • a proof verifier specific error - when proof is not valid
  • slashOrderCollateral(Order calldata order, address reporter, bytes calldata receiveProof, bytes calldata noSendProof)

    Method user by user (or any other account, including liquidator helper) to slash resolver collateral allocated for order in user's favor as compensation after "from" asset was received from them and nothing was sent as "to" asset by any party of the flow. The order hash is calculated and expected to be presented in valid receiveProof of AssetReceive event on "from" chain. The hash is then combined with reporter address (which is user address if user called "no-send" report on their own or liquidator helper address if it was their transaction) and hashed again - this time expected to be in valid noSendProof of AssetNoSend event on "to" chain. Full amount (as specified in order) of collateral asset is sent to user address if reporter matches their address or no reward specified in the order, alternatively the rewardable share of the collateral is sent to the reporter. Marks order resolution in storage (readable via orderResolved view). Emits OrderCollateralSlash(bytes32 orderHash) event for informational purposes.

    Errors:

    • CollateralChainMismatch - slash called on chain that differs from order's "collateral" chain
    • OrderAlreadyResolved - slash called for order that has already been resolved
    • UnauthorizedUnlockAccess - "to" actor hasn't approved collateral unlocker contract on current chain
    • a proof verifier specific error - when proof is not valid

Read

  • orderResolved(bytes32 orderHash) -> bool

    Returns true if order with specified orderHash has been resolved, i.e. one of confirmOrderAssetSend, slashOrderLiqCollateral, or slashOrderCollateral method has been successfully called for it, or false otherwise.

  • resolverCollateralUnlocker() -> ICollateralUnlocker

    Returns address of ICollateralUnlocker-compatible contract that is being used by this OrderResolverFacet.

  • resolverProofVerifier() -> IProofVerifier

    Returns address of IProofVerifier-compatible contract that is being used by this OrderResolverFacet.

OrderBitcoinReserverFacet

Description

Provides collateral pre-lock functionality for resolver so collateral sufficiency can be verified by user before transferring their Bitcoin to resolver via referenced ICollateralLocker contract. The contract also references IProofVerifier for unlocking resolver collateral when user doesn't send Bitcoin.

Interface

IOrderBitcoinReserver.sol

Implementation

OrderBitcoinReserverFacet.sol

Write

  • lockOrderBitcoinCollateral(OrderBitcoin calldata order, bytes32 fromSigR, bytes32 fromSigVs)

    Locks resolver collateral for specified order, where user sends Bitcoin and receives EVM asset from resolver. The lock can only be called by resolver on collateralChain and requires signature (fromSigR & fromSigVs params) of the order by user. When collateral sufficiency is verified, the lock state is updated in the storage, which is readable via orderBitcoinCollateralState view. User must observe this view, and send their Bitcoin to resolver only after successful lock detected (view result changes from "pending" to "locked"). The lock call is restricted on time with deadline field of the order. Note that resolver can unlock the collateral if user didn't send Bitcoin (or it was not reported) with unlockOrderBitcoinCollateral call. The lock can only be performed once for an order. Resolver's "to" address on Bitcoin (i.e. toActorBitcoin) will be checked for usage uniqueness if user Bitcoin address (fromActorBitcoin) is assigned a special constant value indicating "transaction from any address". The fact of the address usage will be saved to storage and can be checked via bitcoinAddressUsedOrder view. Emits BitcoinCollateralLock(bytes32 orderHash) event on success for informational purposes.

    Errors:

    • BitcoinLockExpired - lock deadline specified by order exceeded
    • BitcoinLockChainMismatch - lock called on chain that is not the "collateral" one specified in the order
    • BitcoinLockerMismatch - lock called by actor different from "to" actor of the order (i.e. not by resolver)
    • BitcoinLockRefusal - lock cannot be performed due to incorrect state for the order (currently in "locked" or "unlocked" state)
    • BitcoinAddressUsed - toActorBitcoin address of the order already used but expected to be unique due to send from any address specified in fromActorBitcoin field
    • UnauthorizedLockAccess - "to" actor hasn't approved collateral locker contract on current chain
  • unlockOrderBitcoinCollateral(OrderBitcoin calldata order, bytes calldata noReceiveProof)

    Unlocks resolver collateral for specified order that was locked by lockOrderBitcoinCollateral before. This method is designed for the case when user didn't send Bitcoin to resolver as the fist step of the swap to EVM asset within deadline specified as createdAtBitcoin + timeToReceiveBitcoin (and additional timeToSubmitBitcoin time for safety) which is verified by checking noReceiveProof validity. The method cancels the lock and makes resolver collateral usable for other orders. The unlock changes state from "locked" to "unlocked" which is reflected in orderBitcoinCollateralState view. Re-locking for order from "unlocked" state is not possible. Emits BitcoinCollateralUnlock(bytes32 orderHash) event on success for informational purposes.

    Errors:

    • BitcoinUnlockRefusal - unlock cannot be performed due to incorrect state for the order (currently in "pending" or "unlocked" state)
    • UnauthorizedLockAccess - "to" actor hasn't approved collateral locker contract on current chain
    • a proof verifier specific error - when noReceiveProof is not a valid proof

Read

  • orderBitcoinCollateralState(bytes32 orderHash) -> BitcoinCollateralState

    Returns state of Bitcoin collateral locking for order corresponding to orderHash parameter. Each state is an enum member with corresponding meaning:

    • Pending - no lock committed for order, may change to Locked due to lock call by resolver
    • Locked - collateral is locked for order, may change to Unlocked by resolver if they can proof there was no Bitcoin transaction by user, otherwise can be considered terminal state
    • Unlocked - collateral was locked and then successfully unlocked for order, terminal state
  • bitcoinAddressUsedOrder(string calldata bitcoinAddress) -> bytes32

    Returns order hash that bitcoinAddress is used as unique toActorBitcoin address for. Zero bytes are returned if there is no such associated order with the address.

  • bitcoinReserverCollateralLocker() -> ICollateralLocker

    Returns address of ICollateralLocker-compatible contract that is being used by this OrderBitcoinReserverFacet.

  • bitcoinReserverProofVerifier() -> IProofVerifier

    Returns address of IProofVerifier-compatible contract that is being used by this OrderBitcoinReserverFacet.

OrderBitcoinReceiverFacet

Description

Extends OrderReceiverFacet facet for receiving user "EVM" assets in Bitcoin orders. References ICollateralLocker compatible contract for tracking if resolver is eligible for starting the order execution, i.e. if collateral counter is sufficient.

Interface

IOrderBitcoinReceiver.sol

Implementation

OrderBitcoinReceiverFacet.sol

Dependencies

Write

  • receiveOrderBitcoinAsset(OrderBitcoin calldata order, bytes32 fromSigR, bytes32 fromSigVs)

    Works exactly as receiveOrderAsset method of OrderReceiverFacet, except accepts OrderBitcoin struct instead of Order as order parameter. Expected to be called as a first step when user's EVM asset is swapped to resolver's Bitcoin.

Read

  • bitcoinReceiverCollateralLocker() -> ICollateralLocker

    Returns address of ICollateralLocker-compatible contract that is being used by this OrderBitcoinReceiverFacet.

OrderSenderBitcoinFacet

Description

Extends OrderSenderFacet facet for sending "EVM" asset to user assets in Bitcoin orders by resolver and liquidator, as well as "no-send" reporting in case of complete inaction of both parties.

Interface

IOrderBitcoinSender.sol

Implementation

OrderBitcoinSenderFacet.sol

Dependencies

Write

  • sendOrderBitcoinAsset(OrderBitcoin calldata order)

    Works exactly as sendOrderAsset method of OrderSenderFacet, except accepts OrderBitcoin struct instead of Order as order parameter. Expected to be called as a second step when user's Bitcoin is swapped to EVM asset of resolver.

  • sendOrderBitcoinLiqAsset(OrderBitcoin calldata order)

    Works exactly as sendOrderLiqAsset method of OrderSenderFacet, except accepts OrderBitcoin struct instead of Order as order parameter.

  • reportOrderBitcoinNoSend(OrderBitcoin calldata order)

    Works exactly as reportOrderNoSend method of OrderSenderFacet, except accepts OrderBitcoin struct instead of Order as order parameter.

OrderBitcoinSenderNativeFacet

Description

Extension for OrderBitcoinSenderFacet contract that allows resolver or liquidator to send native "to" asset to user.

Interface

IOrderBitcoinSenderNative.sol

Implementation

OrderBitcoinSenderNativeFacet.sol

Dependencies

Write

  • sendOrderBitcoinAssetNative(OrderBitcoin calldata order)

    Works exactly as sendOrderAssetNative method of OrderSenderNativeFacet, except accepts OrderBitcoin struct instead of Order as order parameter.

  • sendOrderBitcoinLiqAssetNative(OrderBitcoin calldata order)

    Works exactly as sendOrderLiqAssetNative method of OrderSenderNativeFacet, except accepts OrderBitcoin struct instead of Order as order parameter.

OrderBitcoinResolverFacet

Description

Extension for OrderResolverFacet that supports collateral resolving for Bitcoin order structure via referenced ICollateralUnlocker and IProofVerifier contracts.

Interface

IOrderBitcoinResolver.sol

Implementation

OrderBitcoinResolverFacet.sol

Dependencies

Write

  • confirmOrderBitcoinAssetSend(OrderBitcoin calldata order, bytes calldata receiveProof, bytes calldata sendProof)

    Works exactly as confirmOrderAssetSend method of OrderResolverFacet, except accepts OrderBitcoin struct instead of Order as order parameter.

  • slashOrderBitcoinLiqCollateral(OrderBitcoin calldata order, address liquidator, bytes calldata receiveProof, bytes calldata liqSendProof)

    Works exactly as slashOrderLiqCollateral method of OrderResolverFacet, except accepts OrderBitcoin struct instead of Order as order parameter.

  • slashOrderBitcoinCollateral(OrderBitcoin calldata order, address reporter, bytes calldata receiveProof, bytes calldata noSendProof)

    Works exactly as slashOrderCollateral method of OrderResolverFacet, except accepts OrderBitcoin struct instead of Order as order parameter.

Read

  • bitcoinResolverCollateralUnlocker() -> ICollateralUnlocker

    Returns address of ICollateralUnlocker-compatible contract that is being used by this OrderBitcoinResolverFacet.

  • bitcoinResolverProofVerifier() -> IProofVerifier

    Returns address of IProofVerifier-compatible contract that is being used by this OrderBitcoinResolverFacet.

MulticallFacet

Description

Provides functionality for calling multiple methods of the main contract in one transaction.

Implementation

MulticallFacet.sol

Write

  • multicall(bytes[] calldata data) -> bytes[] memory

    Performs multiple calls to main contract encoded in data param. If any of the calls reverts, entire multicall method reverts. Returns list of corresponding result data.

TokenPermitterFacet

Description

Provides functionality of converting signed permit to main contract allowance. Usually the permit calls are combined with a primary method the allowance is needed for via multicall.

Interface

ITokenPermitter.sol

Implementation

TokenPermitterFacet.sol

Write

  • permit(address from, address token, uint256 amount, uint256 deadline, bytes32 r, bytes32 vs)

    Adds amount allowance of token to the main contract using default ERC-2612 flow. The r & vs parameters are permit compact signature by from account. Permit verification is performed by the token, and may fail primarily due to nonce mismatch, deadline exceeded, or invalid signature provided.

  • permitDai(address from, address token, bool allowed, uint256 deadline, bytes32 r, bytes32 vs)

    Sets enabled state (allowed) of token to the main contract using legacy DAI token permit implementation flow. The r & vs parameters are permit compact signature by from account. Permit verification is performed by the token, and may fail primarily due to nonce mismatch, deadline exceeded, or invalid signature provided.

  • permitUniswap(address from, address token, uint256 amount, uint256 deadline, bytes calldata signature)

    Adds amount allowance of token to the main contract using permitTransferFrom of Uniswap's Permit2 flow. The signature must be provided by from account. Note that nonce is calculated as hash token, from, amount, deadline, and main contract address, unlike using counters as in other permit flows. Also this flow requires from account to preliminary approve token for the Permit2 contract.

BitStorageFacet

Description

Provides ability to observe presence of hash records in storage of main contract. These records are created for all important contract events with the hash key of record being the first topic of the event.

Interface

IBitStorageFacet.sol

Implementation

BitStorageFacet.sol

Read

  • hasHashStore(bytes32 hash) -> bool

    Returns true if event with hash topic has been emitted in this contract, or false if not, including possibility of "not yet" - the finalization depends on logic of emitting a specific event.

NativeTokenFacet

Description

Provides information on which ERC-20 token is used as native currency wrapper on current chain.

Interface

INativeTokenFacet.sol

Implementation

NativeTokenFacet.sol

Read

  • nativeToken() -> IERC20Native

    Returns address of IERC20Native-compatible token contract that is used for wrapping/unwrapping native currency on current chain.

Development

Stack

This project uses the following stack:

  • Language: Solidity v0.8.24
  • Framework: Hardhat
  • Node.js: v22.2
  • Yarn: v4.5

Solidity runtime dependencies:

  • @openzeppelin/contracts v5.0.2

Setup

Initialize dependencies of the project:

  • yarn install (or yarn)

Build

Build all smart contracts of the project:

  • yarn build (or yarn b)

Test

Run smart contract tests:

  • yarn test (or yarn t)

Note: Automatically performs build step prior the run

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published