# Universal Adapter

*This contract provides a single entry-point for atomic swaps, deposits and redemptions.*

### State Variables

#### \_isConfigured

Indicates if the contract was configured.

```solidity
bool internal _isConfigured;
```

#### isPaused

Indicates whether the smart contract is paused or not.

```solidity
bool public isPaused;
```

#### feesCollector

The address of the fees collector.

```solidity
address public feesCollector;
```

#### uniswapRouterAddress

The address of the Uniswap router.

```solidity
address public uniswapRouterAddress;
```

#### vaultReferenceAsset

The reference asset of each whitelisted vault, in the form (vault address => reference asset)

```solidity
mapping(address => address) public vaultReferenceAsset;
```

#### origins

The whitelisted referrers, in the form (origin code => info)

```solidity
mapping(bytes32 => OriginEntry) public origins;
```

#### swapFees

The swap fee of each vault, in the form (vault address => swap fee)

```solidity
mapping(address => uint256) public swapFees;
```

#### whitelistedTokens

The list of whitelisted tokens

```solidity
mapping(address => bool) public whitelistedTokens;
```

#### whitelistedRouters

The list of whitelisted routers for atomic swaps

```solidity
mapping(address => bool) public whitelistedRouters;
```

### Functions

#### constructor

```solidity
constructor();
```

#### ifConfigured

*Throws if the contract was not configured*

```solidity
modifier ifConfigured();
```

#### ifNotConfigured

*Throws if the contract was configured already*

```solidity
modifier ifNotConfigured();
```

#### ifNotPaused

*Throws if the contract is not paused*

```solidity
modifier ifNotPaused();
```

#### ifPaused

*Throws if the contract is paused*

```solidity
modifier ifPaused();
```

#### ifVaultEnabled

*Throws if the vault specified is not enabled*

```solidity
modifier ifVaultEnabled(address vaultAddr);
```

#### configure

Configures the smart contract.

*Throws if the contract was already configured.*

```solidity
function configure(address ownerAddr, address newFeesCollectorAddr) external nonReentrant onlyOwner ifNotConfigured;
```

**Parameters**

| Name                   | Type      | Description                          |
| ---------------------- | --------- | ------------------------------------ |
| `ownerAddr`            | `address` | The new owner of the smart contract. |
| `newFeesCollectorAddr` | `address` | The address of the fees collector.   |

#### setUniswapRouterAddress

Sets the address of the Uniswap router

*Passing the zero address disables the Uniswap router*

```solidity
function setUniswapRouterAddress(address newUniswapRouterAddress)
    external
    nonReentrant
    onlyOwner
    ifConfigured
    ifNotPaused;
```

**Parameters**

| Name                      | Type      | Description                       |
| ------------------------- | --------- | --------------------------------- |
| `newUniswapRouterAddress` | `address` | The address of the Uniswap router |

#### pause

Pauses the smart contract.

```solidity
function pause() external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

#### unPause

Resumes (unpauses) the smart contract.

```solidity
function unPause() external nonReentrant onlyOwner ifConfigured ifPaused;
```

#### discontinue

Discontinues the use of this smart contract.

*The contract is no longer usable after calling this function.*

```solidity
function discontinue() external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

#### enableVaults

Enables the vaults specified.

```solidity
function enableVaults(address[] calldata vaultAddresses, uint256[] calldata newSwapFees)
    external
    nonReentrant
    onlyOwner
    ifConfigured
    ifNotPaused;
```

**Parameters**

| Name             | Type        | Description                            |
| ---------------- | ----------- | -------------------------------------- |
| `vaultAddresses` | `address[]` | The list of vaults to enable.          |
| `newSwapFees`    | `uint256[]` | The swap fee applicable to each vault. |

#### disableVaults

Disables the vaults specified.

```solidity
function disableVaults(address[] calldata vaultAddresses) external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

**Parameters**

| Name             | Type        | Description                    |
| ---------------- | ----------- | ------------------------------ |
| `vaultAddresses` | `address[]` | The list of vaults to disable. |

#### setSwapFee

Sets the swap fee of the vault specified.

```solidity
function setSwapFee(address vaultAddr, uint256 fee) external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

**Parameters**

| Name        | Type      | Description                                                    |
| ----------- | --------- | -------------------------------------------------------------- |
| `vaultAddr` | `address` | The address of the ERC-4626 vault.                             |
| `fee`       | `uint256` | The fee applicable to swaps, expressed in bps. It can be zero. |

#### updateFeesCollector

Updates the address of the fees collector.

