Skip to content

Deposit and redeem

A deposit buys shares in a term's vault. It is a signal: support for an atom, agreement with a triple, or disagreement with a triple, made through its counter-triple. Redeeming returns shares to the vault in exchange for TRUST. See Vaults and signals for the model and its fees.

Before you begin

You need:

  • the config object with a wallet client, as set up in Publish onchain,
  • an account that holds TRUST, or testnet TRUST, and
  • the identifier of a registered term. To register one, see Publish onchain.

Choose a curve

Every deposit and redemption names a bonding curve, and each term has one vault per curve. Use the protocol's default curve unless your application has a reason to choose another:

import { multiVaultGetBondingCurveConfig } from '@0xintuition/protocol';

const { defaultCurveId } = await multiVaultGetBondingCurveConfig(config);

A term's vault on the default curve opens when the term is created. A vault on another curve opens with the first deposit into it.

Deposit

deposit takes the receiver of the shares, the term, the curve, and the minimum number of shares you accept. The amount to deposit is the transaction's value.

  1. Preview the deposit to see how many shares it buys after fees:

    import { multiVaultPreviewDeposit } from '@0xintuition/protocol';
    import { parseEther } from 'viem';
    
    const amount = parseEther('1');
    
    const [expectedShares] = await multiVaultPreviewDeposit(config, {
      args: [termId, defaultCurveId, amount],
    });

    termId is the identifier of the atom, triple, or counter-triple you deposit into. parseEther('1') is 1 TRUST, in wei.

  2. Set the minimum you accept. The price can move between the preview and the transaction. This example tolerates a 1% change:

    const minShares = (expectedShares * 99n) / 100n;
  3. Send the deposit:

    import { multiVaultDeposit } from '@0xintuition/protocol';
    
    const hash = await multiVaultDeposit(config, {
      args: [account.address, termId, defaultCurveId, minShares],
      value: amount,
    });
    
    await publicClient.waitForTransactionReceipt({ hash });

    account.address is your own address, so the shares are yours.

After the transaction is mined, multiVaultGetShares returns your new balance:

import { multiVaultGetShares } from '@0xintuition/protocol';

const shares = await multiVaultGetShares(config, {
  args: [account.address, termId, defaultCurveId],
});

The amount must be at least the contract's minimum deposit, minDeposit, which you can read with multiVaultGetGeneralConfig. If the deposit would buy fewer shares than minShares, the transaction reverts and you keep your TRUST.

Signal disagreement with a triple

To disagree with a triple, deposit into its counter-triple:

import { calculateCounterTripleId } from '@0xintuition/ids';

const counterTripleId = calculateCounterTripleId(tripleId);

Then deposit into counterTripleId as above. An account can hold shares on only one side of a triple per curve. To change sides, redeem your shares on the other side first.

Redeem

redeem takes the receiver of the TRUST, the term, the curve, the number of shares, and the minimum amount you accept.

  1. Read how many shares you can redeem:

    import { multiVaultMaxRedeem } from '@0xintuition/protocol';
    
    const sharesToRedeem = await multiVaultMaxRedeem(config, {
      args: [account.address, termId, defaultCurveId],
    });

    To redeem part of a position, use a smaller number.

  2. Preview the redemption to see what it pays after fees:

    import { multiVaultPreviewRedeem } from '@0xintuition/protocol';
    
    const [expectedAssets] = await multiVaultPreviewRedeem(config, {
      args: [termId, defaultCurveId, sharesToRedeem],
    });
    
    const minAssets = (expectedAssets * 99n) / 100n;
  3. Send the redemption:

    import { multiVaultRedeem } from '@0xintuition/protocol';
    
    const hash = await multiVaultRedeem(config, {
      args: [account.address, termId, defaultCurveId, sharesToRedeem, minAssets],
    });
    
    await publicClient.waitForTransactionReceipt({ hash });

The TRUST is sent to the receiver, here your own address.

Deposit or redeem in batches

multiVaultDepositBatch and multiVaultRedeemBatch act on several vaults in one transaction. They take one receiver and parallel arrays, one entry per vault:

import { multiVaultDepositBatch } from '@0xintuition/protocol';

const amounts = [parseEther('0.5'), parseEther('0.5')];

const hash = await multiVaultDepositBatch(config, {
  args: [
    account.address,
    [atomId, tripleId],
    [defaultCurveId, defaultCurveId],
    amounts,
    [0n, 0n],
  ],
  value: amounts[0] + amounts[1],
});

The transaction's value must equal the sum of the amounts. The last array holds the minimum shares for each vault. 0n accepts any result, so set real minimums from a preview in production. multiVaultRedeemBatch takes the receiver, the terms, the curves, the shares, and the minimum amounts.

Read the result of a transaction

The Deposited and Redeemed events report the exact outcome. The @0xintuition/protocol event parsers wait for the receipt and decode them:

import { eventParseDeposited } from '@0xintuition/protocol';

const [event] = await eventParseDeposited(publicClient, hash);
event.args.shares; // Shares received
event.args.assetsAfterFees; // TRUST added to the vault, after fees

eventParseRedeemed does the same for redemptions.

Deposit on behalf of another account

By default, only the receiver can deposit for itself or redeem its own shares. An account can allow another address to do either, for example a fee proxy:

import { multiVaultApprove } from '@0xintuition/protocol';

const hash = await multiVaultApprove(config, {
  args: [operatorAddress, 1],
});

operatorAddress is the address you approve. The second argument is the approval type:

ValueAllows the address to
0Nothing. Revokes an approval
1Deposit on your behalf
2Redeem on your behalf
3Deposit and redeem on your behalf

Common errors

ErrorCause
MultiVault_DepositBelowMinimumDepositThe amount is below minDeposit
MultiVault_SlippageExceededThe result is below minShares or minAssets
MultiVault_HasCounterStakeYou hold shares on the other side of this triple, on this curve
MultiVault_InsufficientSharesInVaultYou asked to redeem more shares than you can
MultiVault_SenderNotApprovedThe sender is not approved to deposit for the receiver
MultiVault_RedeemerNotApprovedThe sender is not approved to redeem for the receiver
MultiVaultCore_TermDoesNotExistThe term is not registered