Flash is a cross-chain asset swap system based on contracts presented in this project.
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.
Flash supports multiple order structure types:
Order
- order for swapping one EVM asset to another EVM assetOrderBitcoin
- order for swapping EVM asset to Bitcoin
Order that allows user to swap one EVM asset to another EVM asset with resolver.
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:
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" assetfromActorReceiver
(address
) - user address that will receive "to" asset from resolverfromChain
(uint256
) - EVM chain ID (i.e.block.chainid
) where "from" asset isfromToken
(address
) - ERC-20 token address of the "from" assetfromAmount
(uint256
) - amount of the "from" asset user is giving to resolvertoActor
(address
) - resolver address that will send "to" asset to user and receive "from" assettoChain
(uint256
) - EVM chain ID where "to" asset istoToken
(address
) - ERC-20 token address of the "to" assettoAmount
(uint256
) - amount of the "to" asset resolver is giving to usercollateralReceiver
(address
) - user address that will receive "collateral" asset from resolver in case of slashcollateralChain
(uint256
) - EVM chain ID where "collateral" asset iscollateralAmount
(uint256
) - amount of the "collateral" asset allocated for the swapcollateralRewardable
(uint256
) - amount of the "collateral" asset that is allowed to be used fromcollateralAmount
amount as reward for "no-send" report liquidator. Logically expected to be significantly less thancollateralAmount
, 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 ordertimeToSend
(uint256
) - time in seconds that is added todeadline
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 liquidatortimeToLiqSend
(uint256
) - time in seconds that is added todeadline
andtimeToSend
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 usernonce
(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)
Order that allows user to swap their EVM asset to Bitcoin with resolver or vise versa.
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 assettoChain
,toToken
,toAmount
- when Bitcoin is sent by resolver in exchange for user's EVM assetcollateralAmount
,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 atcreatedAtBitcoin
timetimeToLiqSend
- unused, since send by liquidator is not supported on Bitcoin chain. Preferred to be0
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 usertoActorBitcoin
- Bitcoin address of the resolver (toActor
). WhenfromActorBitcoin
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 allowedtoActorBitcoin
- 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 ofOrder
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 usingOrderBitcoin
-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:
OrderBitcoinReserverFacet
OrderBitcoinReceiverFacet
OrderBitcoinSenderFacet
OrderBitcoinSenderNativeFacet
OrderBitcoinResolverFacet
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 resolvertoActorBitcoin
(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
ortimeToSend
is added depending on order directiontimeToReceiveBitcoin
(uint256
) - specifies deadline to receive Bitcoin, i.e. time for user to send Bitcoin to specified resolver addresstimeToSubmitBitcoin
(uint256
) - specifies time to submit Bitcoin transaction by user after the receive phase, i.e. total time to submit the Bitcoin receive iscreatedAtBitcoin
+timeToReceiveBitcoin
+timeToSubmitBitcoin
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
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
Implementation
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 inorder
. Cannot be called afterdeadline
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'scollateralAmount
&collateralUnlocked
fields. When execution is successful, emits theAssetReceive
event with first topic being the order hash, which allows to proof "from" asset receive for the order. Receive is marked as performed fororder
in storage (readable viaorderAssetReceived
view) and the method cannot be called again with it.Errors:
OrderReceiveExpired
- receive deadline specified by order exceededReceiveChainMismatch
- receive called on chain that differs from order's "from" chainReceiveCallerMismatch
- receive called by account that differs from order's "to" actorOrderAlreadyReceived
- receive operation has already been called for the orderInvalidSignature
- restored signer of the order signature mismatch the "from" actorUnauthorizedLockAccess
- "to" actor hasn't approved collateral locker contract on current chainLockRefusal
- 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
ifreceiveOrderAsset
method has been successfully called for order with hash specified byorderHash
parameter, orfalse
otherwise. -
receiverCollateralLocker()
->ICollateralLocker
Returns address of
ICollateralLocker
-compatible contract that is being used by thisOrderReceiverFacet
.
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
Implementation
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'sdeadline
+timeToSend
. When succeeds, theAssetSend
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 fororder
in storage (readable viaorderAssetSent
view) and the method cannot be called again with it (along with other send methods).Errors:
OrderSendExpired
- send deadline specified by order exceededSendChainMismatch
- send called on chain that differs from order's "to" chainSendCallerMismatch
- send called by account that differs from order's "to" actorOrderAlreadySent
- 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'sdeadline
+timeToSend
+timeToLiqSend
andsendOrderAsset
has not been called by resolver. When succeeds, theAssetLiqSend
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 fororder
in storage (readable viaorderAssetSent
view) and the method cannot be called again with it.Errors:
OrderLiqSendExpired
- liquidation send deadline specified by order exceededOrderLiqSendUnreached
- send deadline specified by order is not exceeded yetSendChainMismatch
- liquidation send called on chain that differs from order's "to" chainOrderAlreadySent
- 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
norsendOrderLiqAsset
has been called. When succeeds, theAssetNoSend
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 yetSendChainMismatch
- no-send report called on chain that differs from order's "to" chainOrderAlreadySent
- send (or its liquidation variant) operation has already been called for the order.
Read
-
orderAssetSent(bytes32 orderHash)
->bool
Returns
true
ifsendOrderAsset
orsendOrderLiqAsset
method has been successfully called for order with hash specified byorderHash
parameter, orfalse
otherwise. -
orderLiquidator(bytes32 orderHash)
->address
Returns address of
sendOrderLiqAsset
caller, i.e. liquidator. Zero address is returned ifsendOrderLiqAsset
has not been called. Note that this value may only change whileorderAssetSent
view returnsfalse
and order liquidation send call deadline (i.e.deadline
+timeToSend
+timeToLiqSend
andsendOrderAsset
) is not reached.
Description
Extension for OrderSenderFacet
contract that allows resolver or
liquidator to send native "to" asset to user.
Interface
Implementation
Dependencies
Write
-
sendOrderAssetNative(Order calldata order)
Works in the same way as
sendOrderAsset
method ofOrderSenderFacet
, 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 vianativeToken
view method ofNativeTokenFacet
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 ofOrderSenderFacet
, 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 vianativeToken
view method ofNativeTokenFacet
dependency.Errors:
OrderSendNotNative
- "to" asset address specified in order is not set to special constant reserved for native
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
Implementation
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 releasescollateralAmount
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
ofAssetReceive
event on "from" chain andsendProof
ofAssetSend
event on "to" chain. Marks order resolution in storage (readable viaorderResolved
view). EmitsOrderSendConfirm(bytes32 orderHash)
event on success for informational purposes.Errors:
CollateralChainMismatch
- confirm called on chain that differs from order's "collateral" chainOrderAlreadyResolved
- confirm called for order that has already been resolvedUnauthorizedUnlockAccess
- "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 validreceiveProof
ofAssetReceive
event on "from" chain. The hash is then combined withliquidator
address and hashed again - this time expected to be in validliqSendProof
ofAssetLiqSend
event on "to" chain. Full amount (as specified in order) of collateral asset is sent toliquidator
address. Marks order resolution in storage (readable viaorderResolved
view). EmitsOrderCollateralSlash(bytes32 orderHash)
event for informational purposes.Errors:
CollateralChainMismatch
- slash called on chain that differs from order's "collateral" chainOrderAlreadyResolved
- slash called for order that has already been resolvedUnauthorizedUnlockAccess
- "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 validreceiveProof
ofAssetReceive
event on "from" chain. The hash is then combined withreporter
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 validnoSendProof
ofAssetNoSend
event on "to" chain. Full amount (as specified in order) of collateral asset is sent to user address ifreporter
matches their address or no reward specified in the order, alternatively the rewardable share of the collateral is sent to thereporter
. Marks order resolution in storage (readable viaorderResolved
view). EmitsOrderCollateralSlash(bytes32 orderHash)
event for informational purposes.Errors:
CollateralChainMismatch
- slash called on chain that differs from order's "collateral" chainOrderAlreadyResolved
- slash called for order that has already been resolvedUnauthorizedUnlockAccess
- "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 specifiedorderHash
has been resolved, i.e. one ofconfirmOrderAssetSend
,slashOrderLiqCollateral
, orslashOrderCollateral
method has been successfully called for it, orfalse
otherwise. -
resolverCollateralUnlocker()
->ICollateralUnlocker
Returns address of
ICollateralUnlocker
-compatible contract that is being used by thisOrderResolverFacet
. -
resolverProofVerifier()
->IProofVerifier
Returns address of
IProofVerifier
-compatible contract that is being used by thisOrderResolverFacet
.
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
Implementation
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 oncollateralChain
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 viaorderBitcoinCollateralState
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 withdeadline
field of the order. Note that resolver can unlock the collateral if user didn't send Bitcoin (or it was not reported) withunlockOrderBitcoinCollateral
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 viabitcoinAddressUsedOrder
view. EmitsBitcoinCollateralLock(bytes32 orderHash)
event on success for informational purposes.Errors:
BitcoinLockExpired
- lock deadline specified by order exceededBitcoinLockChainMismatch
- lock called on chain that is not the "collateral" one specified in the orderBitcoinLockerMismatch
- 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 infromActorBitcoin
fieldUnauthorizedLockAccess
- "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 bylockOrderBitcoinCollateral
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 ascreatedAtBitcoin
+timeToReceiveBitcoin
(and additionaltimeToSubmitBitcoin
time for safety) which is verified by checkingnoReceiveProof
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 inorderBitcoinCollateralState
view. Re-locking for order from "unlocked" state is not possible. EmitsBitcoinCollateralUnlock(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 toLocked
due to lock call by resolverLocked
- collateral is locked for order, may change toUnlocked
by resolver if they can proof there was no Bitcoin transaction by user, otherwise can be considered terminal stateUnlocked
- collateral was locked and then successfully unlocked for order, terminal state
-
bitcoinAddressUsedOrder(string calldata bitcoinAddress)
->bytes32
Returns order hash that
bitcoinAddress
is used as uniquetoActorBitcoin
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 thisOrderBitcoinReserverFacet
. -
bitcoinReserverProofVerifier()
->IProofVerifier
Returns address of
IProofVerifier
-compatible contract that is being used by thisOrderBitcoinReserverFacet
.
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
Implementation
Dependencies
Write
-
receiveOrderBitcoinAsset(OrderBitcoin calldata order, bytes32 fromSigR, bytes32 fromSigVs)
Works exactly as
receiveOrderAsset
method ofOrderReceiverFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
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 thisOrderBitcoinReceiverFacet
.
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
Implementation
Dependencies
Write
-
sendOrderBitcoinAsset(OrderBitcoin calldata order)
Works exactly as
sendOrderAsset
method ofOrderSenderFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
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 ofOrderSenderFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
parameter. -
reportOrderBitcoinNoSend(OrderBitcoin calldata order)
Works exactly as
reportOrderNoSend
method ofOrderSenderFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
parameter.
Description
Extension for OrderBitcoinSenderFacet
contract that allows
resolver or liquidator to send native "to" asset to user.
Interface
Implementation
OrderBitcoinSenderNativeFacet.sol
Dependencies
Write
-
sendOrderBitcoinAssetNative(OrderBitcoin calldata order)
Works exactly as
sendOrderAssetNative
method ofOrderSenderNativeFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
parameter. -
sendOrderBitcoinLiqAssetNative(OrderBitcoin calldata order)
Works exactly as
sendOrderLiqAssetNative
method ofOrderSenderNativeFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
parameter.
Description
Extension for OrderResolverFacet
that supports collateral
resolving for Bitcoin order structure via referenced
ICollateralUnlocker
and
IProofVerifier
contracts.
Interface
Implementation
Dependencies
Write
-
confirmOrderBitcoinAssetSend(OrderBitcoin calldata order, bytes calldata receiveProof, bytes calldata sendProof)
Works exactly as
confirmOrderAssetSend
method ofOrderResolverFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
parameter. -
slashOrderBitcoinLiqCollateral(OrderBitcoin calldata order, address liquidator, bytes calldata receiveProof, bytes calldata liqSendProof)
Works exactly as
slashOrderLiqCollateral
method ofOrderResolverFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
parameter. -
slashOrderBitcoinCollateral(OrderBitcoin calldata order, address reporter, bytes calldata receiveProof, bytes calldata noSendProof)
Works exactly as
slashOrderCollateral
method ofOrderResolverFacet
, except acceptsOrderBitcoin
struct instead ofOrder
asorder
parameter.
Read
-
bitcoinResolverCollateralUnlocker()
->ICollateralUnlocker
Returns address of
ICollateralUnlocker
-compatible contract that is being used by thisOrderBitcoinResolverFacet
. -
bitcoinResolverProofVerifier()
->IProofVerifier
Returns address of
IProofVerifier
-compatible contract that is being used by thisOrderBitcoinResolverFacet
.
Description
Provides functionality for calling multiple methods of the main contract in one transaction.
Implementation
Write
-
multicall(bytes[] calldata data)
->bytes[] memory
Performs multiple calls to main contract encoded in
data
param. If any of the calls reverts, entiremulticall
method reverts. Returns list of corresponding result data.
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
Implementation
Write
-
permit(address from, address token, uint256 amount, uint256 deadline, bytes32 r, bytes32 vs)
Adds
amount
allowance oftoken
to the main contract using default ERC-2612 flow. Ther
&vs
parameters are permit compact signature byfrom
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
) oftoken
to the main contract using legacy DAI token permit implementation flow. Ther
&vs
parameters are permit compact signature byfrom
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 oftoken
to the main contract usingpermitTransferFrom
of Uniswap's Permit2 flow. Thesignature
must be provided byfrom
account. Note that nonce is calculated as hashtoken
,from
,amount
,deadline
, and main contract address, unlike using counters as in other permit flows. Also this flow requiresfrom
account to preliminary approvetoken
for the Permit2 contract.
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
Implementation
Read
-
hasHashStore(bytes32 hash)
->bool
Returns
true
if event withhash
topic has been emitted in this contract, orfalse
if not, including possibility of "not yet" - the finalization depends on logic of emitting a specific event.
Description
Provides information on which ERC-20 token is used as native currency wrapper on current chain.
Interface
Implementation
Read
-
nativeToken()
->IERC20Native
Returns address of
IERC20Native
-compatible token contract that is used for wrapping/unwrapping native currency on current chain.
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
Initialize dependencies of the project:
yarn install
(oryarn
)
Build all smart contracts of the project:
yarn build
(oryarn b
)
Run smart contract tests:
yarn test
(oryarn t
)
Note: Automatically performs build step prior the run