# Contracts

Derivio uses EIP-2535 Diamonds for a modular contract architecture.

## zkSync Era

<table><thead><tr><th width="261">Contract</th><th>Address</th></tr></thead><tbody><tr><td>Manager Diamond</td><td>0x240D5645bFFAF6f8Bc3586e459A4155F270BCb3b</td></tr><tr><td>Pool Diamond Beacon</td><td>0x104ACF59009759296CD7127B52cFC671d7954222</td></tr><tr><td>Staking Diamond Beacon</td><td>0x878779D32D3FCac4543c5f1EdE6b94b061933c77</td></tr><tr><td>DLPM</td><td>0xfc00dAC251711508D4dD7b0C310e913575988838</td></tr><tr><td>sDLPM</td><td>0x142cF97Ac1a40dFEBCCa488607Ea99D0eABDfe8c</td></tr><tr><td>WETH</td><td>0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91</td></tr></tbody></table>

## Interfaces

### Staking Diamond (sDLPM)

```solidity
interface IStakingRewardsToken {
    struct StakingRewardsConfigPrimitives {
        address assetToken;
        address rewardToken;
        uint256 rewardPeriod;
    }

    struct StakingRewardsStatePrimitives {
        uint256 rewardPerSecond;
        uint256 cumulativeRewardPerToken;
        uint256 lastCumulativeRewardPerTokenUpdate;
        uint256 rewardPeriodEnd;
    }

    struct StakingRewardsAccount {
        uint256 balance;
        uint256 entryCumulativeRewardPerToken;
        uint256 claimableReward;
    }

    /// @notice Get reward token address
    function getRewardToken() external view returns (address);

    /// @notice Get config primitives
    function getStakingRewardsConfigPrimitives()
        external
        view
        returns (StakingRewardsConfigPrimitives memory);

    /// @notice Get state primitives
    function getStakingRewardsStatePrimitives()
        external
        view
        returns (StakingRewardsStatePrimitives memory);

    /// @notice Get account info
    function getStakingRewardsAccount(
        address owner
    ) external view returns (StakingRewardsAccount memory);

    /// @notice Get reward amount claimable by owner
    function previewClaimableReward(
        address owner
    ) external view returns (uint256);

    /// @notice Stake transferred in tokens (assumes token already transferred in)
    function stake(address recipient) external;

    /// @notice Unstake sender's tokens, transfer unstaked tokens to recipient
    /// @dev Untrusted external call
    function unstake(uint256 amount, address recipient) external;

    /// @notice Claim sender's reward, transfer reward to recipient
    /// @dev Untrusted external call
    function claim(address recipient) external returns (uint256 rewardAmount);
}
```

####

### Manager Diamond: Orders

Orders are created by the user (TX 1), then executed by keeper bot (TX 2).

To create an order (TX 1), the user needs to transfer tokens to the contract, then immediately call the create order function. WARNING: Transferring the tokens & order creation must be done in the same TX atomically, otherwise the tokens may be taken by someone else.

To do so, use the multi-delegatecall interface included in the manager diamond:

```solidity
/// @notice Receives and executes a batch of function calls on this contract.
function multicall(
    bytes[] calldata data
) external payable returns (bytes[] memory results);

/// @notice Send ERC20 tokens to the contract. Intended to be used with multicall.
function sendERC20(address token, uint256 amount) external payable;
```

Creating an order requires execution fee in ETH. To get the current minimum execution fee:

```solidity
function getMinExecutionFee() external view returns (uint256);
```

See below for specific order types and examples.

#### Swap Orders

```solidity
struct CreatePoolSwapOrder {
    uint256 executionFee;
    // ---------- DEPOSIT ----------
    address inToken;
    // ---------- SWAP: asset->outToken
    /// Empty = no swap
    address[] swapPoolPath;
    /// Intermediate tokens, length must be 1 less than swapPoolPath
    address[] swapTokenPath;
    /// Min accepted after swap
    uint256 minSwapOut;
    // ---------- WITHDRAW ----------
    address outToken;
    address recipient;
}

/// @notice Create a pool swap order. Assumes tokens already transferred.
function createPoolSwapOrder(
    CreatePoolSwapOrder memory params
) external payable returns (bytes32);
```

Note: If inToken is WETH, directly send raw ETH to the contract. If outToken is WETH, it will be unwrapped and sent to recipient as ETH.

Example usage:

{% code fullWidth="false" %}

```typescript
const executionFee = ManagerDiamond.read.getMinExecutionFee();
const pool = '0xfc00dAC251711508D4dD7b0C310e913575988838';

// Swap ERC20 example
const inToken = '0x....';
const inTokenAmount = 100n;
const outToken = '0x....';
ManagerDiamond.write.multicall([
  [
    encodeFunctionData({
      functionName: 'sendERC20',
      args: [inToken, inTokenAmount],
    }),
    encodeFunctionData({
      functionName: 'createPoolSwapOrder',
      args: [{
        executionFee,
        inToken,
        swapPoolPath: [pool],
        swapTokenPath: [],
        minSwapOut: 0n,
        outToken,
        recipient: '0x....',
      }]
    })
  ]
], { value: executionFee });

// Swap ETH example
const inToken = '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91'; // WETH
const inTokenAmount = 100n;
const outToken = '0x....';
ManagerDiamond.write.multicall([
  [
    encodeFunctionData({
      functionName: 'createPoolSwapOrder',
      args: [{
        executionFee,
        inToken,
        swapPoolPath: [pool],
        swapTokenPath: [],
        minSwapOut: 0n,
        outToken,
        recipient: '0x....',
      }]
    })
  ]
], { value: inTokenAmount + executionFee });
```

{% endcode %}

#### Events

```solidity
event OrderExecuted(bytes32 indexed key, address indexed owner);
event OrderCancelled(bytes32 indexed key, address indexed owner, bytes reason);
event OrderNotExecuted(bytes32 indexed key, address indexed owner, bytes reason);
```