```solidity
function updateFeesCollector(address newFeesCollectorAddr) external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

**Parameters**

| Name                   | Type      | Description                            |
| ---------------------- | --------- | -------------------------------------- |
| `newFeesCollectorAddr` | `address` | The address of the new fees collector. |

#### enableSwapInputTokens

Allows the tokens specified to be used during an atomic swap.

*This function prevents the fee collector and origin collectors from receiving unauthorized tokens.*

```solidity
function enableSwapInputTokens(address[] calldata tokenAddresses)
    external
    nonReentrant
    onlyOwner
    ifConfigured
    ifNotPaused;
```

**Parameters**

| Name             | Type        | Description                                                           |
| ---------------- | ----------- | --------------------------------------------------------------------- |
| `tokenAddresses` | `address[]` | The list of tokens to enable. These tokens can be used during a swap. |

#### disableSwapInputTokens

Prevents the tokens specified to be used during an atomic swap.

```solidity
function disableSwapInputTokens(address[] calldata tokenAddresses)
    external
    nonReentrant
    onlyOwner
    ifConfigured
    ifNotPaused;
```

**Parameters**

| Name             | Type        | Description                                                               |
| ---------------- | ----------- | ------------------------------------------------------------------------- |
| `tokenAddresses` | `address[]` | The list of tokens to disable. These tokens cannot be used during a swap. |

#### enableRouter

Enables the router address specified.

*Throws if you pass the address of the Uniswap router.*

```solidity
function enableRouter(address routerAddr) external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

**Parameters**

| Name         | Type      | Description                |
| ------------ | --------- | -------------------------- |
| `routerAddr` | `address` | The address of the router. |

#### disableRouter

Disables the router address specified.

*This function allows you to disable a router.*

```solidity
function disableRouter(address routerAddr) external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

**Parameters**

| Name         | Type      | Description            |
| ------------ | --------- | ---------------------- |
| `routerAddr` | `address` | The router to disable. |

#### addOrigin

Enables a new referrer.

*Reverts if the referrer already exists.*

```solidity
function addOrigin(bytes32 originCode, uint256 originFee, address originFeeCollector)
    external
    nonReentrant
    onlyOwner
    ifConfigured
    ifNotPaused;
```

**Parameters**

| Name                 | Type      | Description                                                      |
| -------------------- | --------- | ---------------------------------------------------------------- |
| `originCode`         | `bytes32` | The code of the referrer.                                        |
| `originFee`          | `uint256` | The fee taken by the referrer, expressed in bps. It can be zero. |
| `originFeeCollector` | `address` | The fee collector of the referrer.                               |

#### updateOrigin

Updates the settings of the referrer specified.

*Reverts if the referrer does not exist.*

```solidity
function updateOrigin(bytes32 originCode, uint256 originFee, address originFeeCollector)
    external
    nonReentrant
    onlyOwner
    ifConfigured
    ifNotPaused;
```

**Parameters**

| Name                 | Type      | Description                                                      |
| -------------------- | --------- | ---------------------------------------------------------------- |
| `originCode`         | `bytes32` | The code of the referrer.                                        |
| `originFee`          | `uint256` | The fee taken by the referrer, expressed in bps. It can be zero. |
| `originFeeCollector` | `address` | The fee collector of the referrer.                               |

#### revokeOrigin

Disables the referrer specified.

```solidity
function revokeOrigin(bytes32 originCode) external nonReentrant onlyOwner ifConfigured ifNotPaused;
```

**Parameters**

| Name         | Type      | Description               |
| ------------ | --------- | ------------------------- |
| `originCode` | `bytes32` | The code of the referrer. |

#### swapAndDeposit

Swaps the tokens specified via Uniswap V3 and deposits the resulting outcome in a given vault.

*This overload runs the swap via Uniswap V3.*

```solidity
function swapAndDeposit(bytes32 originCode, address vaultAddr, address receiverAddr, SingleHopItem[] calldata swaps)
    external
    nonReentrant
    ifConfigured
    ifNotPaused
    returns (uint256 shares, uint256 swapAmountOut);
