# Official Links and Notes

Public Links:

|    [Twitter](https://twitter.com/home)   |         [Github](https://github.com/dcaf-labs)         |
| :--------------------------------------: | :----------------------------------------------------: |
| [Discord](https://discord.gg/GJexU32nqK) | [Drip Devnet App](https://devnet.drip.dcaf.so/deposit) |
|                                          |        [Drip Mainnet App](https://drip.dcaf.so/)       |

At this time there are only 3 members of Dcaf Labs, anyone claiming otherwise is a **scammer**.

|  [Dcaf Mocha](https://twitter.com/dcaf_mocha) |
| :-------------------------------------------: |
| [Dcaf Matcha](https://twitter.com/DcafMatcha) |
|  [Dcaf Latte](https://twitter.com/DcafLatte)  |


# Drip

What the Drip?

Drip is an on-chain permission-less dollar cost averaging protocol. Lot's of words, but what does that mean?&#x20;

Lets break it down word by word:

**Dollar Cost Averaging:**  Dollar cost averaging describes the act of performing recurring trades to obtain an average price. We won't re-invent the wheel here, if you are still confused here is an [amazing article by Binance](https://academy.binance.com/en/glossary/dollar-cost-averaging).

**On-Chain:** The dollar cost averaging mechanism happens directly on the blockchain, i.e. all the trading/swaps happen on chain and can be verified on chain.

**Permission-less:** Permission-less, the lack of permissions. Anyone can perform a swap to progress a DCA, there are no restrictions on who can do this. Why would anyone want to? A small fee is rewarded to the user that can successfully trigger a swap for a token pair + frequency. Dcaf Labs runs a bot to do this for our users, and we hope the community will create their own bots to take advantage of this [fee structure](/products/drip/fee-structure).\
\
Drip is a unique product in the DeFi space because it offers a truly decentralized DCA experience and this is done via incentivized drips. In the next set of pages we go over the protocol in depth, and how you can interact with it either via the UI or programatically via the SDK.

#### Official Deployed Programs

<table><thead><tr><th width="129">Network</th><th width="130.79773156899807">Enviornment</th><th>Address</th></tr></thead><tbody><tr><td>mainnet</td><td>production</td><td>dripTrkvSyQKvkyWg7oi4jmeEGMA5scSYowHArJ9Vwk</td></tr><tr><td>devnet</td><td>production</td><td>dripTrkvSyQKvkyWg7oi4jmeEGMA5scSYowHArJ9Vwk</td></tr><tr><td>devnet</td><td>staging</td><td>F1NyoZsUhJzcpGyoEqpDNbUMKVvCnSXcCki1nN3ycAeo</td></tr></tbody></table>

{% hint style="info" %}
The Devnet Staging program is frequently updated as development progresses, it is not a stable program to use for integrations or testing. Please use the Devnet Production program.
{% endhint %}


# Programming Model

The section will detail out the different accounts used by the Drip progra.


# Vault Proto Config

The `VaultProtoConfig` stores the common configuration for a set of vaults such as fee information, the drip granularity, and the admin that can deploy new vaults using this config.&#x20;

```rust
pub struct VaultProtoConfig {
    pub granularity: u64, // 8
    // spread applied to each drip trigger in bps
    pub token_a_drip_trigger_spread: u16, // 2
    // spread applied to each withdrawal in bps
    pub token_b_withdrawal_spread: u16, // 2
    // spread applied to each withdrawal in bps
    pub token_b_referral_spread: u16, //2
    // to be used with the vault to modify certain fields (whitelist)
    pub admin: Pubkey, //32
}
```


# Vault

The `Vault` is the main account for a token pair and granularity. The `Vault` account is a PDA composed of the following seeds:

```rust
seeds = [
    b"drip-v1".as_ref(),
    token_a_mint.key().as_ref(),
    token_b_mint.key().as_ref(),
    vault_proto_config.key().as_ref(),
],
```

The `Vault` combined with the `Vault Period` is responsible for making sure that user funds are kept track of correctly on deposits and withdraws. The `Vault` also performs the the `Drips` in every period.

```rust
pub struct Vault {
    // Account relations
    pub proto_config: Pubkey,                                   // 32
    pub token_a_mint: Pubkey,                                   // 32
    pub token_b_mint: Pubkey,                                   // 32
    pub token_a_account: Pubkey,                                // 32
    pub token_b_account: Pubkey,                                // 32
    pub treasury_token_b_account: Pubkey,                       // 32
    pub whitelisted_swaps: [Pubkey; VAULT_SWAP_WHITELIST_SIZE], // 32*5

    // Data
    // 1 to N
    pub last_drip_period: u64,          // 8
    pub drip_amount: u64,               // 8
    pub drip_activation_timestamp: i64, // 8
    pub bump: u8,                       // 1
    pub limit_swaps: bool,              // 1
    pub max_slippage_bps: u16,          // 2
}
```


# Vault Period

The `VaultPeriod` holds the average price data for a `Vault` as well as the drip reduce amount once that period is finished (each position will contribute to the drip reduce amount on their position expiry period).  This account has the following PDA:

```rust
seeds = [
    b"vault_period".as_ref(),
    vault.key().as_ref(),
    params.period_id.to_string().as_bytes()
],

```

```rust
pub struct VaultPeriod {
    // Account relations
    pub vault: Pubkey, // 32

    // Data
    // The period index/offset from the genesis period of the vault (0, 1, ...)
    pub period_id: u64, // 8
    // Drip amount to reduce at this period
    pub dar: u64, // 8
    // Time weighted average price of asset A expressed in asset B from period 1 to this period
    pub twap: u128, // 16
    // Timestamp for the drip
    pub drip_timestamp: i64, //8
    // Bump
    pub bump: u8, // 1
}
```


# Position

The `Position` represents information on a user/account's DCA. It keeps track of a users withdrawal and deposits and is owned by the `Vault`. Authority of the `Position` is given to whoever owns the NFT token that has a `mint == position_authority.`<br>

```rust
pub struct Position {
    // The A/B/G vault the position belongs to
    pub vault: Pubkey, // 32
    // The position authority NFT mint
    pub position_authority: Pubkey, // 32
    // The address to send referral fees too
    pub referrer: Pubkey, // 32
    // Total deposited
    pub deposited_token_a_amount: u64, // 8
    // Total withdrawn B (amount sent to the user + amount sent to the treasury)
    pub withdrawn_token_b_amount: u64, // 8
    pub deposit_timestamp: i64,        // 8
    // The drip period ID of the vault that happened prior to the user opening this position
    pub drip_period_id_before_deposit: u64, // 8
    // Number of drips/Swaps that this position will be a part of
    pub number_of_swaps: u64, // 8
    // deposit_amount_token_a / number_of_swaps
    pub periodic_drip_amount: u64, // 8
    pub is_closed: bool,           // 1
    pub bump: u8,                  // 1
}
```


# Web Guide

This guide will go over how to use the Drip Protocol via our Web UI.


# Deposit

The first thing you will want to do within the application is connect you wallet.

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FznlwUttcGGjBqVL0nDc9%2FScreen%20Shot%202022-09-11%20at%204.51.10%20PM.png?alt=media&amp;token=c21628e5-0fd5-435d-a74a-345f8a9d0e49" alt=""><figcaption><p>Connect you wallet with the website</p></figcaption></figure>

If it is the first time you are connecting to the website, you will be prompted to approve the application **(this does NOT move any funds or sign any transactions)**.

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FnQDCBm84HkeZYdPpXqO4%2Fimage.png?alt=media&amp;token=ee910963-e4c0-4a48-bec2-909042cc023e" alt=""><figcaption><p>Example prompt from the phnatom web extension</p></figcaption></figure>

<details>

<summary>🚨 Devnet Minting</summary>

If you are using the devnet application, you can mint test tokens directly from within the application, however you still need SOL to perform transactions. You can obtain some small amounts of sol [here](https://solfaucet.com/).

<img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FcqDChoRxoGSxRkcdfBlc%2FScreen%20Shot%202022-09-11%20at%204.55.57%20PM.png?alt=media&amp;token=bd8c88fb-6a96-43ad-ab59-40abe085e061" alt="" data-size="original">

</details>

Select the source asset (Token A)&#x20;

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FBgwvgzgsw5Oy5GqrPCyR%2Fimage.png?alt=media&amp;token=656f3ec1-7601-4d41-97e4-3c339d692314" alt=""><figcaption></figcaption></figure>

Select the amount you would like to deposit (this is exact amount will be debited from your account)

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FOAG2xVIlisON8Mze2y3Z%2FScreen%20Shot%202022-09-11%20at%205.00.30%20PM.png?alt=media&amp;token=23f4002c-4e69-490a-82ff-d398a109770e" alt=""><figcaption><p>Type in a deposit amount, or click "max" to deposit your entire balance</p></figcaption></figure>

Select the destination asset (Token B). Only valid Token B's for Token A will be shown.

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FvJvgE3dy68ob0Q0Cldcg%2Fimage.png?alt=media&amp;token=7ad149da-132b-4cf2-aa4d-07bed48597d5" alt=""><figcaption></figcaption></figure>

Choose your desired frequency. A frequency describes how often you would like a swap to happen. \
Depending on the environment, different options may be displayed:

Devnet: Minutely, Hourly

Mainnet: Daily

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2F8whIrSDqLd7Q9qKP3q9w%2Fimage.png?alt=media&amp;token=4ca08c87-7b66-4d40-b219-30e6e7704bd3" alt=""><figcaption></figcaption></figure>

Choose your desired end date. Another way to view it is the date and time you would like to finish your recurring trades.

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FE9pzgC9Qosv7Ah8IngYN%2Fimage.png?alt=media&amp;token=ee50d882-896c-4a16-81d4-1e9f65f06a3d" alt=""><figcaption><p>Choose a date, and optionally adjust the time if necessary</p></figcaption></figure>

Once all the details are inputed, a summary of your action is displayed. Carefully review the text, and hit deposit once you are finished.&#x20;

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2Fkzn8gaTWKBUcjl4fqtzP%2Fimage.png?alt=media&amp;token=2c55bba4-4ad4-4a0b-bacc-3193f69a05a7" alt=""><figcaption></figcaption></figure>

Once you deposit, you will a new NFT in your wallet, this represents your DCA and more importantly it signifies your ownership of the DCA. If you transfer this NFT, the new NFT owner will be the owner of the DCA. If you burn this NFT your DCA will be lost **forever**.

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2Fz6lO7UFcWB4KR5EwL9bu%2Fimage.png?alt=media&amp;token=c24d804d-ebaf-4f82-984e-bc04174da83a" alt=""><figcaption></figcaption></figure>


# Withdraw

To view your positions, navigate to the positions tab in the website.

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FtoWQsMdceYpxMOe6MIwF%2FScreen%20Shot%202022-09-11%20at%206.24.13%20PM.png?alt=media&amp;token=82ed68fa-1bd4-48e2-9cc1-1aadf73a0318" alt=""><figcaption><p>Click "Positions" to navigate to the positions page</p></figcaption></figure>

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2F7IgLBW50Q1eip6rpqZAX%2Fimage.png?alt=media&amp;token=d8a76a53-885a-46a8-a2c6-8c0f9eba07f3" alt=""><figcaption><p>The positions page</p></figcaption></figure>

To initiate a withdrawal or a position closure, click into a position.

<figure><img src="https://830642869-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7Fe84MvzJ8tiOlQNqCK8%2Fuploads%2FncvNG2GIaJIx60CKYhcT%2Fimage.png?alt=media&amp;token=ac2432a8-8a70-4049-80fe-98819194dbf0" alt=""><figcaption><p>Position modal</p></figcaption></figure>

Once the modal is open, two call to actions are available, withdraw token B or close position.

**Withdraw**: Clicking this will withdraw all token B that has been accumulated thus for for your DCA position. You may withdraw after every swap if you desire to receive your Token B or you can withdraw once at the end of your DCA. This action does NOT withdraw any token A.

**Close Position:** Clicking this will do all the same things as withdraw, but it will also withdraw any token A that has not been swapped yet as well as burns the position NFT and closing the position NFT token account. **This action can only be done once per position.**


# Typescript Guides

This section will cover installing the SDK, going through the 3 major actions, and how to interact with them via the SDK.

### Installation&#x20;

The Drip Program SDK is hosted on [NPM](https://www.npmjs.com/package/@dcaf-labs/drip-sdk).&#x20;

```bash
npm i @dcaf-labs/drip-sdk
# or with yarn
yarn add @dcaf-labs/drip-sdk
```

The Drip Backend API SDK is hosted on [NPM](https://www.npmjs.com/package/@dcaf-labs/drip-ts).

```bash
npm i @dcaf-labs/drip-ts
# or with yarn
yarn add @dcaf-labs/drip-ts
```


# Deposit

This guide will go over deposit and depositWithMetadata.

The full example can be found on [github here](https://github.com/dcaf-labs/drip-sdk-example/blob/main/deposit.ts).

### Setup

<pre class="language-typescript"><code class="lang-typescript">import { Drip, DripVault, findVaultPubkey, Network, VaultAccount } from '@dcaf-labs/drip-sdk';
import { Address, AnchorProvider, BN } from '@project-serum/anchor';
import NodeWallet from '@project-serum/anchor/dist/cjs/nodewallet';
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';

async function main() {
    // export your wallet as such
    // export EXAMPLE_WALLET="[92,116,...,245,129]"
    const keypairData = process.env.EXAMPLE_WALLET;
    const programID = Uint8Array.from(JSON.parse(keypairData));
    const walletKeypair = Keypair.fromSecretKey(programID);
    console.log('connected wallet', walletKeypair.publicKey.toString());
    
    // Setup
    const programId = 'dripTrkvSyQKvkyWg7oi4jmeEGMA5scSYowHArJ9Vwk';
    const network = Network.Devnet;
    const clientEnv = ClientEnv.Production;
    const provider = new AnchorProvider(
        new Connection('https://api.devnet.solana.com', 'confirmed'),
        new NodeWallet(walletKeypair),
        AnchorProvider.defaultOptions()
    );
<strong>    const drip = Drip.fromNetworkClient(network, provider, programId, clientEnv);
</strong>    
    // Devnet Drip USDT
    const tokenA = new PublicKey('H9gBUJs5Kc5zyiKRTzZcYom4Hpj9VPHLy4VzExTVPgxa');
    
    // Given a tokenA, get valid tokenBs
    const tokenBs = await drip.config.getAllTokenBs(tokenA);
    // For the example's sake, lets pick the first token available
    const tokenB = tokenBs[Object.keys(tokenBs)[0]].mint;
    console.log('tokenA', tokenA.toString(), 'tokenB', tokenB.toString());
    
    const vaultProtoConfigs = await drip.config.getSupportedVaultProtoConfigsForPair(
        tokenA,
        tokenB
    );
    // For the example's sake, lets pick the first proto config
    const vaultProtoConfig = vaultProtoConfigs[0];
    console.log(
        'vaultProtoConfig',
        vaultProtoConfig.pubkey.toString(),
        'granularity',
        vaultProtoConfig.granularity.toString()
    );
    
    const vaultPubkey = findVaultPubkey(drip.programId, {
        protoConfig: vaultProtoConfig.pubkey,
        tokenAMint: tokenA,
        tokenBMint: tokenB
    });
    console.log('vault', vaultPubkey.toString());
    
    const dripVault = await drip.getVault(vaultPubkey);
    // ...
}
</code></pre>

### Deposit Without Token Metadata

This example creates a user position **without** creating the metaplex token metadata account. The position created by this instruction has no limitations, but the NFT image will not be viewable in your wallet provider (such as phantom). The instruction it is calling under the hood is `deposit`.

```typescript
console.log('\n\n\nDeposit Without TokenMetadata');

const res = await dripVault.deposit({
    // units are base units
    amount: new BN(100),
    dripParams: {
        numberOfSwaps: 10
    }
});

console.log('position', res.metadata.position.toString());
```

### Deposit With Token Metadata

This function does the same as [Deposit Without Token Metadata](#deposit-without-token-metadata), but it does create the token metadata account, thus making the NFT image viewable in most wallet providers. The instruction it is calling under the hood is `depositWithMetadata`.

```typescript
console.log('\n\n\nDeposit With TokenMetadata');

const res = await dripVault.depositWithMetadata({
    // units are base units
    amount: new BN(100),
    dripParams: {
        numberOfSwaps: 10
    }
});
console.log('position', res.metadata.position.toString());
console.log('positionMetadataAccount', res.metadata.positionMetadataAccount.toString());
```

### Deposit With Referrer

Both [Deposit With Token Metadata](#deposit-with-token-metadata) and [Deposit Without Token Metadata](#deposit-without-token-metadata) take an optional parameter of `referrer`. This parameter represents the Token B token account that will receive the referral fees on a withdrawal instruction (`withdrawB`, `closePosition`), see [Fee Structure](/products/drip/fee-structure) for more details. If this parameter is not provided, the vault's `treasuryTokenBAccount` will be used as the default value.

There is no restriction on the `referrer` so long that it is a token account for the vaults `tokenBMint`.


# Drip


# Orca Whirlpools

Coming soon.


# SPL Token Swap

Coming soon.


# Withdraw

This guide will go over withdawB and closePosition.

The full example can be found on [github here](https://github.com/dcaf-labs/drip-sdk-example/blob/main/withdraw.ts).

### Setup

```typescript
//import { Drip, DripVault, findVaultPubkey, Network, VaultAccount } from '@dcaf-labs/drip-sdk';
import { Address, AnchorProvider, BN } from '@project-serum/anchor';
import NodeWallet from '@project-serum/anchor/dist/cjs/nodewallet';
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';

async function main() {
    // export your wallet as such
    // export EXAMPLE_WALLET="[92,116,...,245,129]"
    const keypairData = process.env.EXAMPLE_WALLET;
    const programID = Uint8Array.from(JSON.parse(keypairData));
    const walletKeypair = Keypair.fromSecretKey(programID);
    console.log('connected wallet', walletKeypair.publicKey.toString());
    
    // Setup
    const programId = 'dripTrkvSyQKvkyWg7oi4jmeEGMA5scSYowHArJ9Vwk';
    const network = Network.Devnet;
    const clientEnv = ClientEnv.Production;
    const provider = new AnchorProvider(
        new Connection('https://api.devnet.solana.com', 'confirmed'),
        new NodeWallet(walletKeypair),
        AnchorProvider.defaultOptions()
    );
    const drip = Drip.fromNetworkClient(network, provider, programId, clientEnv);
    
    // Devnet Drip USDT
    const tokenA = new PublicKey('H9gBUJs5Kc5zyiKRTzZcYom4Hpj9VPHLy4VzExTVPgxa');
    
    // Given a tokenA, get valid tokenBs
    const tokenBs = await drip.config.getAllTokenBs(tokenA);
    // For the example's sake, lets pick the first token available
    const tokenB = tokenBs[Object.keys(tokenBs)[0]].mint;
    console.log('tokenA', tokenA.toString(), 'tokenB', tokenB.toString());
    
    const vaultProtoConfigs = await drip.config.getSupportedVaultProtoConfigsForPair(
        tokenA,
        tokenB
    );
    // For the example's sake, lets pick the first proto config
    const vaultProtoConfig = vaultProtoConfigs[0];
    console.log(
        'vaultProtoConfig',
        vaultProtoConfig.pubkey.toString(),
        'granularity',
        vaultProtoConfig.granularity.toString()
    );
    
    const vaultPubkey = findVaultPubkey(drip.programId, {
        protoConfig: vaultProtoConfig.pubkey,
        tokenAMint: tokenA,
        tokenBMint: tokenB
    });
    console.log('vault', vaultPubkey.toString());
    
    const dripVault = await drip.getVault(vaultPubkey);
    // Any function from the deposit guide will work here 
    // the specifc one is not relevant, therefore it is not shown
    const positionPubkey = await deposit(dripVault);
    const dripPosition = await drip.getPosition(positionPubkey);
    // ...
}
```

### Withdraw

This function will withdraw all the accrued destination token (token B) for a position. Under the hood it calls instruction `withdrawB`. Note, this function will fail if there is no destination token accrued.

```typescript
const res = await dripPosition.withdrawB();
console.log('withdraw txId', res.id);
```

### Close Position

This function will withdraw all accrued destination token (token B) for a position along with all remaining source token (token A), burn the position nft token, and close the position nft token account (refunding the lamports to the user).

```typescript
const res = await dripPosition.closePosition();
console.log('close position txId', res.id);
```


# Rust Guides

Coming soon :eyes:


# Fee Structure

There are 3 fee's that are charged for a position, they are itemized in the table below. All the fee configs can be viewed on a vault's associated `protoConfig` account.&#x20;

<table><thead><tr><th width="243">Value</th><th width="205">Type</th><th>Description</th></tr></thead><tbody><tr><td>tokenADripTriggerSpread</td><td>Fee in Basis Points.</td><td>This spread is applied on every drip for a vault. This can be thought of as a spread on the users source token (token A) whenever a swap is done. This fee is sent to the user that initiates the swap (can be anyone).</td></tr><tr><td>tokenBWithdrawalSpread</td><td>Fee in Basis Points.</td><td>This spread is applied on the accrued destination asset for a position (token b) and is sent to the vault <code>treasuryTokenBAccount</code>.  </td></tr><tr><td>tokenBReferralSpread</td><td>Fee in Basis Points.</td><td>This spread is applied on the accrued destination asset for a position (token b) and is sent to the referrer that was specified during the deposit instruction. See <a href="/products/drip/typescript-guides/deposit">Deposit</a> for details on how to specify the referrer programatically. </td></tr></tbody></table>

{% hint style="info" %}
If a user deposits, creates a position and closes their position before any drips have occurred, not fees are taken and all of their source tokens (token A) are returned.&#x20;
{% endhint %}


