# Overview

The first DeFi super dapp. Swap and LP anything across major DeFi protocols from one intuitive interface.

<figure><img src="https://1553670060-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8NDihB2RNfi1LyoblpUf%2Fuploads%2F25SJEGSvEOFe0aisjvsK%2Fsignals-from-the-deep.jpeg?alt=media&amp;token=80a42dcd-4605-4b37-bffb-71b687e53840" alt=""><figcaption><p>Something big is building in the waters of Shell World...</p></figcaption></figure>

Aloha and welcome to the Shell Protocol's developer documentation.

Looking to integrate a protocol or build on Shell Protocol? You've found the right place.

The following pages contain tutorials, guides, and technical documentation for Shell Protocol.

## **Shell Protocol Basics**

Start here to [learn the basics](/start-here/shell-protocol-basics) about Shell Protocol.

## **Quickstart: Deploy a liquidity pool**

Learn how to [build an AMM](/start-here/quickstart-deploy-a-liquidity-pool) on Shell using a testnet. This exercise will show you how to build a primitive on the Ocean using the Proteus AMM engine.

## **Tutorial: Executing a swap with Shell**

Learn how to [execute a basic swap](/start-here/tutorial-executing-swap-with-shell-protocol) on Shell using a testnet. This exercise will show you how to turn a set of user interactions into one atomic transaction using the Ocean.

## **Reference Library**

To explore further, check out [various resources](/start-here/reference-library) like Shell's GitHub, white papers, and other important references including contract addresses.


# Shell Protocol Basics

Shell in a nutShell

## What is Shell Protocol?

Shell Protocol is the first DeFi super dapp. Access as many DeFi protocols as you want, without connecting to a hundred different dapps. Instead, use just one dapp for every protocol (like Beefy, Aave, Uniswap, Curve, Balancer, Pendle, and Aerodrome). Wrong chain? Zap into any protocol from other chains in one click. Best of all, Shell is open source and permissionless—any developer can connect their protocol or build their dapp on the platform.

## Shell is for developers

Shell v3 allows you to compose a variety of DeFi protocols in one atomic transaction, cross chain.