```

**Parameters**

| Name           | Type              | Description                                                                         |
| -------------- | ----------------- | ----------------------------------------------------------------------------------- |
| `originCode`   | `bytes32`         | The code of the referrer, if any. Pass zero bytes32 if there is no referrer at all. |
| `vaultAddr`    | `address`         | The address of the ERC-4626 vault.                                                  |
| `receiverAddr` | `address`         | The address of the receiver. This address receives the LP tokens.                   |
| `swaps`        | `SingleHopItem[]` | The list of atomic swaps to perform.                                                |

**Returns**

| Name            | Type      | Description                                                                                               |
| --------------- | --------- | --------------------------------------------------------------------------------------------------------- |
| `shares`        | `uint256` | The number of shares acquired.                                                                            |
| `swapAmountOut` | `uint256` | The amount of reference assets swapped via Uniswap V3. Any applicable fees are deducted from this amount. |

#### swapAndDeposit

Swaps the tokens specified through a whitelisted router and deposits the resulting outcome in a given vault.

*This overload runs the swap through an abstract call.*

```solidity
function swapAndDeposit(
    bytes32 originCode,
    address vaultAddr,
    address receiverAddr,
    address tokenApprovalAddr,
    address routerAddr,
    OffchainSwapInfo[] calldata items
) external nonReentrant ifConfigured ifNotPaused returns (uint256 shares, uint256 swapAmountOut);
```

**Parameters**

| Name                | Type                 | Description                                                                         |
| ------------------- | -------------------- | ----------------------------------------------------------------------------------- |
| `originCode`        | `bytes32`            | The code of the referrer, if any. Pass zero bytes32 if there is no referrer at all. |
| `vaultAddr`         | `address`            | The address of the ERC-4626 vault.                                                  |
| `receiverAddr`      | `address`            | The address of the receiver. This address receives the LP tokens.                   |
| `tokenApprovalAddr` | `address`            | The address of the token approver.                                                  |
| `routerAddr`        | `address`            | The address of the router capable of running the atomic swap.                       |
| `items`             | `OffchainSwapInfo[]` | The swaps to perform.                                                               |

**Returns**

| Name            | Type      | Description                                                                                                                     |
| --------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `shares`        | `uint256` | The number of shares acquired.                                                                                                  |
| `swapAmountOut` | `uint256` | The amount of reference assets swapped through the abstract calls specified. Any applicable fees are deducted from this amount. |

#### deposit

Deposits the reference asset in the vault specified.

*Origin fees may apply, depending on the origin. The swap fee is not applicable.*

```solidity
function deposit(bytes32 originCode, uint256 depositAmount, address vaultAddr, address receiverAddr)
    external
    nonReentrant
    ifConfigured
    ifNotPaused
    returns (uint256 shares);
```

**Parameters**

| Name            | Type      | Description                                                                         |
| --------------- | --------- | ----------------------------------------------------------------------------------- |
| `originCode`    | `bytes32` | The code of the referrer, if any. Pass zero bytes32 if there is no referrer at all. |
| `depositAmount` | `uint256` | The deposit amount.                                                                 |
| `vaultAddr`     | `address` | The address of the ERC-4626 vault.                                                  |
| `receiverAddr`  | `address` | The address of the receiver. This address receives the LP tokens.                   |

**Returns**

| Name     | Type      | Description                    |
| -------- | --------- | ------------------------------ |
| `shares` | `uint256` | The number of shares acquired. |

#### requestRedeem

Requests a redemption from the vault specified.

```solidity
function requestRedeem(uint256 shares, address receiverAddr, address holderAddr, address vaultAddr, bytes32 originCode)
    external
    nonReentrant
    ifConfigured
    ifNotPaused
    ifVaultEnabled(vaultAddr)
    returns (uint256 assets, uint256 claimableEpoch);
```

**Parameters**

| Name           | Type      | Description                                                                         |
| -------------- | --------- | ----------------------------------------------------------------------------------- |
| `shares`       | `uint256` | The number of shares to redeem.                                                     |
| `receiverAddr` | `address` | The address of the receiver.                                                        |
| `holderAddr`   | `address` | The address of the tokens holder.                                                   |
| `vaultAddr`    | `address` | The address of the ERC-4626 vault.                                                  |
| `originCode`   | `bytes32` | The code of the referrer, if any. Pass zero bytes32 if there is no referrer at all. |

**Returns**

| Name             | Type      | Description                                                                       |
| ---------------- | --------- | --------------------------------------------------------------------------------- |
| `assets`         | `uint256` | The amount of assets that can be claimed for this specific withdrawal request.    |
| `claimableEpoch` | `uint256` | The date at which the assets become claimable. This is expressed as a Unix epoch. |

#### claim

Allows any public address to process the scheduled withdrawal requests of the receiver specified.

*Throws if the receiving address is not the legitimate address you registered via "requestRedeem()"*

```solidity
function claim(uint256 year, uint256 month, uint256 day, address receiverAddr, address vaultAddr, bytes32 originCode)
    external
    nonReentrant
    ifConfigured
    ifNotPaused
    ifVaultEnabled(vaultAddr)
    returns (uint256 shares, uint256 assets);
