Skip to main content
During order fulfillment the DlnDestination smart contract performs standard routine procedures, including checking that the order is still open (neither Fulfilled nor Cancelled) and that the requested amount of tokens were successfully pulled from the solver. Finally, it transfers the requested amount of tokens to the order’s recipient address, OR — if the hook raw data is provided — to the DlnExternalCallAdapter hook engine smart contract address (accessible via DlnDestination.externalCallAdapter), immediately invoking it for hook handling. DlnExternalCallAdapter is responsible for proper hook raw data decoding, hook execution, and guaranties that hook behavior conforms given properties.

Hook data V1 layout

DlnExternalCallAdapter expects the hook raw data (called externalCallEnvelope) to be an concatenation of two encodePacked’d data types, specifically:
  • first byte: uint8 envelopeVersion
  • subsequent bytes: bytes envelopeData
The envelopeVersion determines which data structure was used to encode the envelopeData.

Envelope v1

The envelopeVersion=1 is currently the only available version, and its corresponding structure for the envelopeData is HookDataV1 as follows:
HookDataV1.target defines a target smart contract address that would get called by the DlnExternalCallAdapter hook engine smart. The target smart contract MUST implement the IExternalCallExecutor interface with only two functions: onEtherReceived() and onERC20Received() — that get called (along with order details and the payload) right after the native or ERC-20 token got transferred to it:
For orders buying ERC-20 token, the DlnExternalCallAdapter first transfers the token’s amount to the hook’s target, then invokes its onERC20Received() method:
For orders buying native blockchain currency (ether, etc), the DlnExternalCallAdapter invokes the hook’s target.onEtherReceived() method along with the amount of native currency as a msg.value:

Universal Hook

One the common ways to build cross-chain interactions is to make calls to arbitrary existing contracts, without the need to introduce custom intermediaries (smart contracts that act as hooks). To facilitate this need, we’ve build a default Universal Hook — a pre-deployed implementation of the IExternalCallExecutor and a part of the DLN deployment — that can act as a hook’s target and is designed to transparently execute arbitrary transaction calls bypassed through its targetPayload. To reuse this hook, HookDataV1’s target must be set to address(0) (this would tell the DlnExternalCallAdapter hook engine to switch to the universal hook as a default hook implementation), and HookDataV1’s targetPayload must represent the following encoded data struct:
When called, the universal hook would makes a CALL to the given to address using the given callData. The transfer of native blockchain currency is performed during the call itself:
Mind that ERC-20 token transfer during transaction call made by the Universal hook behaves differently: the universal hook does not transfer the token to the to address (like the DlnExternalCallAdapter does when calling a hook’s target), but sets a temporary allowance instead before making a call, and reverts it back after the call:
If the payload.to had pulled less amount than the order’s outcome, the remainder is transferred to the given fallback address automatically. If the call to the payload.to target gets reverted, the execution bubbles up to the DlnExternalCallAdapter hook engine who handles this failure according to the hook’s properties (revert entire call if the hook is a success-required hook; gracefully ignore the failure if the hook is a success-optional hook).