It consists of a set of EVM-based smart contracts that form a base layer for things like building [omni dapps](#what-is-an-omni-dapp) or executing intents.

Shell contracts have been [production-tested and rigorously audited](https://wiki.shellprotocol.io/getting-started/security-and-bounties).

## Why build with Shell?

Using Shell's pre-built DeFi components can reduce development time, saving big on costs.

How? Shell reduces code complexity and streamlines DeFi composability. At its heart this is due to an intent-centric architecture, which is critical for the future of UX. Future-proof your DeFi project with Shell, where everything can natively plug into an intents framework.

## Builders can:

* compose together any set of DeFi components on Shell (think [omni dapps](#what-is-an-omni-dapp))
* connect a DeFi protocol to Shell by building an adapter, and get instant composability with all major DeFi protocols
* create new Shell primitives, aka any new DeFi protocol with custom logic

## **How does Shell compare to existing DEXs and aggregators**?

Shell is not a DEX or an aggregator. Rather, it is a framework for composing any DeFi protocol in one atomic transaction.

While a DEX simply allows users to swap tokens using its own pools, Shell allows users to swap tokens through multiple pools on multiple DEXs.

While an aggregator specializes in optimizing trade routes across multiple pools, Shell's purpose is to standardize integrations between those pools, making it easier to build aggregators.

Unlike DEXs and aggregators, Shell is not limited to just swaps. Instead, Shell is useful for composing any type of action within DeFi: providing and withdrawing liquidity, lending and borrowing, buying and selling NFTs, and so on.

## **What's the innovation?**

Shell's intent-centric smart contracts completely separate accounting (the [Ocean](/deep-dive/the-ocean)) and business logic ([Ocean Primitives](/deep-dive/important-concepts/ocean-primitives)) in an open framework for all DeFi. This is the critical innovation that standardizes integrations for everyone.

Shell is fully composable and can be extended with any kind of logic or component that interacts with fungible or non-fungible tokens. In certain scenarios, it proves to be up to 4 times more gas-efficient than its competitors.

This unique architecture enables powerful omni dapps.

## **What is an omni dapp?**

The simplest and slightly geeky explanation would be **"one dapp to rule them all"**.

An omni dapp is any dapp that can handle and combine multiple interactions with many different protocols without leaving the dapp's interface, or calling external smart contracts directly. Everything is handled within that one app.\
\
For example: **Bob wants to sell his NFT for a certain amount of USDT...**

### In a *mono dapp* world, Bob has to:

1. List his NFT for a price in ETH on OpenSea
2. Once the NFT is sold, he exchanges that ETH for USDC on Uniswap
3. After Bob gets USDC, he exchanges that USDC for USDT on Curve

Bob had to make three steps and go to three different dapps in order to get to the desired outcome. That's a lot of unnecessary time, work, and transactions!

### In an *omni dapp* world, Bob has to:

1. List his NFT for a price in USDT on an omni dapp

And that's all. One transaction.\
\
Everything else mentioned above is handled for him by that one app. In other words, the omni dapp will call all three protocols (OpenSea, Uniswap, and Curve) in order for Bob to ultimately receive his USDT.


# Quickstart: Deploy a liquidity pool

This tutorial will walk you through the example of building a constant product AMM liquidity pool using the two most important Shell Protocol components: the [Ocean](/deep-dive/the-ocean) and [Proteus](/deep-dive/primitives/proteus-amm-engine), Shell's novel AMM primitive. We will do this on Arbitrum Goerli testnet. The process is the same for Arbitrum One, you will just use different contract addresses.

{% hint style="info" %}
You don't need to worry about the inner workings of the Ocean and Proteus for now.
{% endhint %}

## Getting started

Clone the Shell Protocol public repo, `cd` into it and run `npm install`

```
$ git clone https://github.com/Shell-Protocol/Shell-Protocol/tree/main
$ cd Shell-Protocol
$ npm i
```

In the root folder, go to `hardhat.config.js` and add your private key on line 27.

{% hint style="danger" %}
WARNING: Do not just simply paste the private key. Use something like `dot-env` and  environment variables instead. Be sure that you ad the file containing secrets to the `.gitignore`
{% endhint %}

Be sure that your account has enough test tokens on Arbitrum Goerli network. You can use this faucet to fund your account <https://faucet.quicknode.com/arbitrum/goerli>. You can also obtain up to 1000 testnet ERC-20 tokens by calling the `claimTokens` function on the following contract: <https://testnet.arbiscan.io/address/0xEaE5B59499a461887fBf2BF47887e4e4cB91D703#writeContract>

## Creating and deploying pool

A pool deployment script can be found at `scripts/deployPool.js`.\
\
We're going to focus on the main function starting at line 164. You can ignore everything else in this file as it's not relevant for now and will be throughly explained in the later sections.

First thing we have to do is to pass an Ocean contract address in line 171.

```
const ocean = await hre.ethers.getContractAt("Ocean", "OCEAN_ADDRESS_HERE");
```

All contract addresses can be found [here](/start-here/reference-library/contract-addresses).\
\
Ocean is the accounting system that Shell Protocol is using internally. Every interaction that requires moving tokens and updating balances is done by the Ocean. Now that we have an Ocean contract instance it's time to create the pool.\
\
You can see in lines 174 and 175 two constants, `tokenOne` and `wrappedEtherID`. These will be the tokens we will create pool from. On line 174 paste the ERC20 token address you want to create pool with.\
\
`const tokenOne = 'TOKEN_ADDRESS_HERE';`

After you paste the address of your desired token, go to the terminal window and run the following command (make sure you are in the project's root folder):

```
$ npx hardhat run scripts/deployPool.js --network arbitrumGoerli
```

Voila! You have successfully deployed a constant product pool 🥳

Don't forget to [tweet about your accomplishment](https://twitter.com/intent/tweet?text=I%20have%20successfully%20completed%20%22Deploy%20a%20liquidity%20pool%22%20following%20%40ShellProtcol%20dev%20docs%20guide%20and%20leveled%20up%20my%20DeFi%20skills)!


# Tutorial: Executing swap with Shell Protocol

This tutorial will walk you through the example of executing a swap (DAI <> USDC) on Arbitrum Goerli testnet using the two most important Shell Protocol components: the [Ocean](/deep-dive/the-ocean), a unified accounting system, and [Proteus](/deep-dive/primitives/proteus-amm-engine), Shell's novel AMM primitive.

{% hint style="info" %}
You don't need to worry about the inner workings of the Ocean and Proteus for now.
{% endhint %}

## Getting started

{% hint style="info" %}
If you have already completed this steps by following [Quickstart guide](/start-here/quickstart-deploy-a-liquidity-pool) you can skip this section. If not, follow along.
{% endhint %}

Clone the Shell Protocol public repo, `cd` into it and run `npm install`

```
$ git clone https://github.com/Shell-Protocol/Shell-Protocol/tree/main
$ cd Shell-Protocol
$ npm i
```

In the root folder, go to `hardhat.config.js` and add your private key on line 27.

{% hint style="danger" %}
WARNING: Do not just simply paste the private key. Use something like `dot-env` and  environment variables instead. Be sure that you ad the file containing secrets to the `.gitignore`
{% endhint %}

Be sure that your account has enough test tokens on Arbitrum Goerli network. You can use this faucet to fund your account <https://faucet.quicknode.com/arbitrum/goerli>. You can also obtain up to 1000 testnet ERC-20 tokens by calling the `claimTokens` function on the following contract: <https://testnet.arbiscan.io/address/0xEaE5B59499a461887fBf2BF47887e4e4cB91D703#writeContract>

Now go to `scripts` folder and create new file `swap.js`. We will write the whole swap logic inside this file and let the hardhat execute the script.

## Writing the swap script

The first thing we will do is to import hardhat and create an empty `main()` function which will be called upon running `swap.js` by the Hardhat. It's a standard way of writing [Hardhat scripts](https://hardhat.org/hardhat-runner/docs/guides/tasks-and-scripts#writing-hardhat-scripts).

{% code lineNumbers="true" %}

```javascript
const hre = require("hardhat");

async function main() {

}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

{% endcode %}

First thing we will need is an instance of the Ocean smart contract. As Shell Protocol's accounting system, the Ocean is responsible for updating balances and "moving" tokens between the user and the AMM. It's not necessary that you understand how Ocean works for the sake of this tutorial, but if you want to learn more you can start read the [The Ocean page](/start-here/reference-library/contract-addresses#the-ocean) in the deep dive section. Note that reading [Important concepts](/deep-dive/important-concepts) section before that is highly recommended.\
\
So let's create and instance of The Ocean in line 4:

<pre class="language-javascript" data-line-numbers><code class="lang-javascript">const hre = require("hardhat");

async function main() {
<strong>  const ocean = await hre.ethers.getContractAt("Ocean", "OCEAN_ADDRESS_HERE");
</strong>}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
</code></pre>

You should pass the correct Ocean contract address that can be found [here](/start-here/reference-library/contract-addresses).

Congratulations! We just created and instance of the Ocean smart contract. Now we have to pass to that instance a set of instructions (as [Interactions](/deep-dive/the-ocean#interactions)) we want it to execute.\
\
In order to swap 100 DAI for USDC we will need to do the following:

1. Wrap 100 DAI to the Ocean
2. Ask Proteus AMM Engine to calculate how many USDC should we get for 100 DAIs
3. Ask The Ocean to transfer computed amount of USDC to our wallet

Now that we know what to do, we need to determine how to do it.\
\
As we already mentioned, The Ocean executes instructions by passing Ocean Interactions to it in order we want them to be executed. So, in this case we need to pass the following interactions:

1. `WrapErc20` with the DAI token address as an input token and amount set to the 100
2. `ComputeOutputAmount` passing DAI as an input token, 100 as amount and USDC as an output token
3. `UnwrapErc20` to transfer USDC from the Ocean to the specified address

So, the next step is to encode this three interactions and prepare them for execution.\
\
Interactions within the Ocean are uniformly encoded via the `Interaction` struct.

```solidity
struct Interaction {
    bytes32 interactionTypeAndAddress;
    uint256 inputToken;
    uint256 outputToken;
    uint256 specifiedAmount;
    bytes32 metadata;
}
```

That means that we have to create and array of three interaction objects and we will use helper methods for that. Helper methods for creating correct format interaction objects can be found inside `interactions.js` file in the `utils-js` folder. We will need `wrapERC20`, `computeInputAmount` and `unwrapERC20` helper method specifically so let's import them and see how to use them.

{% code lineNumbers="true" fullWidth="true" %}

```javascript
const hre = require("hardhat");
const { ethers } = require("hardhat");
const { wrapERC20, computeInputAmount, unwrapERC20 } = require("../utils-js/interactions");

async function main() {
  const ocean = await hre.ethers.getContractAt("Ocean", "OCEAN_ADDRESS_HERE");

  const interactions = [
    wrapERC20({
      address: "DAI_ADDRESS_HERE",
      amount: 100
    }),
    computeInputAmount({
      address: "DAI_USDC_POOL_ADDRESS_HERE",
      inputToken: "WRAPPED_DAI_OCEAN_ID",
      outputToken: "WRAPPED_USDC_OCEAN_ID",
      specifiedAmount: 100,
      metadata: "0x0000000000000000000000000000000000000000000000000000000000000000"
    }),
    unwrapERC20({
      address: "USDC_ADDRESS_HERE",
      amount: ethers.constants.MaxUint256
    })
  ];
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

{% endcode %}

Now we just have to pass the right values instead of the template strings. DAI contract address on Arbitrum Goerli is [`0xEaE5B59499a461887fBf2BF47887e4e4cB91D703`](https://goerli.arbiscan.io/address/0xEaE5B59499a461887fBf2BF47887e4e4cB91D703) while USDC is at the following address [`0x1f84761D120F2b47E74d201aa7b90B73cCC3312c`](https://goerli.arbiscan.io/address/0x1f84761D120F2b47E74d201aa7b90B73cCC3312c).

Finally, DAI USDC Pool address we need is [`0x785402A418B56fd9a05F60B194B3CeecaB42E78f`](https://goerli.arbiscan.io/address/0x785402A418B56fd9a05F60B194B3CeecaB42E78f). All Proteus pool address can be found in [Contract addresses page](/start-here/reference-library/contract-addresses).

Ok, but what are these `"WRAPPED_DAI_OCEAN_ID"` and `"WRAPPED_USDC_OCEAN_ID"` that we are passing as input and output tokens to the `computeInputAmount` helper function?

Well, as an accounting system Ocean is responsible for handling both tokens from the external ledgers (ERC20, ERC721, ERC1155), i.e. wrapped tokens, and Ocean native tokens. In order to keep the track of everything, every token inside the Ocean has its own ID which we call Ocean ID.\
We won't be going into explaining this concept here as it's not necessary to understand how it works to complete this tutorial, it's throughly explained in the Ocean page under the [Deriving token's Ocean ID](/deep-dive/the-ocean#deriving-tokens-ocean-ids) section.\
\
All we need to know right now is that we have another helper function which we can use to get the correct token id. The helper method name is calculateWrappedTokenId and it's located inside `utils.js` file in the `utils-js` folder.\
\
Let's swap the template strings with the real values:

{% code lineNumbers="true" fullWidth="true" %}

```javascript
const hre = require("hardhat");
const { ethers } = require("hardhat");
const { wrapERC20, computeInputAmount, unwrapERC20 } = require("../utils-js/interactions");
const { calculateWrappedTokenId } = require("../utils-js/utils");

async function main() {
  const ocean = await hre.ethers.getContractAt("Ocean", "OCEAN_ADDRESS_HERE");

  const interactions = [
    wrapERC20({
      address: "0xEaE5B59499a461887fBf2BF47887e4e4cB91D703",
      amount: 100
    }),
    computeInputAmount({
      address: "0x785402A418B56fd9a05F60B194B3CeecaB42E78f",
      inputToken: calculateWrappedTokenId({address: "0xEaE5B59499a461887fBf2BF47887e4e4cB91D703", id: 0}),
      outputToken: calculateWrappedTokenId({address: "0x1f84761D120F2b47E74d201aa7b90B73cCC3312c", id: 0}),
      specifiedAmount: 100,
      metadata: "0x0000000000000000000000000000000000000000000000000000000000000000"
    }),
    unwrapERC20({
      address: "0x1f84761D120F2b47E74d201aa7b90B73cCC3312c",
      amount: ethers.constants.MaxUint256
    })
  ];
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

{% endcode %}

Let's see what we have so far. We have created an instance of the Ocean contract and we have encrypted three interactions we want to execute. All we have to do now is to tell the Ocean to execute them.

We will use another helper function `executeInteractions` defined in `index.js` under the `utils-js` folder. This helper method receives three params: an instance of the Ocean contract, signer and an array of interactons.

```javascript
executeInteractions(ocean, signer, interactions);
```

All this helper method does is it calculates interaction IDs and calls an Ocean contract method `doMultipleInteractions` on the behalf of signer.  \
\
We already have an instance of the Ocean created at line 7 and an array of interactions prepared. We just need a signer. Let's fetch it with the `etherjs` library and place it above the Ocean instance creation on line 7.

{% code lineNumbers="true" fullWidth="true" %}

```javascript
const hre = require("hardhat");
const { ethers } = require("hardhat");
const { wrapERC20, computeInputAmount, unwrapERC20 } = require("../utils-js/interactions");
const { calculateWrappedTokenId } = require("../utils-js/utils");

async function main() {
  const [signer] = await ethers.getSigners();
  const ocean = await hre.ethers.getContractAt("Ocean", "OCEAN_ADDRESS_HERE");

  const interactions = [
    wrapERC20({
      address: "0xEaE5B59499a461887fBf2BF47887e4e4cB91D703",
      amount: 100
    }),
    computeInputAmount({
      address: "0x785402A418B56fd9a05F60B194B3CeecaB42E78f",
      inputToken: calculateWrappedTokenId({address: "0xEaE5B59499a461887fBf2BF47887e4e4cB91D703", id: 0}),
      outputToken: calculateWrappedTokenId({address: "0x1f84761D120F2b47E74d201aa7b90B73cCC3312c", id: 0}),
      specifiedAmount: 100,
      metadata: "0x0000000000000000000000000000000000000000000000000000000000000000"
    }),
    unwrapERC20({
      address: "0x1f84761D120F2b47E74d201aa7b90B73cCC3312c",
      amount: ethers.constants.MaxUint256
    })
  ];
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

{% endcode %}

Only thing we have to do now in order to complete the swap and this tutorial is to call the `executeInteractions`

{% code lineNumbers="true" fullWidth="true" %}

```javascript
const hre = require("hardhat");
const { ethers } = require("hardhat");
const { wrapERC20, computeInputAmount, unwrapERC20 } = require("../utils-js/interactions");
const { calculateWrappedTokenId} = require("../utils-js/utils");
const { executeInteractions } = require("../utils-js");

async function main() {
  const [signer] = await ethers.getSigners()
  const ocean = await hre.ethers.getContractAt("Ocean", "OCEAN_ADDRESS_HERE");

  const interactions = [
    wrapERC20({
      address: "0xEaE5B59499a461887fBf2BF47887e4e4cB91D703",
      amount: transferAmount
    }),
    computeInputAmount({
      address: "0x785402A418B56fd9a05F60B194B3CeecaB42E78f",
      inputToken: calculateWrappedTokenId({address: "0xEaE5B59499a461887fBf2BF47887e4e4cB91D703", id: 0}),
      outputToken: calculateWrappedTokenId({address: "0x1f84761D120F2b47E74d201aa7b90B73cCC3312c", id: 0}),
      specifiedAmount: 100,
      metadata: "0x0000000000000000000000000000000000000000000000000000000000000000"
    }),
    unwrapERC20({
      address: "0x1f84761D120F2b47E74d201aa7b90B73cCC3312c",
      amount: ethers.constants.MaxUint256
    })
  ];

  await executeInteractions({ocean, signer, interactions});
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

{% endcode %}

Congratulations! :partying\_face:\
\
You have successfully completed a swap using Shell Protocol's accounting contract, The Ocean and native AMM engine Proteus.\
\
In this tutorial we tried to explain the complete system form a higher level, using as much abstractions as possible without loosing clarity, while also not going deeper than we need into specifics. In the [deep dive](/deep-dive/important-concepts) section you'll be able to go behind those abstractions and learn the inner workings of every component used in this example.

Since you have successfully completed this tutorial you deserve appreciation.Don't forget to [tweet about your accomplishment](/start-here/tutorial-executing-swap-with-shell-protocol)!


# Reference Library

## Github

[The Ocean + Shell Primitives repo](https://github.com/Shell-Protocol/Shell-Protocol/tree/main)

## Shell Protocol

[Shell Protocol website](https://shellprotocol.io/)

[Shell Protocol app](https://app.shellprotocol.io/trade)

## The Ocean

{% hint style="info" %}
There is an upcoming addendum to the Ocean white paper, to detail modifications in Shell v3 (launched January 2023).
{% endhint %}

Shell v2 [Ocean White Paper](https://shellprotocol.io/static/Ocean_-_Shell_v2_Part_2.pdf) (February 2022), [blog post](https://shellprotocol.io/posts/the-ocean/)

## Proteus AMM Engine

[Paper 3 (November 2022)](https://shell-protocol.notion.site/Proteus-AMM-Engine-Update-3-7f33b7e1561347b696874a8ba02b9782), [blog post](https://shellprotocol.io/posts/shell-launches-proteus-amm-engine/)

[Paper 2 (September 2022)](https://github.com/cowri/Proteus/blob/main/Proteus_white_paper_UPDATED.pdf) \[past iteration]

[Paper 1 (October 2021)](https://shellprotocol.io/static/Proteus_AMM_Engine_-_Shell_v2_Part_1.pdf) \[past iteration], [blog post](https://shellprotocol.io/posts/proteus-amm-engine/)

## **Legacy Resources (Shell v1)**

[Shell v1 White Paper](https://github.com/cowri/shell-solidity-v1/blob/master/Shell_White_Paper_v1.0.pdf) (October 2020)


# Contract addresses

## Protocol governance t**okens**

For information on governance tokens, see [Shell DAO](https://wiki.shellprotocol.io/shell-dao/overview).

`SHELL (Arbitrum):` [`0xe47ba52f326806559c1deC7ddd997F6957d0317D`](https://arbiscan.io/address/0xe47ba52f326806559c1deC7ddd997F6957d0317D)

`SHELL (Ethereum Mainnet):` [`0x8dcaec45365e5ada5676073a07b418c2f538145a`](https://etherscan.io/address/0x8dcaec45365e5ada5676073a07b418c2f538145a#code)

## Shell contracts

### The Ocean

`Ocean:` [`0x96B4f4E401cCD70Ec850C1CF8b405Ad58FD5fB7a`](https://arbiscan.io/address/0x96B4f4E401cCD70Ec850C1CF8b405Ad58FD5fB7a)

### External protocols and adapters

`2CRV Adapter:` [`0x02b4ab3B517371D0BD71D325dbE7dFc0320742e4`](https://arbiscan.io/address/0x02b4ab3B517371D0BD71D325dbE7dFc0320742e4)

[`2CRV Pool`](https://arbitrum.curve.fi/2pool)`:` [`0x7f90122bf0700f9e7e1f688fe926940e8839f353`](https://arbiscan.io/address/0x7f90122bf0700f9e7e1f688fe926940e8839f353)

`wstETH-WETH-BPT Adapter:` [`0xA8Cb454449143912159e066760c1cf3b92415B4A`](https://arbiscan.io/address/0xa8cb454449143912159e066760c1cf3b92415b4a)

[`wstETH-WETH-BPT Pool`](https://app.balancer.fi/#/arbitrum/pool/0x9791d590788598535278552eecd4b211bfc790cb000000000000000000000498)`:` [`0x9791d590788598535278552EEcD4b211bFc790CB`](https://arbiscan.io/address/0x9791d590788598535278552eecd4b211bfc790cb)

### Proteus pools

`SHELL+ETH:` [`0xC32A9fC5665aFFCe85CF043472F718029577F7E0`](https://arbiscan.io/address/0xC32A9fC5665aFFCe85CF043472F718029577F7E0)

## **Shell v2 contracts**

### Proteus pools (still in use)

`DAI+USDC:` [`0x96C7dC9d473e621a1e3968Cb862803EAEDe21888`](https://arbiscan.io/address/0x96c7dc9d473e621a1e3968cb862803eaede21888)

`USDT+USDC:` [`0x0cb736ea2AD425221c368407CAAFDD323b7bDc83`](https://arbiscan.io/address/0x0cb736ea2AD425221c368407CAAFDD323b7bDc83)

`Stablepool:` [`0x4f9d367636d5d2056f848803C11872Fdbc2afc47`](https://arbiscan.io/address/0x4f9d367636d5d2056f848803C11872Fdbc2afc47)

`ETH+USD:` [`0xa2dB39e781A5Eee0EAA625dace6F097c17dfF7Ea`](https://arbiscan.io/address/0xa2dB39e781A5Eee0EAA625dace6F097c17dfF7Ea)

`WBTC+USD:` [`0x3402D87DF0817b2A96b210b8873d33dD979C8D19`](https://arbiscan.io/address/0x3402D87DF0817b2A96b210b8873d33dD979C8D19)

`wstETH+ETH:` [`0x2EaB95A938d1fAbb1b62132bDB0C5A2405a57887`](https://arbiscan.io/address/0x3402D87DF0817b2A96b210b8873d33dD979C8D19)

`ARB+ETH:` [`0xA16F40437213020A167c230E4667ff8f13640f75`](https://arbiscan.io/address/0xA16F40437213020A167c230E4667ff8f13640f75)

`TOUCOIN+ETH:` [`0x81F6F6664E8Ece1E81bc9097084373c1dDDb8Daa`](https://arbiscan.io/address/0x81F6F6664E8Ece1E81bc9097084373c1dDDb8Daa)

`MAGIC+ETH:` [`0x0699645f2fd448398272ae07f82eee8d0388de1c`](https://arbiscan.io/address/0x0699645f2fd448398272ae07f82eee8d0388de1c)

`Smolpool:` [`0x6896177ee52659f22a87b180e8fcb2c850a7427e`](https://arbiscan.io/address/0x6896177ee52659f22a87b180e8fcb2c850a7427e)

`REUNI+ETH:` [`0x3917c74FDeC42071E29461c849bceB81cBC3059c`](https://arbiscan.io/address/0x3917c74FDeC42071E29461c849bceB81cBC3059c)

`STG+ETH:` [`0xe043EB17Cc12C3fD4f5EaC765D0f1b965975F470`](https://arbiscan.io/address/0xe043EB17Cc12C3fD4f5EaC765D0f1b965975F470)

### Other primitives

`Fractionalizer Factory:` [`0x4093ee6cc764e11ce95451f47ddee9d6cc89eed4`](https://arbiscan.io/address/0x4093ee6cc764e11ce95451f47ddee9d6cc89eed4)

### **Old Ocean (Legacy)**

`Old Ocean:`[`0xC32eB36f886F638fffD836DF44C124074cFe3584`](https://arbiscan.io/address/0xc32eb36f886f638fffd836df44c124074cfe3584)

***

## **Testnet contracts (Arbitrum** Sepolia Network)

### The Ocean

`Ocean:` [`0xe5Eb94CEaDEB1A87656b7FB57Cf22D01c1B3229d`](https://sepolia.arbiscan.io/address/0xe5Eb94CEaDEB1A87656b7FB57Cf22D01c1B3229d)

### Shell token

`SHELL:` [`0xcf17664006851A27d5Bd93d497f30853AC558792`](https://sepolia.arbiscan.io/address/0xcf17664006851A27d5Bd93d497f30853AC558792)

### Proteus pools

`DAI+USDC:` [`0xEaE5B59499a461887fBf2BF47887e4e4cB91D703`](https://sepolia.arbiscan.io/address/0xEaE5B59499a461887fBf2BF47887e4e4cB91D703)

`USDT+USDC:` [`0xE290A897504313b46a1198Bd9b25b58E503842f7`](https://sepolia.arbiscan.io/address/0xE290A897504313b46a1198Bd9b25b58E503842f7)

`Stablepool:` [`0x1c78820bE30c6013F5eaC98b3DdFbb3431e1Ad29`](https://sepolia.arbiscan.io/address/0x1c78820bE30c6013F5eaC98b3DdFbb3431e1Ad29)

`ETH+USD:` [`0xe6401F6F9e6391eee7ad5a2527Ef730070f743FA`](https://sepolia.arbiscan.io/address/0xe6401F6F9e6391eee7ad5a2527Ef730070f743FA)

## v2 Testnet contracts (Arbitrum Goerli)

### The Ocean

`Ocean:`[`0x8178f0844F08543A0Bd4956D892ef462BD7e71C4`](https://testnet.arbiscan.io/address/0x8178f0844F08543A0Bd4956D892ef462BD7e71C4)

### Other primitives

`Fractionalizer Factory:` [`0x8E5ae75CD39C95f9074Eb62bE179b779E5F93949`](https://testnet.arbiscan.io/address/0x8e5ae75cd39c95f9074eb62be179b779e5f93949)


# Important concepts

To fully grasp Shell Protocol and its potential, one must understand several foundational concepts upon which the protocol is built. These key concepts are elaborated upon in the subsequent sections:

{% content-ref url="/pages/8pTEOsQRXO24Tf2XR5hY" %}
[Separating accounting logic & business logic](/deep-dive/important-concepts/separating-accounting-logic-and-business-logic)
{% endcontent-ref %}

{% content-ref url="/pages/lLAlZ5Gi5atLAhL3c4qZ" %}
[Ocean Primitives](/deep-dive/important-concepts/ocean-primitives)
{% endcontent-ref %}


# Separating accounting logic & business logic

## Overview

Shell Protocol's unique architecture fully separates the accounting from business logic, thus creating a modular DeFi system.

The [Ocean](/deep-dive/the-ocean) contract acts as Shell Protocol's accounting layer. It manages tasks such as transferring tokens between users and primitives (e.g., liquidity pools), wrapping and unwrapping tokens, and executing interactions. In contrast, the role of a primitive is to compute the numerical results of interactions and relay the results to the Ocean.

## **To illustrate this concept more clearly, consider a simplified example:**

Alice wants to swap DAI for USDC. She provides the Ocean with the details of an interaction, which specifies the input token (`DAI`), the input amount, output token (`USDC`), and the primitive's address (`DAI+USDC` pool).

The Ocean queries the primitive to determine how much `USDC` Alice should receive for the given amount of `DAI`. Subsequently, the Ocean deducts the specified amount of `DAI` from Alice's balance, adds it to the pool balance, and deducts the calculated amount of `USDC` from the pool to credit the Alice's balance.

We won't delve deeper into the intricacies of Ocean here, as it isn't pivotal for understanding the separation of accounting and business logic. For a complete examination of Ocean, refer to its [wiki page](/deep-dive/the-ocean).

## Why separate accounting from business logic in the first place?

This architecture has many advantages, with the most salient being:

* **Generalized Accounting Logic**: By decoupling from business logic, the Ocean's accounting logic can support any DeFi primitive (not just AMMs).
* **Infinite Composability**: This generalization enables limitless composability, unlocking a breadth of potential applications and combinations.
* **Reduced Complexity and Contract Size**: Eliminating repetitive logic, such as the transfer function in primitives, streamlines the system. For a deeper dive, refer to the[ *Insight #1: EVM Token Standards Are Broken*](https://wiki.shellprotocol.io/how-shell-works/the-ocean-accounting-hub#insight-1-evm-token-standards-are-broken) section in our wiki.
* **Gas Efficiency**: When chaining different primitives, it's possible to track intermediate balances (like multiple swaps transitioning from token A to token B) in memory rather than on-chain storage. This approach conserves gas. More on this can be found in the [*Insight #3: Transitory Updates Need Not be Saved to the Blockchain*](https://wiki.shellprotocol.io/how-shell-works/the-ocean-accounting-hub#insight-3-transitory-updates-need-not-be-saved-to-the-blockchain) section of our wiki.


# Ocean Primitives

Ocean Primitives are a type of primitive designed to interact with the Ocean contract. At a minimum, they must implement the `computeOutputAmount` and `computeInputAmount` functions from the `IOceanPrimitive` interface.

Their main role is to compute exchange rates between an input and output token. This can take many forms, depending on the primitive. For instance, in the context of an AMM primitive, the primitive is tasked with determining the swap rate.

Conversely, the Ocean's responsibility lies in updating the relevant balances: of the users, the AMM, and any other associated primitives.


# The Ocean

{% hint style="info" %}
This is a developer's explanation of the Ocean. For a broad introduction, consult the [Ocean wiki page](https://wiki.shellprotocol.io/how-shell-works/the-ocean-accounting-hub). The Shell v2 [Ocean White Paper](https://shellprotocol.io/static/Ocean_-_Shell_v2_Part_2.pdf) is highly recommended as well.
{% endhint %}

{% hint style="info" %}
&#x20;The Ocean implementation can be found in `Ocean.sol` at the [following Shell GitHub link](https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/ocean/Ocean.sol).
{% endhint %}

## What is the Ocean?

The Ocean serves as the bedrock of Shell Protocol. Often referred to as the accounting layer, it functions as a unified accounting system.

Designed with adaptability in mind, Ocean can integrate any kind of primitive, be it AMMs, lending pools, algorithmic stablecoins, NFT markets, or innovative primitives yet to be invented. These primitives are called Ocean Primitives.

## Creating Ocean Primitives

Functioning as an accounting system, the Ocean manages tasks like transferring, wrapping, and unwrapping tokens. While every Ocean Primitive receives queries from the Ocean for computational assessments based on input-output tokens and the type of interaction, only the Ocean directly manages token handling.\
\
In order to create an Ocean primitive smart contract developers must implement `IOceanPrimitive` interface in addition to primitive's internal logic.

```solidity
/// @notice Implementing this allows a primitive to be called by the Ocean's
///  defi framework.
interface IOceanPrimitive {
    function computeOutputAmount(
        uint256 inputToken,
        uint256 outputToken,
        uint256 inputAmount,
        address userAddress,
        bytes32 metadata
    ) external returns (uint256 outputAmount);

    function computeInputAmount(
        uint256 inputToken,
        uint256 outputToken,
        uint256 outputAmount,
        address userAddress,
        bytes32 metadata
    ) external returns (uint256 inputAmount);

    function getTokenSupply(uint256 tokenId)
        external
        view
        returns (uint256 totalSupply);
}

```

The full implementation of this interface can be found here: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/ocean/IOceanPrimitive.sol>

## Ocean implementation details

The Ocean is structured as an ERC-1155 smart contract, allowing it to interface with a multitude of token types, such as ERC-20, ERC-721, and ERC-1155. The architectural approach and execution of the Ocean present a notable advantage over the conventional Sequencer-Adapter and Vault-Router models. These intricacies are elucidated in sections 1.1 to 3.1 of the [Ocean White Paper](https://shellprotocol.io/static/Ocean_-_Shell_v2_Part_2.pdf).

Within the Ocean’s ledger, tokens are categorized as two types:

* **Wrapped Tokens**: Tokens from external ledgers (ERC-20, ERC-721, etc)
* **Native Tokens**: Tokens created by Ocean Primitives.

Each token within the Ocean, regardless of being wrapped or native, has a corresponding Ocean ID, serving as a unique identifier.

### Deriving token's Ocean IDs

{% hint style="info" %}
For an exhaustive understanding of Wrapped and Ocean native tokens and Ocean IDs, refer to sections 3.1 and 3.2 of the [Ocean White Paper](https://shellprotocol.io/static/Ocean_-_Shell_v2_Part_2.pdf).
{% endhint %}

#### Wrapped tokens

For ERC-20 tokens, Ocean IDs are sourced by casting the ERC-20 contract's address to a uint256:

`uint256 oceanID = uint256(uint160(contractAddress));`

For ERC-721 and ERC-1155 tokens, Ocean IDs are derived from a hash of the contract’s address and the token ID:

`uint256 oceanID = uint256(keccak256(abi.encodePacked(contractAddress, tokenID)));`

#### Native tokens

A native token’s Ocean ID is determined when an Ocean Primitive invokes the public function `registerNewToken(uint256, uint256)`. The Ocean ID for native native tokens is derived by a hash combination of the primitive's contract address and a nonce:\
\
`uint256 oceanID = uint256(keccak256(abi.encodePacked(primitiveAddress, nonce)));`

Calling the public function `registerNewToken(unit256, unit256)` by the primitive is done by passing Ocean contract address to the `IOceanToken` interface along with the necessary input data.\
\
You can review the `IOceanToken` interface in [our repo](https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/ocean/OceanERC1155.sol).

```solidity
/**
 * @title Interface for external contracts that issue tokens on the Ocean's
 *  public multitoken ledger
 * @dev Implemented by OceanERC1155.
 */
interface IOceanToken {
    function registerNewTokens(
        uint256 currentNumberOfTokens,
        uint256 numberOfAdditionalTokens
    ) external returns (uint256[] memory);
}
```

A practical demonstration of this function invocation to create an LP token is evident in the `LiquidityPool.sol` smart contract constructor [here](https://github.com/Shell-Protocol/Shell-Protocol/blob/ff4df55ccc3f5e73ec517a193125929f1bf45370/src/proteus/LiquidityPool.sol#L128).

<pre class="language-solidity"><code class="lang-solidity">abstract contract LiquidityPool is IOceanPrimitive {
<strong>    /* ... */
</strong><strong>    constructor(
</strong>        uint256 xToken_,
        uint256 yToken_,
        address ocean_,
        uint256 initialLpTokenSupply_,
        address claimer
    ) {
        claimerOrDeployer = claimer == address(0) ? msg.sender : claimer;
        initialLpTokenSupply = initialLpTokenSupply_;
        ocean = ocean_;
        xToken = xToken_;
        yToken = yToken_;
        uint256[] memory registeredToken = IOceanToken(ocean_)
            .registerNewTokens(0, 1);
        lpTokenId = registeredToken[0];
    }
    /* ... */
}
</code></pre>

For an in-depth look at the `registerNewToken(uint256, uint256)` function's implementation, refer to the `OceanERC1155.sol` file [here](https://github.com/Shell-Protocol/Shell-Protocol/blob/ff4df55ccc3f5e73ec517a193125929f1bf45370/src/ocean/OceanERC1155.sol#L258C1-L258C1). The accompanying comments offer added context.

```solidity
function registerNewTokens(
    uint256 currentNumberOfTokens,
    uint256 numberOfAdditionalTokens
) external override returns (uint256[] memory oceanIds) {
    oceanIds = new uint256[](numberOfAdditionalTokens);
    uint256[] memory nonces = new uint256[](numberOfAdditionalTokens);

    for (uint256 i = 0; i < numberOfAdditionalTokens; ++i) {
        uint256 tokenNonce = currentNumberOfTokens + i;
        uint256 newToken = _calculateOceanId(msg.sender, tokenNonce);
        nonces[i] = tokenNonce;
        oceanIds[i] = newToken;
        tokensToPrimitives[newToken] = msg.sender;
    }
    emit NewTokensRegistered(msg.sender, oceanIds, nonces);
}
```

## Interactions

As the accounting component, the Ocean's primary function is to execute instructions — referred to as interactions — specified by users, Ocean Primitives, or other smart contracts.

{% hint style="danger" %}
Ocean-native primitives mustn't communicate with each other directly. They should relay interactions to the Ocean, which subsequently calls the appropriate primitives for computations.
{% endhint %}

### Interaction types

There are nine distinct interaction types that the Ocean can undertake. These are outlined in the `InteractionType` enum located in the `Interactions.sol` [file](https://github.com/Shell-Protocol/Shell-Protocol/blob/c1e3615130dcbbd307ce72e444290a327f8db69c/src/ocean/Interactions.sol#L86).

```solidity
enum InteractionType {
    WrapErc20,
    UnwrapErc20,
    WrapErc721,
    UnwrapErc721,
    WrapErc1155,
    UnwrapErc1155,
    ComputeInputAmount,
    ComputeOutputAmount,
    UnwrapEther
}
```

The `ComputeInputAmount` and `ComputeOutputAmount` interactions communicate with Ocean Primitives, invoking the respective `computeInputAmount` and `computeOutputAmount` methods that these primitives are mandated to implement (as detailed in the "[Creating Ocean Primitives](#creating-ocean-primitives)" section).\
\
Other interactions within `InteractionType` are intuitive and cater to interactions with external token ledgers.

### Interactions execution

Making a fully modular DeFi system is nothing more than composing Ocean Primitives, and composing these primitives is nothing more than orchestrating multiple interactions.

To execute an interaction or a series of interactions, one should invoke one of two public functions on the Ocean: `doInteraction()` or `doMultipleInteractions()`, accompanied by the necessary parameters.

```solidity
function doInteraction(Interaction calldata interaction)
    external
    override
    nonReentrant
    returns (
        uint256 burnId,
        uint256 burnAmount,
        uint256 mintId,
        uint256 mintAmount
    )
{
    emit OceanTransaction(msg.sender, 1);
    return _doInteraction(interaction, msg.sender);
}

function doMultipleInteractions(
    Interaction[] calldata interactions,
    uint256[] calldata ids
)
    external
    payable
    override
    nonReentrant
    returns (
        uint256[] memory burnIds,
        uint256[] memory burnAmounts,
        uint256[] memory mintIds,
        uint256[] memory mintAmounts
    )
{
    emit OceanTransaction(msg.sender, interactions.length);
    return _doMultipleInteractions(interactions, ids, msg.sender);
}
```

Actual implementation of these functions can be reviewed in the `Ocean.sol` file in our public repo, starting from [lines 246](https://github.com/Shell-Protocol/Shell-Protocol/blob/c1e3615130dcbbd307ce72e444290a327f8db69c/src/ocean/Ocean.sol#L246) and [271](https://github.com/Shell-Protocol/Shell-Protocol/blob/c1e3615130dcbbd307ce72e444290a327f8db69c/src/ocean/Ocean.sol#L271) respectively.

Note that prior to invoking these methods, interactions need to be correctly formatted (encoded).

### Preparing (encoding) interactions for execution

Interactions within the Ocean are uniformly encoded via the `Interaction` struct, encapsulating information for both Ocean Primitives and external ledgers (wrapping and unwrapping tokens).

`Interaction` struct definition can be found in the `Interactions.sol` file in our public repo, starting from the [line 31](https://github.com/Shell-Protocol/Shell-Protocol/blob/c1e3615130dcbbd307ce72e444290a327f8db69c/src/ocean/Interactions.sol#L31).

<pre class="language-solidity"><code class="lang-solidity">struct Interaction {
    bytes32 <a data-footnote-ref href="#user-content-fn-1">interactionTypeAndAddress</a>;
    uint256 inputToken;
    uint256 outputToken;
    uint256 specifiedAmount;
    bytes32 metadata;
}
</code></pre>

Noticed the first field `interactionTypeAndAddress` in the `Interaction` struct?

It's a bytes array that combines both the interaction type and the address of the external contract with which the caller of the `doInteraction()` or `doInteractions()` functions intends the Ocean to query. This combination, or 'packing', of the interaction type with the external contract address is designed to save on gas consumption.

The `interactionType` aids the Ocean in parsing the struct correctly and corresponds to one of the nine potential options highlighted in the '[Interaction Types](#interaction-types)' section.

The final field, `metadata`, is primarily used for ERC-721 and ERC-1155 wraps and unwraps to specify the token ID. Though passed to the primitive by default, it's at the primitive's discretion to utilize this field or ignore it altogether. For example, Proteus primitives use metadata for enforcing slippage protection.

## Balances

Every accountant maintains a balance sheet, and the Ocean is no exception. Functioning as an ERC-1155 contract, the Ocean inherently acts as a ledger. This structure endows the Ocean with potent capabilities, such as tracking state changes in memory, obviating the need for constant storage writing. This feature allows the composing of primitives in the Ocean to be up to three times cheaper than the alternatives.

It's not imperative for a smart contract developer to delve deeply into the Ocean's balance-handling mechanisms, so a detailed explanation is omitted here. For those keen on gaining a more comprehensive understanding of how the Ocean manages balances, it is advisable to consult sections 5.1 to 6 of [the Ocean white paper](https://shellprotocol.io/static/Ocean_-_Shell_v2_Part_2.pdf).

[^1]:


# Primitives

Ocean-native smart contracts

Primitives are an integral part of Shell Protocol's architecture. They are the components that directly connect to Shell's hub contract, the [Ocean](/deep-dive/the-ocean).

First-party [Ocean Primitives](/deep-dive/important-concepts/ocean-primitives) may take many forms and contain unique logic, but all enjoy advantages like reduced code complexity and gas savings.

An important primitive is the adapter. These can make any DeFi protocol or bridge instantly composable with the Shell network. There are many different adapters on Shell, each one tailored to a unique protocol.

Check out the following Ocean Primitives:

1. [Ocean Adapter](/deep-dive/primitives/adapters) - A generalized adapter interface for creating adapter primitives. Adapters can connect external DeFi protocols to Shell.
2. [Proteus](/deep-dive/primitives/proteus-amm-engine) - An AMM engine that can be used to deploy any shape bonding curve, with the ability to evolve over time.
3. [NFT Fractionalizer](/deep-dive/primitives/nft-fractionalizer) - This primitive allows non-fungible tokens (NFTs) to be converted into fungible units, improving asset interoperability within the protocol.

{% hint style="info" %}
If you're working on a new Ocean Primitive, reach out in the Shell [Discord](https://wiki.shellprotocol.io/getting-started/overview/community#discord) to add it here.
{% endhint %}


# Adapters

Ocean adapter primitives

## What is an adapter?

In DeFi, generally speaking, an adapter is any smart contract that integrates unrelated DeFi protocols with each other. The purpose of Ocean adapter smart contracts is to connect Shell with external protocols.

## Ocean Adapters

{% hint style="info" %}
The Ocean Adapter is compatible with Shell v3, which introduced certain changes to the Ocean smart contract.\
\
An Ocean Adapter won't work with older versions of Shell.
{% endhint %}

The Ocean Adapter is a special version of a DeFi Adapter smart contract that is written according to the Ocean specification, i.e. it inherits the special  `abstract contract OceanAdapter` in order to integrate external projects and protocols, and make them compatible with the Ocean.&#x20;

Anyone can write an OceanAdapter, to connect Shell Protocol and any project of the creator's liking. It's completely permissionless!\
\
You can see a few example of the Ocean Adapter in the following links in our repo:

* Curve2PoolAdapter - coming soon
* CurveTricryptoAdapter - coming soon

## Why integrate with the Ocean?

As a fully open source and permissionless protocol, writing an Ocean Adapter is available to anyone. External projects can write their own adapters and integrate with Shell Protocol, getting the best out of its composability and unique architecture.

Integrated projects do not only become compatible with the Shell Protocol, but also with one another.

And last but not least, new protocols that are just starting and may not have big numbers in TVL and other metrics will get to tap into a much bigger user base than they would initially have. Every user on Shell Protocol becomes their user as well.

## Creating an Ocean Adapter

In order to create an Ocean Adapter smart contract, developers must inherit the abstract contract OceanAdapter.sol, passing Ocean contract and Primitive contract addresses (the address for the contract the integration is written for) to its constructor like in the example below:

```solidity
contract Curve2PoolAdapter is OceanAdapter {
    ...
    /**
     * @notice only initializing the immutables, mappings & approves tokens
     */
    constructor(address ocean_, address primitive_) OceanAdapter(ocean_, primitive_) {
        address xTokenAddress = ICurve2Pool(primitive).coins(0);
        xToken = _calculateOceanId(xTokenAddress, 0);
        underlying[xToken] = xTokenAddress;
        decimals[xToken] = IERC20Metadata(xTokenAddress).decimals();
        _approveToken(xTokenAddress);

        address yTokenAddress = ICurve2Pool(primitive).coins(1);
        yToken = _calculateOceanId(yTokenAddress, 0);
        indexOf[yToken] = int128(1);
        underlying[yToken] = yTokenAddress;
        decimals[yToken] = IERC20Metadata(yTokenAddress).decimals();
        _approveToken(yTokenAddress);

        lpTokenId = _calculateOceanId(primitive_, 0);
        underlying[lpTokenId] = primitive_;
        decimals[lpTokenId] = IERC20Metadata(primitive_).decimals();
        _approveToken(primitive_);
    }
    ...
}
```

One requirement that has to be satisfied is implementation of the three methods that were specified, but not implemented by the inherited abstract contract OceanAdapter.sol, and those methods are: `primitiveOutputAmount`, `wrapToken` and `unwrapToken`.

A reference of the actual implementation (which may be different for each Adapter) can be seen in Curve2PoolAdapter example:

```solidity
/**
* @dev wraps the underlying token into the Ocean
* @param tokenId Ocean ID of token to wrap
* @param amount wrap amount
*/
function wrapToken(uint256 tokenId, uint256 amount) internal override {
    address tokenAddress = underlying[tokenId];

    Interaction memory interaction = Interaction({
        interactionTypeAndAddress: _fetchInteractionId(tokenAddress, uint256(InteractionType.WrapErc20)),
        inputToken: 0,
        outputToken: 0,
        specifiedAmount: amount,
        metadata: bytes32(0)
    });

    IOceanInteractions(ocean).doInteraction(interaction);
}

/**
* @dev unwraps the underlying token from the Ocean
* @param tokenId Ocean ID of token to unwrap
* @param amount unwrap amount
*/
function unwrapToken(uint256 tokenId, uint256 amount) internal override returns (uint256 unwrappedAmount) {
    address tokenAddress = underlying[tokenId];

    Interaction memory interaction = Interaction({
        interactionTypeAndAddress: _fetchInteractionId(tokenAddress, uint256(InteractionType.UnwrapErc20)),
        inputToken: 0,
        outputToken: 0,
        specifiedAmount: amount,
        metadata: bytes32(0)
    });

    IOceanInteractions(ocean).doInteraction(interaction);

     // handle the unwrap fee scenario
    uint256 unwrapFee = amount / IOceanInteractions(ocean).unwrapFeeDivisor();
    (, uint256 truncated) = _convertDecimals(NORMALIZED_DECIMALS, decimals[tokenId], amount - unwrapFee);
    unwrapFee = unwrapFee + truncated;

    unwrappedAmount = amount - unwrapFee;
}

/**
* @dev swaps/add liquidity/remove liquidity from Curve 2pool
* @param inputToken The user is giving this token to the pool
* @param outputToken The pool is giving this token to the user
* @param inputAmount The amount of the inputToken the user is giving to the pool
* @param minimumOutputAmount The minimum amount of tokens expected back after the exchange
*/
function primitiveOutputAmount(
    uint256 inputToken,
    uint256 outputToken,
    uint256 inputAmount,
    bytes32 minimumOutputAmount
)
    internal
    override
    returns (uint256 outputAmount)
{
    (uint256 rawInputAmount,) = _convertDecimals(NORMALIZED_DECIMALS, decimals[inputToken], inputAmount);

    ComputeType action = _determineComputeType(inputToken, outputToken);

    uint256 rawOutputAmount;

    // avoid multiple SLOADS
    int128 indexOfInputAmount = indexOf[inputToken];
    int128 indexOfOutputAmount = indexOf[outputToken];

    if (action == ComputeType.Swap) {
        rawOutputAmount =
            ICurve2Pool(primitive).exchange(indexOfInputAmount, indexOfOutputAmount, rawInputAmount, 0);
    } else if (action == ComputeType.Deposit) {
        uint256[2] memory inputAmounts;
        inputAmounts[uint256(int256(indexOfInputAmount))] = rawInputAmount;
        rawOutputAmount = ICurve2Pool(primitive).add_liquidity(inputAmounts, 0);
    } else {
        rawOutputAmount = ICurve2Pool(primitive).remove_liquidity_one_coin(rawInputAmount, indexOfOutputAmount, 0);
    }

    (outputAmount,) = _convertDecimals(decimals[outputToken], NORMALIZED_DECIMALS, rawOutputAmount);

    if (uint256(minimumOutputAmount) > outputAmount) revert SLIPPAGE_LIMIT_EXCEEDED();

    if (action == ComputeType.Swap) {
        emit Swap(inputToken, inputAmount, outputAmount, minimumOutputAmount, primitive, true);
    } else if (action == ComputeType.Deposit) {
        emit Deposit(inputToken, inputAmount, outputAmount, minimumOutputAmount, primitive, true);
    } else {
        emit Withdraw(outputToken, inputAmount, outputAmount, minimumOutputAmount, primitive, true);
    }
}
```

Other than that, smart contract developers are free to add arbitrarily complex logic and custom functionality to their Adapters.

The full implementation of abstract contract `OceanAdapter.sol` can be found here: \[link coming soon].


# Proteus AMM Engine

An Ocean-native AMM primitive

{% hint style="info" %}
This is a developer's guide to building with Proteus. For a complete introduction, check out the [Proteus wiki page](https://wiki.shellprotocol.io/how-shell-works/proteus-amm-engine).
{% endhint %}

## What is Proteus

Proteus is an AMM (Automated Market Maker) engine that is capable of approximating any bonding curve, enhancing Shell Protocol's market-making strategies. It is capable of extremely precise liquidity concentration across multiple price ranges, but still uses fungible LP tokens.

There are two implementations of Proteus: Static Proteus and Evolving Proteus.

## Static Proteus implementation details

It turns out that in order to create any bonding curve and achieve extremely precise liquidity concentration, all you need is 4 parameters: list of slopes of the radial lines in order to create slices, list of values representing relative scale factors of each slice, a list of a values, and a list of b values representing price points of the particular slice.

Those params are labeled as lists of:

1. ms - representing a list of slopes of the radial lines
2. \_as - list of price points of the particular slice
3. bs - list of price points of the particular slice
4. ks - list of values representing relative scale factors of each slice

## Determining ms, \_as, bs and ks values

Determining `ms`, `_as`, `bs` and `ks` values is not an easy task to do. In order to understand them better you may want to spend some time going through the files in `scripts/params` directory of our [public repo](https://github.com/Shell-Protocol/Shell-Protocol/tree/main/scripts/params). You will find examples of different type of pools in that folder, like well known constant product and stablepool.

## Evolving Proteus

Evolving Proteus is an advanced version of the Proteus AMM engine, with which the bonding curve can change every block (or "evolve") during a specified time frame.\
\
Evolving Proteus also differs from Static Proteus in that Evolving Proteus only has one slice. Evolving Proteus is good for liquidity bootstrapping, or any use case that requires a [Dutch auction](https://en.wikipedia.org/wiki/Dutch_auction). It is also good for creating managed pools.

{% hint style="success" %}
For a thorough understanding of Proteus, it is advisable to first read the initial version of the [Proteus White Paper](https://shellprotocol.io/static/Proteus_AMM_Engine_-_Shell_v2_Part_1.pdf), followed by the [updated (second version) White Paper](https://github.com/cowri/Proteus/blob/main/Proteus_white_paper_UPDATED.pdf), and finally, the [Update 3 document](https://shell-protocol.notion.site/Proteus-AMM-Engine-Update-3-7f33b7e1561347b696874a8ba02b9782). The actual implementation of the Ocean can be accessed in our public repository, located within the Proteus.sol file at the [provided link](https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/proteus/Proteus.sol).
{% endhint %}

<br>


# NFT Fractionalizer

An Ocean-native primitive for fractionalizing NFTs

{% hint style="info" %}
This page is dedicated to providing a developer-focused exploration of the NFT Fracitonalizer, one of Shell Protocol's Ocean Primitives built by Cowri Labs. For a more extensive and detailed overview, consider visiting the [NFT Fractionalizer page on Shell Protocol's wiki](https://wiki.shellprotocol.io/how-shell-works/proteus-amm-engine).

The actual implementation of the NFT Fractionalizers for ERC-721 and ERC-1155 can be accessed in our public repository, located within the [`Fractionalizer721.sol`](https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/fractionalizer/Fractionalizer721.sol) and [`Fractionalizer1155.sol`](https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/fractionalizer/Fractionalizer1155.sol) files.
{% endhint %}

## About NFT Fractionalizer

NFT Fractionalizer is a pretty straightforward Ocean Primitive. All it does is turning NFT smart contracts or collections, how ever you wish to call them and turns them into fungible tokens. This give us some interesting new use cases and things we can do that usually not possible with non fungible token types like creating NFT AMMs enabling instant liquidity for the NFT owners.


# Ocean

{% content-ref url="/pages/lrzNgt0zaVB6l5jwPzMr" %}
[Ocean.sol](/smart-contracts-specification/ocean/ocean.sol)
{% endcontent-ref %}

{% content-ref url="/pages/kVcvFavile4VUeU82Cjw" %}
[IOceanPrimitive.sol](/smart-contracts-specification/ocean/ioceanprimitive.sol)
{% endcontent-ref %}

{% content-ref url="/pages/BoWoBKbV0CzHugSnzGuj" %}
[IOceanToken.sol](/smart-contracts-specification/ocean/ioceantoken.sol)
{% endcontent-ref %}

{% content-ref url="/pages/5qilH7ZqwJM3QhRH8FrN" %}
[OceanAdapter.sol](/smart-contracts-specification/ocean/oceanadapter.sol)
{% endcontent-ref %}


# Ocean.sol

Github link: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/ocean/Ocean.sol>

## WRAPPED\_ETHER\_ID()

```solidity
/// @notice this is the oceanId used for shETH
/// @dev hexadecimal(ascii("shETH"))
uint256 public immutable WRAPPED_ETHER_ID;
```

This function is automatically created because `WRAPPED_ETHER_ID` variable is declared as `public`.&#x20;

It should...

1. Return the Ocean ID for Ether (Wrapping Ether into Ocean would result in shETH, so it would be a shETH ID actually).

## unwrapFeeDivisor()

```solidity
/// @notice Used to calculate the unwrap fee
/// unwrapFee = unwrapAmount / unwrapFeeDivisor
/// Because this uses integer division, the fee is always rounded down
/// If unwrapAmount < unwrapFeeDivisor, unwrapFee == 0
uint256 public unwrapFeeDivisor;
```

This function is automatically created because `unwrapFeeDivisor` variable is declared as `public`. A fee is charged by the Ocean on each unwrap.

It should...

1. Return the correct unwrap fee divisor.

## doInteraction()

{% code overflow="wrap" %}

```solidity
/**
* @notice Execute interactions `interaction`
* @notice Does not need ids because a single interaction does not require
*  the accounting system
* @dev MUST HAVE nonReentrant modifier.
* @dev call to _doInteraction() binds msg.sender to userAddress
* @param interaction Executed to produce a set of balance updates
*/
function doInteraction(
    Interaction calldata interaction
) external override nonReentrant returns (
    uint256 burnId,
    uint256 burnAmount,
    uint256 mintId,
    uint256 mintAmount
);
```

{% endcode %}

| Parameter Name | Type               | Description                                                                   |
| -------------- | ------------------ | ----------------------------------------------------------------------------- |
| interaction    | Interaction struct | one of nine different interactions types encoded via the `Interaction` struct |

Interaction Struct Params:

| Parameter Name            | Type    | Description                                                                                                                     |
| ------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| interactionTypeAndAddress | bytes32 | a bytes32 array that combines both the interaction type and the address of the external contract called during this interaction |
| inputToken                | uint256 | input token Ocean ID                                                                                                            |
| outputToken               | uint256 | output token Ocean ID                                                                                                           |
| specifiedAmount           | uint256 | amount of the specified token                                                                                                   |
| metadata                  | bytes32 | bytes32 array of arbitrary data, during 721/1155 and wraps and unwraps we use this filed to pass token ID                       |

This function executes a single interaction.&#x20;

It should...

1. Execute a single forwarded interaction.

## doMultipleInteractions()

{% code overflow="wrap" %}

```solidity
/**
* @notice Execute interactions `interactions` with tokens `ids`
* @notice ids must include all tokens invoked during the transaction
* @notice ids are used for memory allocation in the intra-transaction
*  accounting system.
* @dev MUST HAVE nonReentrant modifier.
* @dev call to _doMultipleInteractions() binds msg.sender to userAddress
* @param interactions Executed to produce a set of balance updates
* @param ids Ocean IDs of the tokens invoked by the interactions.
*/
function doMultipleInteractions(
    Interaction[] calldata interactions,
    uint256[] calldata ids
) external payable override nonReentrant returns (
    uint256[] memory burnIds,
    uint256[] memory burnAmounts,
    uint256[] memory mintIds,
    uint256[] memory mintAmounts
);
```

{% endcode %}

| Parameter Name | Type                  | Description                                                                                                         |
| -------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------- |
| interactions   | Interaction struct\[] | an array of interactions which can be one of nine different interactions types encoded via the `Interaction` struct |
| ids            | uint256\[]            | an array of tokens Ocean IDs used by the interactions forwarded by the interactions param                           |

Interaction Struct Params:

| Parameter Name            | Type    | Description                                                                                                                     |
| ------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| interactionTypeAndAddress | bytes32 | a bytes32 array that combines both the interaction type and the address of the external contract called during this interaction |
| inputToken                | uint256 | input token Ocean ID                                                                                                            |
| outputToken               | uint256 | output token Ocean ID                                                                                                           |
| specifiedAmount           | uint256 | amount of the specified token                                                                                                   |
| metadata                  | bytes32 | bytes32 array of arbitrary data, during 721/1155 and wraps and unwraps we use this filed to pass token ID                       |

This function executes multiple interactions in order they were stacked in the array of interactions. Use this function to compose different interactions, i.e. Ocean native primitives.

It should...

1. Execute a a list of forwarded interactions.

## forwardedDoInteraction()

{% code overflow="wrap" %}

```solidity
/**
* @notice Execute interactions `interactions` on behalf of `userAddress`
* @notice Does not need ids because a single interaction does not require
*  the overhead of the intra-transaction accounting system
* @dev MUST HAVE nonReentrant modifier.
* @dev MUST HAVE onlyApprovedForwarder modifer.
* @dev call to _doMultipleInteractions() forwards the userAddress
* @param interaction Executed to produce a set of balance updates
* @param userAddress interactions are executed on behalf of this address
*/
function forwardedDoInteraction(
    Interaction calldata interaction,
    address userAddress
)
external override nonReentrant onlyApprovedForwarder(userAddress) returns (
    uint256 burnId,
    uint256 burnAmount,
    uint256 mintId,
    uint256 mintAmount
);
```

{% endcode %}

| Parameter Name | Type               | Description                                                                   |
| -------------- | ------------------ | ----------------------------------------------------------------------------- |
| interaction    | Interaction struct | one of nine different interactions types encoded via the `Interaction` struct |
| userAddress    | address            | address on which behalf to  execute interactions                              |

Interaction Struct Params:

<table><thead><tr><th>Parameter Name</th><th width="297.3333333333333">Type</th><th>Description</th></tr></thead><tbody><tr><td>interactionTypeAndAddress</td><td>bytes32</td><td>a bytes32 array that combines both the interaction type and the address of the external contract called during this interaction</td></tr><tr><td>inputToken</td><td>uint256</td><td>input token Ocean ID</td></tr><tr><td>outputToken</td><td>uint256</td><td>output token Ocean ID</td></tr><tr><td>specifiedAmount</td><td>uint256</td><td>amount of the specified token</td></tr><tr><td>metadata</td><td>bytes32</td><td>bytes32 array of arbitrary data, during 721/1155 and wraps and unwraps we use this filed to pass token ID</td></tr></tbody></table>

This function executes a single interaction on behalf the address that was forwarded as `userAddress` param.

It should...

1. Revert if address forwarded as `userAddress` param hasn't approved message sender to pass interactions on its behalf via i`sApprovedForAll` ERC1155 method.
2. Execute a single forwarded interaction.

## forwardedDoMultipleInteractions()

{% code overflow="wrap" %}

```solidity
/**
* @notice Execute interactions `interactions` with tokens `ids` on behalf of `userAddress`
* @notice ids must include all tokens invoked during the transaction
* @notice ids are used for memory allocation in the intra-transaction
*  accounting system.
* @dev MUST HAVE nonReentrant modifier.
* @dev MUST HAVE onlyApprovedForwarder modifer.
* @dev call to _doMultipleInteractions() forwards the userAddress
* @param interactions Executed to produce a set of balance updates
* @param ids Ocean IDs of the tokens invoked by the interactions.
* @param userAddress interactions are executed on behalf of this address
*/
function forwardedDoMultipleInteractions(
    Interaction[] calldata interactions,
    uint256[] calldata ids,
    address userAddress
)
external payable override nonReentrant onlyApprovedForwarder(userAddress) returns (
    uint256[] memory burnIds,
    uint256[] memory burnAmounts,
    uint256[] memory mintIds,
    uint256[] memory mintAmounts
);
```

{% endcode %}

| Parameter Name | Type                  | Description                                                                                                         |
| -------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------- |
| interactions   | Interaction struct\[] | an array of interactions which can be one of nine different interactions types encoded via the `Interaction` struct |
| ids            | unit256\[]            | an array of interaction IDs forwarded by the first param Interaction struct\[]                                      |
| userAddress    | address               | address on which behalf to  execute interactions                                                                    |

Interaction Struct Params:

<table><thead><tr><th>Parameter Name</th><th width="297.3333333333333">Type</th><th>Description</th></tr></thead><tbody><tr><td>interactionTypeAndAddress</td><td>bytes32</td><td>a bytes32 array that combines both the interaction type and the address of the external contract called during this interaction</td></tr><tr><td>inputToken</td><td>uint256</td><td>input token Ocean ID</td></tr><tr><td>outputToken</td><td>uint256</td><td>output token Ocean ID</td></tr><tr><td>specifiedAmount</td><td>uint256</td><td>amount of the specified token</td></tr><tr><td>metadata</td><td>bytes32</td><td>bytes32 array of arbitrary data, during 721/1155 and wraps and unwraps we use this filed to pass token ID</td></tr></tbody></table>

This function executes multiple interactions in order they were stacked in the array of interactions  on behalf the address that was forwarded as the `userAddress` param. Use this function to compose different interactions, i.e. Ocean native primitives.

It should...

1. Revert if address forwarded as `userAddress` param hasn't approved message sender to pass interactions on its behalf via i`sApprovedForAll` ERC1155 method.
2. Execute a single forwarded interaction.

## registerNewTokens()

```solidity
/**
* @dev Registered Tokens are tokens issued directly on the ocean's 1155 ledger.
* @dev These are tokens that cannot be wrapped or unwrapped.
* @dev We don't validate the inputs.  The happy path usage is for callers
*  to obtain authority over tokens that have their ids derived from
*  successive nonces.
*
*  registerNewTokens(0, n):
*      _calculateOceanId(caller, 0)
*      _calculateOceanId(caller, 1)
*      ...
*      _calculateOceanId(caller, n)
*
*  Since the ocean tracks the one to one relationship of:
*    token => authority
*  but not the one to many relationship of:
*    authority => tokens
*  it is nice UX to be able to re-derive the tokens on the fly from the
*  authority's address and successive (predictable) nonces are used.
*
*  However, if the caller wants to use this interface in a different way,
*  they could easily make a call like:
*  registerNewTokens($SOME_NUMBER, 1); to use $SOME_NUMBER
*  as the nonce.  A user could request to buy an in-ocean nft with a
*  specific seed value, and the external contract gains authority over
*  this id on the fly in order to sell it.
*
*  If the caller tries to reassert authority over a token they've already
*  registered, they just waste gas.  If a caller expects to create
*  new tokens over time, it should track how many tokens it has already
*  created
* @dev the guiding philosophy is to track only essential information in
*  the Ocean's state, and let users (both EOAs and contracts) track other
*  information as they see fit.
* @param currentNumberOfTokens the starting nonce
* @param numberOfAdditionalTokens the number of new tokens registered
* @return oceanIds Ocean IDs of the tokens the caller now has authority over
*/
function registerNewTokens(
   uint256 currentNumberOfTokens,
   uint256 numberOfAdditionalTokens
) external override returns (
   uint256[] memory oceanIds
);
```

| Parameter Name           | Type    | Description                                  |
| ------------------------ | ------- | -------------------------------------------- |
| currentNumberOfTokens    | uint256 | current number of tokens as a starting nonce |
| numberOfAdditionalTokens | unit256 | the number of new tokens to be registered    |

This functions should register new tokens that are issued directly on the Ocean's ERC-1155 ledger.

## supportsInterface()

A standard implementation of ERC165 supportsInterface method which checks for `IERC1155`, `IERC1155MetadataURI` or `IERC165` implementations. For more details see check the official [EIP-165 page](https://eips.ethereum.org/EIPS/eip-165) or OpenZeppelin [Introspection page](https://docs.openzeppelin.com/contracts/3.x/api/introspection).

## Other methods

Below is a list of other public and external methods accessible in the Ocean smart contract, which may not be as relevant. Most of these methods are implemented as part of the ERC-1155 specification.

### uri()

This function is an implementation of the ERC-1155 `uri` method. For more details, check the  Metadata section of the [EIP-1155 page](https://eips.ethereum.org/EIPS/eip-1155#metadata).

### onERC721Received()

This function is an implementation of the `onERC721Received` method from the `IERC721Receiver` interface contract. For more details, check the interface ERC721TokenReceiver part of the [specification section](https://eips.ethereum.org/EIPS/eip-721#specification) of the EIP-721 page.

### onERC1155Received()

This function is an implementation of the `onERC1155Received` method from the `IERC1155TokenReceiver` interface contract. For more details, check the [ERC-1155 Token Receiver section](https://eips.ethereum.org/EIPS/eip-1155#erc-1155-token-receiver) of the EIP-1155 page.

### onERC1155BatchReceived()

This function is an implementation of the `onERC1155BatchReceived` method from the `IERC1155TokenReceiver` interface contract. For more details check the [ERC-1155 Token Receiver section](https://eips.ethereum.org/EIPS/eip-1155#erc-1155-token-receiver) of the EIP-1155 page.

### balanceOf()

This function is an implementation of the `balanceOf` method from the `IERC1155` interface contract. For more details, check the [specification section](https://eips.ethereum.org/EIPS/eip-1155#specification) of the EIP-1155 page.

### balanceOfBatch()

This function is an implementation of the `balanceOfBatch` method from the `IERC1155` interface contract. For more details, check the [specification](https://eips.ethereum.org/EIPS/eip-1155#specification) and [Batch Balance](https://eips.ethereum.org/EIPS/eip-1155#batch-balance) sections of the EIP-1155 page.

### setApprovalForAll()

This function is an implementation of the `setApprovalForAll` method from the `IERC1155` interface contract. For more details, check the [specification](https://eips.ethereum.org/EIPS/eip-1155#specification) and [Approval](https://eips.ethereum.org/EIPS/eip-1155#approval) sections of the EIP-1155 page.

### isApprovedForAll()

This function is an implementation of the `isApprovedForAll` method from the `IERC1155` interface contract. For more details, check the [specification](https://eips.ethereum.org/EIPS/eip-1155#specification) and [Approval](https://eips.ethereum.org/EIPS/eip-1155#approval) sections of the EIP-1155 page.

### safeTransferFrom()

This function is an implementation of the `safeTransferFrom` method from the `IERC1155` interface contract. For more details, check the [specification](https://eips.ethereum.org/EIPS/eip-1155#specification) and [Safe Transfer Rules](https://eips.ethereum.org/EIPS/eip-1155#safe-transfer-rules) sections of the EIP-1155 page.

### safeBatchTransferFrom()

This function is an implementation of the `safeBatchTransferFrom` method from the `IERC1155` interface contract. For more details, check the [specification](https://eips.ethereum.org/EIPS/eip-1155#specification) and [Batch Transfers](https://eips.ethereum.org/EIPS/eip-1155#batch-transfers) sections of the EIP-1155 page.


# IOceanPrimitive.sol

Github link: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/ocean/IOceanPrimitive.sol>

## computeOutputAmount()

{% code overflow="wrap" %}

```solidity
function computeOutputAmount(
    uint256 inputToken,
    uint256 outputToken,
    uint256 inputAmount,
    address userAddress,
    bytes32 metadata
) external returns (
    uint256 outputAmount
);
```

{% endcode %}

| Parameter Name | Type    | Description                                                                      |
| -------------- | ------- | -------------------------------------------------------------------------------- |
| inputToken     | unit256 | input token Ocean ID                                                             |
| outputToken    | unit256 | output token Ocean ID                                                            |
| inputAmount    | unit256 | amount of the specified input token                                              |
| userAddress    | address | address which may be used or ignored by the Ocean Primitive                      |
| metadata       | bytes32 | bytes32 array of arbitrary data which Ocean Primitive may use or chose to ignore |

This function calculates the amount of the output token should be received for the provided amount of the input token. For example, in case of AMM: here's 100 DAIs how many USDCs can I get? Where 100 is inputAmount, DAI is inputToken and USDC is outputToken.

## computeInputAmount()

{% code overflow="wrap" %}

```solidity
function computeOutputAmount(
    uint256 inputToken,
    uint256 outputToken,
    uint256 inputAmount,
    address userAddress,
    bytes32 metadata
) external returns (
    uint256 inputAmount
);
```

{% endcode %}

| Parameter Name | Type    | Description                                                                      |
| -------------- | ------- | -------------------------------------------------------------------------------- |
| inputToken     | unit256 | input token Ocean ID                                                             |
| outputToken    | unit256 | output token Ocean ID                                                            |
| outputAmount   | unit256 | amount of the specified input token                                              |
| userAddress    | address | address which may be used or ignored by the Ocean Primitive                      |
| metadata       | bytes32 | bytes32 array of arbitrary data which Ocean Primitive may use or chose to ignore |

This function calculates the amount of the input token should be given for the provided amount of the output token. For example, in case of AMM: How much DAIs should I give to receive a 100 USDC? Where DAI is inputToken, outputAmount is 100 and USDC is outputToken.

## getTokenSupply()

{% code overflow="wrap" %}

```solidity
function getTokenSupply(
    uint256 tokenId
) external view returns (
    uint256 totalSupply
);
```

{% endcode %}

| Parameter Name | Type    | Description          |
| -------------- | ------- | -------------------- |
| tokenId        | unit256 | input token Ocean ID |

This function returns a total supply of the Ocean Primitive's registered tokens.\
\
It's optional and Ocean Primitives don't have to implement it if they don't want to expose the the total supply of their registered tokens.


# IOceanToken.sol

Github Link: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/ocean/IOceanToken.sol>

## registerNewTokens()

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity">/**
* @title Interface for external contracts that issue tokens on the Ocean's
*  public multitoken ledger
* @dev Implemented by OceanERC1155.
*/
<strong>function registerNewTokens(
</strong>    uint256 currentNumberOfTokens,
    uint256 numberOfAdditionalTokens
) external returns (
    uint256[] memory
);
</code></pre>

| Parameter Name           | Type    | Description                                  |
| ------------------------ | ------- | -------------------------------------------- |
| currentNumberOfTokens    | unit256 | current number of tokens as a starting nonce |
| numberOfAdditionalTokens | unit256 | the number of new tokens to be registered    |

This function creates native tokens for Ocean Primitives. It can be invoked anytime, but Ocean Primitives always invoke it upon creation first.

It is implemented by the `OceanERC1155.sol` which is inherited by the actual Ocean implementation `Ocean.sol`. In order to call it you should pass Ocean address to the interface like in the example below:

```solidity
address oceanAddress = 0xc32eb36f886f638fffd836df44c124074cfe3584;

IOceanToken(oceanAddress).registerNewTokens(0, 1);
```


# OceanAdapter.sol


# Proteus

{% content-ref url="/pages/NzsbBAD3oCaoSMh2btCn" %}
[Proteus.sol](/smart-contracts-specification/proteus/proteus.sol)
{% endcontent-ref %}

{% content-ref url="/pages/T0l0OXY7937Hf6f4wZ5G" %}
[EvolvingProteus.sol](/smart-contracts-specification/proteus/evolvingproteus.sol)
{% endcontent-ref %}

{% content-ref url="/pages/z9pVJOm62fFKMCZz1U9p" %}
[LiquidityPoolProxy.sol](/smart-contracts-specification/proteus/liquiditypoolproxy.sol)
{% endcontent-ref %}


# Proteus.sol

Github link: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/proteus/Proteus.sol>

## constructor()

{% code overflow="wrap" %}

```solidity
constructor(
    int128[] memory ms,
    int128[] memory _as,
    int128[] memory bs,
    int128[] memory ks
) Slices(ms, _as, bs, ks);
```

{% endcode %}

| Parameter Name | Type      | Description                                               |
| -------------- | --------- | --------------------------------------------------------- |
| ms             | int128\[] | a list of slopes of the radial lines                      |
| \_as           | int128\[] |                                                           |
| bs             | int128\[] |                                                           |
| ks             | int128\[] | a list of values for relative scale factors of each slice |

This method is called whenever a new pool is deployed.

## swapGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an input amount of a reserve token, we compute an output
*  amount of the other reserve token, keeping utility invariant.
* @dev We use FEE_DOWN because we want to decrease the perceived
*  input amount and decrease the observed output amount.
*/
function swapGivenInputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 inputAmount,
   SpecifiedToken inputToken
) external view returns (
   uint256 outputAmount
);
```

{% endcode %}

| Parameter Name | Type                | Description                                      |
| -------------- | ------------------- | ------------------------------------------------ |
| xBalance       | unit256             | x token balance                                  |
| yBalance       | unit256             | y token balance                                  |
| inputAmount    | unit256             | amount of input tokens to swap for output tokens |
| inputToken     | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y             |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes output amount of the reserve token based on the input amount of the reserved token.

It should...

1. Return the output amount based on the input amount.

## swapGivenOutputAmount()

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity">/**
<strong>* @dev Given an output amount of a reserve token, we compute an input
</strong>*  amount of the other reserve token, keeping utility invariant.
* @dev We use FEE_UP because we want to increase the perceived output
*  amount and increase the observed input amount.
*/
function swapGivenOutputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 outputAmount,
   SpecifiedToken outputToken
) external view returns (
   uint256 inputAmount
);
</code></pre>

| Parameter Name | Type                | Description                                      |
| -------------- | ------------------- | ------------------------------------------------ |
| xBalance       | unit256             | x token balance                                  |
| yBalance       | unit256             | y token balance                                  |
| outputAmount   | unit256             | amount of output tokens to swap for input tokens |
| outputToken    | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y             |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes input amount of the reserve token necessary to get for the desired amount of the output token.

It should...

1. Return input amount necessary to receive the output amount.

## depositGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an input amount of a reserve token, we compute an output
*  amount of LP tokens, scaling the total supply of the LP tokens with the
*  utility of the pool.
* @dev We use FEE_DOWN because we want to decrease the perceived amount
*  deposited and decrease the amount of LP tokens minted.
*/
function depositGivenInputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 depositedAmount,
   SpecifiedToken depositedToken
) external view returns (
   uint256 mintedAmount
);
```

{% endcode %}

| Parameter Name  | Type                | Description                                         |
| --------------- | ------------------- | --------------------------------------------------- |
| xBalance        | unit256             | x token balance                                     |
| yBalance        | unit256             | y token balance                                     |
| totalSupply     | unit256             | total supply of the LP tokens that exists currently |
| depositedAmount | unit256             | the amount of token to be deposited                 |
| depositedToken  | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes output amount of LP tokens based on the amount of the input token.

It should...

1. Return amount of LP tokens minted for the amount of the provided token.

## depositGivenOutputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an output amount of the LP token, we compute an amount of
*  a reserve token that must be deposited to scale the utility of the pool
*  in proportion to the change in total supply of the LP token.
* @dev We use FEE_UP because we want to increase the perceived change in
*  total supply and increase the observed amount deposited.
*/
function depositGivenOutputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 mintedAmount,
   SpecifiedToken depositedToken
) external view returns (
   uint256 depositedAmount
);
```

{% endcode %}

| Parameter Name | Type                | Description                                         |
| -------------- | ------------------- | --------------------------------------------------- |
| xBalance       | unit256             | x token balance                                     |
| yBalance       | unit256             | y token balance                                     |
| totalSupply    | unit256             | total supply of the LP tokens that exists currently |
| mintedAmount   | unit256             | the amount of LP token to be minted                 |
| depositedToken | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes deposit amount necessary to in order to receive desired amount of LP tokens (minted amount).

It should...

1. Return amount of deposited token necessary to get the desired amount of LP tokens.

## withdrawGivenOutputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an output amount of a reserve token, we compute an amount of
*  LP tokens that must be burned in order to decrease the total supply in
*  proportion to the decrease in utility.
* @dev We use FEE_UP because we want to increase the perceived amount
*  withdrawn from the pool and increase the observed decrease in total
*  supply.
*/
function withdrawGivenOutputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 withdrawnAmount,
   SpecifiedToken withdrawnToken
) external view returns (
   uint256 burnedAmount
);
```

{% endcode %}

| Parameter Name  | Type                | Description                                         |
| --------------- | ------------------- | --------------------------------------------------- |
| xBalance        | unit256             | x token balance                                     |
| yBalance        | unit256             | y token balance                                     |
| totalSupply     | unit256             | total supply of the LP tokens that exists currently |
| withdrawnAmount | unit256             | the amount of token to be withdrawn                 |
| withdrawnToken  | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes how many LP tokens should be burned in exchange for the withdraw amount of the specified token.

It should...

1. Return amount of LP tokens burned for the request amount of withdraw token.

## withdrawGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an input amount of the LP token, we compute an amount of
*  a reserve token that must be output to decrease the pool's utility in
*  proportion to the pool's decrease in total supply of the LP token.
* @dev We use FEE_UP because we want to increase the perceived amount of
*  reserve tokens leaving the pool and to increase the observed amount of
*  LP tokens being burned.
*/
function withdrawGivenInputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 burnedAmount,
   SpecifiedToken withdrawnToken
) external view returns (
   uint256 withdrawnAmount
);
```

{% endcode %}

| Parameter Name | Type                | Description                                         |
| -------------- | ------------------- | --------------------------------------------------- |
| xBalance       | unit256             | x token balance                                     |
| yBalance       | unit256             | y token balance                                     |
| totalSupply    | unit256             | total supply of the LP tokens that exists currently |
| burnedAmount   | unit256             | the amount of LP tokens that are going to be burned |
| withdrawnToken | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes amount of specified withdrawn token to be received for the given amount of burned LP tokens.

It should...

1. Return amount of withdraw tokens to be received for the amount of burned LP tokens.


# EvolvingProteus.sol

Github Link: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/proteus/EvolvingProteus.sol>

## constructor()

{% code overflow="wrap" %}

```solidity
/**
* @param _py_init The initial price at the y axis
* @param _px_init The initial price at the x axis
* @param _py_final The final price at the y axis
* @param _px_final The final price at the y axis
* @param _curveEvolutionStartTime curve evolution start time
* @param _curveEvolutionDuration duration for which the curve will evolve
*/
constructor(
    int128 _py_init,
    int128 _px_init,
    int128 _py_final,
    int128 _px_final,
    uint256 _curveEvolutionStartTime,
    uint256 _curveEvolutionDuration
)
```

{% endcode %}

| Parameter Name            | Type    | Description                   |
| ------------------------- | ------- | ----------------------------- |
| \_py\_init                | int128  | initial price on the y axis   |
| \_px\_init                | int128  | initial price on the x axis   |
| \_py\_final               | int128  | final price on the y axis     |
| \_px\_final               | int128  | initial price on the x axis   |
| \_curveEvolutionStartTime | uint256 | timestamp in seconds          |
| \_curveEvolutionDuration  | uint256 | evolution duration in seconds |

This method is called whenever a new EvolvingProteus pool is deployed.

## params()

<pre class="language-solidity"><code class="lang-solidity">/**
<strong>* @notice Returns all the pool configuration params in a tuple
</strong>*/
function params() public view returns (
    int128,
    int128,
    int128,
    int128,
    uint256,
    uint256,
    uint256
);
</code></pre>

This function returns all the pool configuration.

It should...

1. Return a tuple of all the pool configuration params `(py_init, px_init, py_final, px_final, t_init, t_final, curveEvolutionDuration)`.

## elapsed()

```solidity
/**
* @notice Calculates the time that has passed since deployment
*/
function elapsed() public view returns (
    uint256
);
```

This function returns the time that has passed since contract deployment.

## t()

```solidity
/**
* @notice Calculates the time as a percent of total duration
*/
function t() public view returns (
    int128
);
```

This function returns percentage of how much time has passed since the evolution started.

## p\_min()

```solidity
/**
* notice The minimum price (at the x asymptote) at the current block
*/
function p_min() public view returns (
    int128
);
```

This function returns the minimum price at the current block.

## p\_max()

```solidity
/**
* @notice The maximum price (at the y asymptote) at the current block
*/
function p_max() public view returns (
    int128
);
```

This function returns the maximum price at the current block.

## a()

```solidity
/**
* @notice Calculates the a variable in the curve eq which is basically a sq. root
* of the inverse of y instantaneous price
*/
function a() public view returns (
    int128
);
```

This function returns a sq. root of the inverse of y instantaneous price.

## b()

```solidity
/**
* @notice Calculates the b variable in the curve eq which is basically a sq. root
* of the inverse of x instantaneous price
*/
function b() public view returns (
    int128
);
```

This function returns a sq. root of the inverse of x instantaneous price.

## swapGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an input amount of one reserve token, we compute the output
* amount of the other reserve token, keeping utility invariant.
* @dev We use FEE_DOWN because we want to decrease the perceived
* input amount and decrease the observed output amount.
*/
function swapGivenInputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 inputAmount,
   SpecifiedToken inputToken
) external view returns (
   uint256 outputAmount
);
```

{% endcode %}

| Parameter Name | Type                | Description                                      |
| -------------- | ------------------- | ------------------------------------------------ |
| xBalance       | unit256             | x token balance                                  |
| yBalance       | unit256             | y token balance                                  |
| inputAmount    | unit256             | amount of input tokens to swap for output tokens |
| inputToken     | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y             |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes output amount of the reserve token based on the input amount of the reserved token.

It should...

1. Revert if the function is invoked before the pool evolution start date.
2. Return the output amount based on the input amount.

## swapGivenOutputAmount()

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity">/**
<strong>* @dev Given an output amount of a reserve token, we compute an input
</strong>*  amount of the other reserve token, keeping utility invariant.
* @dev We use FEE_UP because we want to increase the perceived output
*  amount and increase the observed input amount.
*/
function swapGivenOutputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 outputAmount,
   SpecifiedToken outputToken
) external view returns (
   uint256 inputAmount
);
</code></pre>

| Parameter Name | Type                | Description                                      |
| -------------- | ------------------- | ------------------------------------------------ |
| xBalance       | unit256             | x token balance                                  |
| yBalance       | unit256             | y token balance                                  |
| outputAmount   | unit256             | amount of output tokens to swap for input tokens |
| outputToken    | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y             |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes input amount of the reserve token necessary to get for the desired amount of the output token.

It should...

1. Revert if the function is invoked before the pool evolution start date.
2. Return input amount necessary to receive the output amount.

## depositGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an input amount of a reserve token, we compute an output
*  amount of LP tokens, scaling the total supply of the LP tokens with the
*  utility of the pool.
* @dev We use FEE_DOWN because we want to decrease the perceived amount
*  deposited and decrease the amount of LP tokens minted.
*/
function depositGivenInputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 depositedAmount,
   SpecifiedToken depositedToken
) external view returns (
   uint256 mintedAmount
);
```

{% endcode %}

| Parameter Name  | Type                | Description                                         |
| --------------- | ------------------- | --------------------------------------------------- |
| xBalance        | unit256             | x token balance                                     |
| yBalance        | unit256             | y token balance                                     |
| totalSupply     | unit256             | total supply of the LP tokens that exists currently |
| depositedAmount | unit256             | the amount of token to be deposited                 |
| depositedToken  | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes output amount of LP tokens based on the amount of the input token.

It should...

1. Revert if the function is invoked before the pool evolution start date.
2. Return amount of LP tokens minted for the amount of the provided token.

## depositGivenOutputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an output amount of the LP token, we compute an amount of
*  a reserve token that must be deposited to scale the utility of the pool
*  in proportion to the change in total supply of the LP token.
* @dev We use FEE_UP because we want to increase the perceived change in
*  total supply and increase the observed amount deposited.
*/
function depositGivenOutputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 mintedAmount,
   SpecifiedToken depositedToken
) external view returns (
   uint256 depositedAmount
);
```

{% endcode %}

| Parameter Name | Type                | Description                                         |
| -------------- | ------------------- | --------------------------------------------------- |
| xBalance       | unit256             | x token balance                                     |
| yBalance       | unit256             | y token balance                                     |
| totalSupply    | unit256             | total supply of the LP tokens that exists currently |
| mintedAmount   | unit256             | the amount of LP token to be minted                 |
| depositedToken | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes deposit amount necessary to in order to receive desired amount of LP tokens (minted amount).

It should...

1. Revert if the function is invoked before the pool evolution start date.
2. Return amount of deposited token necessary to get the desired amount of LP tokens.

## withdrawGivenOutputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an output amount of a reserve token, we compute an amount of
*  LP tokens that must be burned in order to decrease the total supply in
*  proportion to the decrease in utility.
* @dev We use FEE_UP because we want to increase the perceived amount
*  withdrawn from the pool and increase the observed decrease in total
*  supply.
*/
function withdrawGivenOutputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 withdrawnAmount,
   SpecifiedToken withdrawnToken
) external view returns (
   uint256 burnedAmount
);
```

{% endcode %}

| Parameter Name  | Type                | Description                                         |
| --------------- | ------------------- | --------------------------------------------------- |
| xBalance        | unit256             | x token balance                                     |
| yBalance        | unit256             | y token balance                                     |
| totalSupply     | unit256             | total supply of the LP tokens that exists currently |
| withdrawnAmount | unit256             | the amount of token to be withdrawn                 |
| withdrawnToken  | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes how many LP tokens should be burned in exchange for the withdraw amount of the specified token.

It should...

1. Revert if the function is invoked before the pool evolution start date.
2. Return amount of LP tokens burned for the request amount of withdraw token.

## withdrawGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev Given an input amount of the LP token, we compute an amount of
*  a reserve token that must be output to decrease the pool's utility in
*  proportion to the pool's decrease in total supply of the LP token.
* @dev We use FEE_UP because we want to increase the perceived amount of
*  reserve tokens leaving the pool and to increase the observed amount of
*  LP tokens being burned.
*/
function withdrawGivenInputAmount(
   uint256 xBalance,
   uint256 yBalance,
   uint256 totalSupply,
   uint256 burnedAmount,
   SpecifiedToken withdrawnToken
) external view returns (
   uint256 withdrawnAmount
);
```

{% endcode %}

| Parameter Name | Type                | Description                                         |
| -------------- | ------------------- | --------------------------------------------------- |
| xBalance       | unit256             | x token balance                                     |
| yBalance       | unit256             | y token balance                                     |
| totalSupply    | unit256             | total supply of the LP tokens that exists currently |
| burnedAmount   | unit256             | the amount of LP tokens that are going to be burned |
| withdrawnToken | SpecifiedToken enum | SpecifiedToken.X or SpecifiedToken.Y                |

SpecifiedToken enum:

| Enum Member Name | Type                                     | Description                                            |
| ---------------- | ---------------------------------------- | ------------------------------------------------------ |
| X                | enum member (technically token Ocean ID) | an indicator stating usage of token X in the operation |
| Y                | enum member (technically token Ocean ID) | an indicator stating usage of token Y in the operation |

This function computes amount of specified withdrawn token to be received for the given amount of burned LP tokens.

It should...

1. Revert if the function is invoked before the pool evolution start date.
2. Return amount of withdraw tokens to be received for the amount of burned LP tokens.


# LiquidityPoolProxy.sol

Github Link: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/proteus/LiquidityPoolProxy.sol>

## constructor()

{% code overflow="wrap" %}

```solidity
constructor(
    uint256 xToken_,
    uint256 yToken_,
    address ocean_,
    uint256 initialLpTokenSupply_
) LiquidityPool(
    xToken_,
    yToken_,
    ocean_,
    initialLpTokenSupply_,
    address(0)
);
```

{% endcode %}

| Parameter Name         | Type    | Description                                                                     |
| ---------------------- | ------- | ------------------------------------------------------------------------------- |
| xToken\_               | unit256 | Ocean ID of the first of two tokens that make up the base pair                  |
| yToken\_               | unit256 | Ocean ID of the second of two tokens that make up the base pair                 |
| ocean\_                | address | an address of the Ocean contract                                                |
| initialLpTokenSupply\_ | unit256 | the initial supply of the Liquidity Provider token. It should be an even number |

This method is called whenever a new LiquidityPoolProxy contract is deployed.

## swapGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev this function should begin by calling _getBalances() to get the
*  xBalance and yBalance
*/
function swapGivenInputAmount(
   uint256 inputToken, 
   uint256 inputAmount
) public view override notFrozen returns (
   uint256 outputAmount
);
```

{% endcode %}

| Parameter Name | Type    | Description                                              |
| -------------- | ------- | -------------------------------------------------------- |
| inputToken     | unit256 | Ocean ID of one of two tokens that make up the base pair |
| inputAmount    | unit256 | amount of tokens to swap                                 |

This function executes a swap of the input amount of input token for the second of the tokens that make up the pool base pair.

It should...

1. Swap specified of input tokens for the second token that makes the liquidity pool.

## depositGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev this function should begin by calling _getBalances() to get the
*  xBalance and yBalance and _getTotalSupply to get the lpTokenSupply
*/
function depositGivenInputAmount(
   uint256 depositToken,
   uint256 depositAmount
) public view override notFrozen returns (
   uint256 mintAmount
);
```

{% endcode %}

| Parameter Name | Type    | Description                                                                                             |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------- |
| depositToken   | unit256 | Ocean ID of the token to be deposited. It should be one of the two tokens that make up the LP base pair |
| depositAmount  | unit256 | amount of tokens to deposit                                                                             |

This function deposits specified deposit amount of the specified deposit token into Liquidity Pool. Deposit token should be one of the two tokens that make up the LP base pair.

It should...

1. Deposit a token into the Liquidity Pool.

## withdrawGivenInputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev this function should begin by calling _getBalances() to get the
*  xBalance and yBalance and _getTotalSupply to get the lpTokenSupply
*/
function withdrawGivenInputAmount(
   uint256 withdrawnToken,
   uint256 burnAmount
) public view override notFrozen returns (
   uint256 withdrawnAmount
);
```

{% endcode %}

| Parameter Name | Type    | Description                                                                                             |
| -------------- | ------- | ------------------------------------------------------------------------------------------------------- |
| withdrawnToken | unit256 | Ocean ID of the token to be withdrawn. It should be one of the two tokens that make up the LP base pair |
| burnAmount     | unit256 | amount of tokens to withdraw                                                                            |

This function withdraws specified withdraw amount of the specified withdraw token from the Liquidity Pool. Withdraw token should be one of the two tokens that make up the LP base pair.

It should...

1. Withdraw a token from the Liquidity Pool.

## swapGivenOutputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev this function should begin by calling _getBalances() to get the
*  xBalance and yBalance
*/
function swapGivenOutputAmount(
   uint256 outputToken, 
   uint256 outputAmount
) public view override notFrozen returns (
   uint256 inputAmount
);
```

{% endcode %}

| Parameter Name | Type    | Description                                              |
| -------------- | ------- | -------------------------------------------------------- |
| outputToken    | unit256 | Ocean ID of one of two tokens that make up the base pair |
| outputAmount   | unit256 | amount of tokens desired to get from the swap            |

This function returns how many input tokens should be given for the desired output amount of the specified output token. Output token should be one of the two tokens that make up the LP base pair.

It should...

1. Return the number of the other of the tokens that make up Liquidity Pool's base pair should be given for the specified output token.

## depositGivenOutputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev this function should begin by calling _getBalances() to get the
*  xBalance and yBalance and _getTotalSupply() to get the lpTokenSupply
*/
function depositGivenOutputAmount(
   uint256 depositToken, 
   uint256 mintAmount
) public view override notFrozen returns (
   uint256 depositAmount
);
```

{% endcode %}

| Parameter Name | Type    | Description                                              |
| -------------- | ------- | -------------------------------------------------------- |
| depositToken   | unit256 | Ocean ID of one of two tokens that make up the base pair |
| mintAmount     | unit256 | amount of LP tokens to be minted                         |

This function returns how many deposit tokens should be deposited for the desired amount of the LP tokens. Deposit token should be one of the two tokens that make up the LP base pair.

It should...

1. Return the number of deposit tokens necessary to receive specified mint amount of LP tokens.

## withdrawGivenOutputAmount()

{% code overflow="wrap" %}

```solidity
/**
* @dev this function should begin by calling _getBalances() to get the
*  xBalance and yBalance and _getTotalSupply() to get the lpTokenSupply
*/
function withdrawGivenOutputAmount(
   uint256 withdrawnToken,
   uint256 withdrawnAmount
) public view override notFrozen returns (
   uint256 burnAmount
);
```

{% endcode %}

| Parameter Name  | Type    | Description                                              |
| --------------- | ------- | -------------------------------------------------------- |
| withdrawnToken  | unit256 | Ocean ID of one of two tokens that make up the base pair |
| withdrawnAmount | unit256 | amount of tokens to be withdrawn                         |

This function returns how many LP tokens should be burned in order to receive specified withdrawn amount of the specified withdrawn token. Withdrawn token should be one of the two tokens that make up the LP base pair.

It should...

1. Return the number of LP tokens that should be burned in order to receive specified amount of wanted token.


# Fractionalizer

{% content-ref url="/pages/yhSyCCYYliVZfhlgA5gw" %}
[FractionalizerFactory.sol](/smart-contracts-specification/fractionalizer/fractionalizerfactory.sol)
{% endcontent-ref %}


# FractionalizerFactory.sol

Github Link: <https://github.com/Shell-Protocol/Shell-Protocol/blob/main/src/fractionalizer/FractionalizerFactory.sol>

## deploy()

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity">/**
* @notice
* Deploys Fractionalizer with create2(https://eips.ethereum.org/EIPS/eip-1014)
* 
* @param oceanAddress Ocean contract address.
* @param nftCollection_ NFT collection address
* @param exchangeRate_ No of fungible tokens per each NFT.
* 
* @return fractionalizer fractionalizer contract address
*/
function deploy(
    address oceanAddress,
    address nftCollection_,
    uint256 exchangeRate_,
    bool isErc721
) external returns (
<strong>    address fractionalizer
</strong>)
</code></pre>

| Parameter Name  | Type    | Description                                                                           |
| --------------- | ------- | ------------------------------------------------------------------------------------- |
| oceanAddress    | address | address of the deployed Ocean smart contract                                          |
| nftCollection\_ | address | address of the NFT smart contract you want to create fractionalizer for               |
| exchangeRate\_  | unit256 | number of fungible tokens per each NFT (basically, how many tokens each NFT is worth) |
| isErc721        | bool    | if true NFT smart contract is ERC-721, if false NFT smart contract is ERC-1155        |

This function creates a new `Fractionalizer721` or `Fractionalizer1155` smart contract for a given collection.

It should...

1. Deploy new smart contract based on whether the forwarded NFT smart contract is ERC-721 or ERC-1155


# Build an AMM with Proteus

A brief summary of how to construct an AMM using Proteus

### Quick Links

* [Deploy a Proteus Pool GitHub](https://github.com/Shell-Protocol/Shell-Protocol/blob/main/scripts/deployPool.js)

### Derive a Bonding Curve for Proteus

Constructing an AMM using Proteus is much simpler than building one from scratch. Here is a brief summary of how to derive a Proteus bonding curve with concentrated liquidity.

1. Gather price data by examining the historical prices for the pair over the last year. You can use[ Dune Analytics](https://dune.com/home),[ CoinMarketCap](https://coinmarketcap.com/),[ CoinGecko](https://www.coingecko.com/), or any resource of your liking for this.
2. Use the historical prices to decide where to concentrate liquidity. Stable-to-stable pools are designed so that when the pool's liquidity is split 50-50 across both tokens, the swap rate is the median rate over the last year. Volatile-to-stable pools (like USD+ETH) are designed so that when the pool's liquidity is split 50-50 across both tokens, the swap rate uses the median dollar value of the volatile token over the last year (note, this creates visually unusual bonding curves—basically it looks like a vertical line).
3. Assign price buckets to fit the historical price distribution. You can use as many as you like. The first deployed pools used 8-12 for stable-to-stable pairs and fewer (\~4) for volatile-to-stable pairs. In this case, fewer buckets means larger buckets. This is necessary because their prices (of ETH or BTC, for example) are so variable. Therefore these volatile-to-stable curves are less concentrated than the stable-to-stable pools, although they are still significantly more concentrated than constant product curves.
4. Next, you assign approximate liquidity concentration values to each price bucket. The concentration of liquidity determines how much to magnify that portion of the curve (as detailed in the section "[Deriving segment parameters](https://shell-protocol.notion.site/Proteus-AMM-Engine-Update-3-7f33b7e1561347b696874a8ba02b9782)"). In other words, assign multipliers to each price bucket so a higher proportion of the pool's liquidity will always be allocated to the more popular price buckets.
5. Finally, you plug all this information into a gigantic system of equations to help create a composite function that takes each magnified curve section and stitches it together, resulting in one big curve.


# Build an NFT Fractionalizer

{% hint style="info" %}
This page is under construction.
{% endhint %}


# Build an NFT AMM

{% hint style="info" %}
This page is under construction.
{% endhint %}