```

**Parameters**

| Name           | Type      | Description                                                                         |
| -------------- | --------- | ----------------------------------------------------------------------------------- |
| `year`         | `uint256` | The year component of the claim. It can be a past date.                             |
| `month`        | `uint256` | The month component of the claim. It can be a past date.                            |
| `day`          | `uint256` | The day component of the claim. It can be a past date.                              |
| `receiverAddr` | `address` | The address of the legitimate receiver of the funds.                                |
| `vaultAddr`    | `address` | The address of the ERC-4626 vault.                                                  |
| `originCode`   | `bytes32` | The code of the referrer, if any. Pass zero bytes32 if there is no referrer at all. |

**Returns**

| Name     | Type      | Description                                                                            |
| -------- | --------- | -------------------------------------------------------------------------------------- |
| `shares` | `uint256` | uint256 The effective number of shares (LP tokens) that were burnt from the vault.     |
| `assets` | `uint256` | uint256 The effective amount of reference assets that were transfered to the receiver. |

#### instantRedeem

Redeems the number of shares specified, instantly.

```solidity
function instantRedeem(uint256 shares, address receiverAddr, address vaultAddr, bytes32 originCode)
    external
    nonReentrant
    ifConfigured
    ifNotPaused
    ifVaultEnabled(vaultAddr);
```

**Parameters**

| Name           | Type      | Description                                                                         |
| -------------- | --------- | ----------------------------------------------------------------------------------- |
| `shares`       | `uint256` | The number of shares to redeem.                                                     |
| `receiverAddr` | `address` | The address of the receiver.                                                        |
| `vaultAddr`    | `address` | The address of the ERC-4626 vault.                                                  |
| `originCode`   | `bytes32` | The code of the referrer, if any. Pass zero bytes32 if there is no referrer at all. |

#### getOrigin

Gets the details of the referrer specified.

```solidity
function getOrigin(bytes32 originCode) external view returns (uint256 originFee, address originFeeCollector);
```

**Parameters**

| Name         | Type      | Description               |
| ------------ | --------- | ------------------------- |
| `originCode` | `bytes32` | The code of the referrer. |

**Returns**

| Name                 | Type      | Description                                      |
| -------------------- | --------- | ------------------------------------------------ |
| `originFee`          | `uint256` | The fee taken by the referrer, expressed in bps. |
| `originFeeCollector` | `address` | The fee collector of the referrer.               |

#### \_deposit

*Applies origin fees and deposits the reference asset in the vault*

```solidity
function _deposit(
    bytes32 originCode,
    uint256 depositAmount,
    address vaultAddr,
    address underlyingAssetAddr,
    address receiverAddr
) private returns (uint256 shares);
```

#### \_applyOriginFees

*Applies origin fees. The fee is applied if -and only if- the origin code is valid.*

```solidity
function _applyOriginFees(uint256 consumableAmount, bytes32 originCode, address vaultAddr, address underlyingAssetAddr)
    private
    returns (uint256 newBalance);
```

#### \_applySwapFees

*Applies the respective swap fee*

```solidity
function _applySwapFees(uint256 consumableAmount, address underlyingAssetAddr, address vaultAddr)
    private
    returns (uint256 newBalance);
```

#### \_swapViaUniswapV3

*Runs a swap via Uniswap V3*

```solidity
function _swapViaUniswapV3(SingleHopItem[] calldata items, address underlyingAssetAddr) private;
```

#### \_swapViaOffchainCall

*Runs a swap based on the off-chain quote specified*

```solidity
function _swapViaOffchainCall(
    address underlyingAssetAddr,
    address tokenApprovalAddr,
    address routerAddr,
    OffchainSwapInfo[] calldata items
) private;
```

### Events

#### ContractPaused

```solidity
event ContractPaused();
```

#### ContractResumed

```solidity
event ContractResumed();
```

#### ContractDiscontinued

```solidity
event ContractDiscontinued();
```

#### ContractConfigured

```solidity
event ContractConfigured();
```

#### TokenEnabled

```solidity
event TokenEnabled(address indexed tokenAddr);
```

#### TokenDisabled

```solidity
event TokenDisabled(address indexed tokenAddr);
```

#### VaultEnabled

```solidity
event VaultEnabled(address indexed vaultAddr, uint256 newSwapFee);
```

#### VaultDisabled

```solidity
event VaultDisabled(address indexed vaultAddr);
```

#### FeesCollectorUpdated

```solidity
event FeesCollectorUpdated(address newFeesCollectorAddr);
```

#### SwapFeeUpdated

```solidity
event SwapFeeUpdated(address indexed vaultAddr, uint256 fee);
```

#### SwapFeeApplied

```solidity
event SwapFeeApplied(
    address indexed vaultAddr, address indexed referenceAssetAddr, uint256 consumableAmount, uint256 feeAmount
);
```

#### Deposit

```solidity
event Deposit(
    address indexed vaultAddr,
    address referenceAssetAddr,
    uint256 effectiveDepositAmount,
    uint256 shares,
    bytes32 originCode
);
```

#### OriginFeeApplied

```solidity
event OriginFeeApplied(
    address indexed vaultAddr,
    address indexed referenceAssetAddr,
    uint256 consumableAmount,
    uint256 feeAmount,
    bytes32 indexed originCode
);
```

#### RedemptionRequested

```solidity
event RedemptionRequested(
    uint256 shares,
    address receiverAddr,
    address holderAddr,
    address indexed vaultAddr,
    bytes32 indexed originCode,
    uint256 assets,
    uint256 claimableEpoch
);
```

#### RedemptionClaimed

```solidity
event RedemptionClaimed(
    uint256 year,
    uint256 month,
    uint256 day,
    address receiverAddr,
    address indexed vaultAddr,
    bytes32 indexed originCode,
    uint256 shares,
    uint256 assets
);
```

#### InstantRedeption

```solidity
event InstantRedeption(uint256 shares, address receiverAddr, address indexed vaultAddr, bytes32 indexed originCode);
```

#### OriginAdded

```solidity
event OriginAdded(bytes32 indexed originCode, uint256 originFee, address originFeeCollector);
```

#### OriginUpdated

```solidity
event OriginUpdated(bytes32 indexed originCode, uint256 originFee, address originFeeCollector);
```

#### OriginRevoked

```solidity
event OriginRevoked(bytes32 indexed originCode);
```

### Errors

#### InvalidOrigin

```solidity
error InvalidOrigin();
```

#### OriginAlreadyExists

```solidity
error OriginAlreadyExists();
```

#### RouterNotSet

```solidity
error RouterNotSet();
```

#### InvalidRouter

```solidity
error InvalidRouter();
```

#### InvalidTokenApprovalAddress

```solidity
error InvalidTokenApprovalAddress();
```

#### InvalidVault

```solidity
error InvalidVault();
```

#### UnsupportedVault

```solidity
error UnsupportedVault();
```

#### InvalidFeeCollector

```solidity
error InvalidFeeCollector();
```

#### FeeCollectorNotSet

```solidity
error FeeCollectorNotSet();
```

#### VaultTokenNotAllowed

```solidity
error VaultTokenNotAllowed();
```

#### InvalidFee

```solidity
error InvalidFee();
```

#### InvalidToken

```solidity
error InvalidToken();
```

#### LengthMismatch

```solidity
error LengthMismatch();
```

#### AddressRequired

```solidity
error AddressRequired();
```

#### ContractIsPaused

```solidity
error ContractIsPaused();
```

#### ContractNotPaused

```solidity
error ContractNotPaused();
```

#### InvalidReceiver

```solidity
error InvalidReceiver();
```

#### SwapFailed

```solidity
error SwapFailed(bytes returnData);
```

#### SwapFailedNoReason

```solidity
error SwapFailedNoReason();
```

#### TokenNotWhitelisted

```solidity
error TokenNotWhitelisted();
```

#### SlippageCheckFailed

```solidity
error SlippageCheckFailed();
```

#### OriginFeeTooHigh

```solidity
error OriginFeeTooHigh();
```

#### SwapFeeTooHigh

```solidity
error SwapFeeTooHigh();
```

#### NotConfigured

```solidity
error NotConfigured();
```

#### AlreadyConfigured

```solidity
error AlreadyConfigured();
```

#### AmountTooLow

```solidity
error AmountTooLow();
```

### Structs

#### OriginEntry

```solidity
struct OriginEntry {
    uint256 originFee;
    address originFeeCollector;
}
```

#### SingleHopItem

```solidity
struct SingleHopItem {
    uint256 amountIn;
    uint256 minAmountOut;
    address tokenIn;
    uint24 fee;
    uint160 sqrtPriceLimitX96;
}
```

#### OffchainSwapInfo

```solidity
struct OffchainSwapInfo {
    uint256 amountIn;
    uint256 minAmountOut;
    address tokenIn;
    bytes payload;
}
```
