UpshiftDocs

EVM Actions

Deposit, request withdrawals, claim redemptions, and manage token approvals on EVM vaults with the Upshift SDK.

Overview

EVM write operations require a connected wallet with a signer. The SDK supports all vault versions (evm-0, evm-1, evm-2) and automatically selects the correct contract ABI and function signatures.

Setup

import { ethers } from 'ethers';
import AugustSDK from '@augustdigital/sdk';

// Initialize SDK
const sdk = new AugustSDK({
  appName: '<APP_NAME>', // required
  providers: {
    1: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
  },
});

// Connect wallet and set signer
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
sdk.evm.setSigner(signer);

const userAddress = await signer.getAddress();

Vault Deposit

Deposit tokens into a vault. The SDK automatically handles different vault versions (evm-0, evm-1, evm-2) and adapter deposits.

sdk.evm.vaultDeposit({
  target: string;
  wallet: string;
  amount: string | bigint | number;
  wait?: boolean;
  depositAsset?: string;  // Optional: for adapter deposits
  chainId?: number;       // Optional: for adapter routing
  poolName?: string;      // Optional: for adapter routing
}): Promise<string>

Vault Version Detection

The SDK automatically detects the vault version and uses the correct deposit method:

VersionDeposit FunctionParametersUse Case
evm-0deposit(uint256, address)2 paramsLegacy vaults
evm-1deposit(uint256, address)2 paramsStandard vaults
evm-2deposit(address, uint256, address)3 paramsMulti-asset vaults
AdapterVariousDepends on adapter typeAlternative token deposits

You don't need to specify the version - the SDK detects it automatically from the vault's version field.

Parameters

ParameterTypeRequiredDescription
targetstringYesVault contract address
walletstringYesUser wallet address
amountstring | bigint | numberYesAmount to deposit
waitbooleanNoWait for confirmation (default: false)
depositAssetstringNoToken to deposit (defaults to underlying)
chainIdnumberNoChain ID for adapter routing
poolNamestringNoPool name for adapter routing

Returns

Transaction hash as string

Example: Standard Deposit

// Deposit underlying token
const txHash = await sdk.evm.vaultDeposit({
  target: '0x80E1048eDE66ec4c364b4F22C8768fc657FF6A42',
  wallet: userAddress,
  amount: '100', // 100 tokens
  wait: true,
});

console.log('Deposit successful:', txHash);

How It Works for Each Version

EVM-0 & EVM-1 Vaults (Standard)

Contract Function: deposit(uint256 assets, address receiver)

Behavior:

  • Deposits the vault's underlying token only
  • 2 parameters: amount and receiver
  • Automatic approval of underlying token to vault

Example:

// Upshift USDC (evm-1)
await sdk.evm.vaultDeposit({
  target: '0x80E1048eDE66ec4c364b4F22C8768fc657FF6A42',
  wallet: userAddress,
  amount: '100', // 100 USDC
  wait: true,
});
// SDK calls: vault.deposit(100e6, userAddress)

EVM-2 Vaults (Multi-Asset)

Contract Function: deposit(address assetIn, uint256 amount, address receiver)

Behavior:

  • Accepts multiple whitelisted tokens (listed in vault.depositAssets)
  • 3 parameters: asset address, amount, and receiver
  • Automatic approval of selected token to vault

Example:

// Get vault to see deposit options
const vault = await sdk.getVault({
  vault: '0x18EE038C114a07f4B08b420fb1E4149a4F357249',
  chainId: 1,
});

console.log(
  'Can deposit:',
  vault.depositAssets.map((a) => a.symbol),
);
// Output: ["USDC", "USDT", "DAI"]

// Deposit any whitelisted asset
await sdk.evm.vaultDeposit({
  target: vault.address,
  wallet: userAddress,
  amount: '100',
  depositAsset: '0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT
  chainId: 1,
  wait: true,
});
// SDK calls: vault.deposit(USDT_ADDRESS, 100e6, userAddress)

Note: For EVM-2 vaults, you can optionally specify depositAsset. If omitted, SDK uses the first asset in depositAssets array (usually the primary/underlying token).

Adapter Vaults (Alternative Tokens)

Contract Functions: Various depending on adapter type

Behavior:

  • Enables deposits with tokens beyond the vault's standard accepted tokens
  • Uses wrapper contracts or swap protocols
  • Requires depositAsset, chainId, and sometimes poolName parameters

Adapter Types:

  1. Native Token Adapter (e.g., ETH → wstETH)
    • Wraps native tokens before depositing
    • Uses WrapperAdapter contract
    • Example: Treehouse Growth
  2. Token Wrapper Adapter (e.g., WETH → wstETH)
    • Wraps ERC20 tokens before depositing
    • Uses WrapperAdapter contract
    • Example: Treehouse Growth
  3. Swap Adapter (e.g., USDC → WBTC)
    • Swaps tokens via Paraswap before depositing
    • Uses PoolAdapter contract
    • Example: BTC Multi-Token

Example: Native ETH Deposit

// Treehouse Growth accepts: wstETH, WETH, ETH (via adapter)
await sdk.evm.vaultDeposit({
  target: '0x5Fde59415625401278c4d41C6beFCe3790eb357f',
  wallet: userAddress,
  amount: '1.0', // 1 ETH
  depositAsset: '0x0000000000000000000000000000000000000000', // Native ETH
  chainId: 1,
  poolName: 'Treehouse Growth',
  wait: true,
});
// SDK calls: wrapperAdapter.depositETH() with value

Example: WETH Deposit (via adapter)

await sdk.evm.vaultDeposit({
  target: '0x5Fde59415625401278c4d41C6beFCe3790eb357f',
  wallet: userAddress,
  amount: '1.0',
  depositAsset: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
  chainId: 1,
  poolName: 'Treehouse Growth',
  wait: true,
});
// SDK calls: wrapperAdapter.deposit() after approving WETH

Example: Swap Adapter Deposit

// BTC Multi-Token accepts WBTC but can swap from USDC
await sdk.evm.vaultDeposit({
  target: '0xBTCVaultAddress...',
  wallet: userAddress,
  amount: '10000', // 10,000 USDC
  depositAsset: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
  chainId: 1,
  poolName: 'BTC Multi-Token',
  wait: true,
});
// SDK:
// 1. Gets Paraswap quote (USDC → WBTC)
// 2. Approves USDC to PoolAdapter
// 3. Calls: poolAdapter.swapAndDeposit()

Automatic Detection Flow

// Step 1: Get vault info
const vault = await sdk.getVault({ vault: vaultAddress, chainId: 1 });

// Step 2: SDK checks vault.version
if (vault.version === 'evm-2') {
  // Use 3-param deposit(address, uint256, address)
} else if (depositAsset && depositAsset !== vault.underlying.address) {
  // Use adapter logic
} else {
  // Use 2-param deposit(uint256, address)
}

// Step 3: SDK handles approvals automatically
// Step 4: SDK calls correct contract method

When to Use Each Parameter

ParameterRequiredUse When
targetAlwaysVault address
walletAlwaysUser's address
amountAlwaysDeposit amount
waitOptionalWant to wait for confirmation
depositAssetSometimesUsing adapter OR EVM-2 with non-primary token
chainIdSometimesUsing adapter
poolNameSometimesUsing adapter (helps with routing)

Quick Reference: Vault Versions

How to check which version a vault uses:

const vault = await sdk.getVault({ vault: vaultAddress, chainId: 1 });
console.log('Version:', vault.version); // "evm-0", "evm-1", or "evm-2"
console.log('Has adapters:', vault.depositAssets.length > 1);

Common Vaults by Version:

Vault NameVersionDeposit TokensNotes
Upshift USDCevm-1USDC onlyStandard deposit
Upshift USDTevm-1USDT onlyStandard deposit
Treehouse Growthevm-1wstETH, WETH, ETHHas adapters
Kelp TAC rsETHevm-1rsETH, stETH, ETHx, WETH, ETHHas adapters
Wild USDevm-2USDC, USDT, DAIMulti-asset
BTC Multi-Tokenevm-1WBTC, USDC (via swap)Has swap adapter

Decision Tree

Do you have a depositAsset parameter?

├─ NO → Standard deposit with underlying token
│        ├─ EVM-0/1: 2-param deposit
│        └─ EVM-2: 3-param deposit with first depositAsset

└─ YES → Is depositAsset different from underlying?

         ├─ NO → Standard deposit (same as above)

         └─ YES → Is vault EVM-2 with depositAsset whitelisted?

                  ├─ YES → Multi-asset deposit (3-param)

                  └─ NO → Adapter deposit
                           ├─ Native token? → Wrapper adapter
                           ├─ Different ERC20? → Swap adapter
                           └─ Wrapped version? → Wrapper adapter

Adapter Deposits

Deposit with alternative tokens beyond the vault's underlying asset.

Check Available Tokens

const vault = await sdk.getVault({ vault: vaultAddress, chainId: 1 });

console.log('Supported deposit tokens:');
vault.depositAssets.forEach((asset) => {
  console.log(`- ${asset.symbol}: ${asset.address}`);
});

Deposit with Alternative Token

// Get vault info
const vault = await sdk.getVault({
  vault: '0x5Fde59415625401278c4d41C6beFCe3790eb357f', // Treehouse
  chainId: 1,
});

// Deposit WETH instead of wstETH
const txHash = await sdk.evm.vaultDeposit({
  target: vault.address,
  wallet: userAddress,
  amount: '1.0',
  depositAsset: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
  chainId: 1,
  wait: true,
});

Deposit Native ETH

// Deposit native ETH (zero address)
await sdk.evm.vaultDeposit({
  target: '0x5Fde59415625401278c4d41C6beFCe3790eb357f',
  wallet: userAddress,
  amount: '1.0',
  depositAsset: '0x0000000000000000000000000000000000000000', // Native ETH
  chainId: 1,
  poolName: 'Treehouse Growth',
  wait: true,
});

Supported Adapter Vaults

VaultSupported TokensType
Treehouse GrowthwstETH, WETH, ETHNative deposits
Kelp TAC rsETHstETH, ETHx, WETH, ETHNative deposits
BTC Multi-TokenWBTC, cbBTC, tBTCSwap adapter (Paraswap)
AVAX StrategyWAVAX, AVAXNative deposits

Request Withdrawal

Request to withdraw tokens from a vault. Subject to lag period before claiming.

sdk.evm.vaultRequestRedeem({
  target: string;
  wallet: string;
  amount: string | bigint | number;
  wait?: boolean;
}): Promise<string>

Parameters

ParameterTypeRequiredDescription
targetstringYesVault contract address
walletstringYesUser wallet address
amountstring | bigint | numberYesAmount of shares to redeem
waitbooleanNoWait for confirmation

Returns

Transaction hash as string

Example

// Request to redeem 50 vault shares
const txHash = await sdk.evm.vaultRequestRedeem({
  target: '0x80E1048eDE66ec4c364b4F22C8768fc657FF6A42',
  wallet: userAddress,
  amount: '50',
  wait: true,
});

console.log('Redemption requested:', txHash);
console.log('Wait for lag period before claiming');

// Check when you can claim
const { availableRedemptions } = await sdk.getVaultAvailableRedemptions({
  vault: '0x80E1048eDE66ec4c364b4F22C8768fc657FF6A42',
  wallet: userAddress,
  chainId: 1,
});

Behavior

The SDK automatically:

  1. Detects vault version
  2. Uses correct function signature:
    • EVM-0/1: requestRedeem(uint256, address, address) (3 params)
    • EVM-2: requestRedeem(uint256, address) (2 params)
  3. Converts amount to proper decimals
  4. Submits transaction

Claim Redemption

Claim tokens from a completed redemption request.

sdk.evm.vaultRedeem({
  target: string;
  wallet: string;
  wait?: boolean;
  year: string;
  month: string;
  day: string;
  receiverIndex: string;
}): Promise<string>

Parameters

ParameterTypeRequiredDescription
targetstringYesVault contract address
walletstringYesUser wallet address
yearstringYesYear from redemption request
monthstringYesMonth from redemption request
daystringYesDay from redemption request
receiverIndexstringYesReceiver index
waitbooleanNoWait for confirmation

Returns

Transaction hash as string

Example

// Get available redemptions
const { availableRedemptions } = await sdk.getVaultAvailableRedemptions({
  vault: vaultAddress,
  wallet: userAddress,
  chainId: 1,
});

// Claim first available redemption
if (availableRedemptions.length > 0) {
  const redemption = availableRedemptions[0];

  const txHash = await sdk.evm.vaultRedeem({
    target: vaultAddress,
    wallet: userAddress,
    year: redemption.year.raw,
    month: redemption.month.raw,
    day: redemption.day.raw,
    receiverIndex: '0',
    wait: true,
  });

  console.log('Claimed:', redemption.amount.normalized, 'tokens');
}

Token Approval

Approve vault to spend tokens. Usually called automatically by vaultDeposit.

sdk.evm.vaultApprove({
  target: string;
  wallet: string;
  amount: string | bigint | number;
  wait?: boolean;
}): Promise<string | undefined>

Returns

  • Transaction hash if approval was needed
  • undefined if allowance already sufficient

Example

// Manually approve before deposit
const txHash = await sdk.evm.vaultApprove({
  target: vaultAddress,
  wallet: userAddress,
  amount: '1000',
  wait: true,
});

if (txHash) {
  console.log('Approval tx:', txHash);
} else {
  console.log('Already approved');
}

Check Allowance

Check current token allowance for a vault.

sdk.evm.vaultAllowance({
  target: string;
  wallet: string;
}): Promise<INormalizedNumber>

Example

const allowance = await sdk.evm.vaultAllowance({
  target: vaultAddress,
  wallet: userAddress,
});

console.log('Current allowance:', allowance.normalized);

if (BigInt(allowance.raw) < BigInt(depositAmount)) {
  console.log('Need to approve more');
}

Examples

Complete Deposit Flow

// 1. Get vault and check options
const vault = await sdk.getVault({ vault: vaultAddress, chainId: 1 });

console.log('Deposit options:');
vault.depositAssets.forEach((asset) => {
  console.log(`- ${asset.symbol}`);
});

// 2. Check if vault accepts deposits
if (vault.isDepositPaused) {
  throw new Error('Vault deposits are paused');
}

// 3. Check user balance
const tokenContract = new ethers.Contract(
  vault.depositAssets[0].address,
  ['function balanceOf(address) view returns (uint256)'],
  provider,
);
const balance = await tokenContract.balanceOf(userAddress);

// 4. Deposit
const txHash = await sdk.evm.vaultDeposit({
  target: vault.address,
  wallet: userAddress,
  amount: '100',
  wait: true,
});

console.log('Success:', txHash);

Complete Withdrawal Flow

// 1. Check user position
const position = await sdk.getVaultPositions({
  vault: vaultAddress,
  wallet: userAddress,
  chainId: 1,
});

if (position[0].walletBalance.raw === '0') {
  throw new Error('No balance to withdraw');
}

// 2. Request redemption
const requestTx = await sdk.evm.vaultRequestRedeem({
  target: vaultAddress,
  wallet: userAddress,
  amount: '50',
  wait: true,
});

console.log('Redemption requested:', requestTx);

// 3. Wait for lag period...
await new Promise((resolve) => setTimeout(resolve, vault.lagDuration * 1000));

// 4. Check if ready to claim
const { availableRedemptions } = await sdk.getVaultAvailableRedemptions({
  vault: vaultAddress,
  wallet: userAddress,
  chainId: 1,
});

// 5. Claim
if (availableRedemptions.length > 0) {
  const redemption = availableRedemptions[0];
  const claimTx = await sdk.evm.vaultRedeem({
    target: vaultAddress,
    wallet: userAddress,
    year: redemption.year.raw,
    month: redemption.month.raw,
    day: redemption.day.raw,
    receiverIndex: '0',
    wait: true,
  });

  console.log('Claimed:', claimTx);
}

Multi-Asset Vault Deposit

// Get EVM-2 vault
const vault = await sdk.getVault({
  vault: '0x18EE038C114a07f4B08b420fb1E4149a4F357249',
  chainId: 1,
});

console.log('Vault version:', vault.version); // "evm-2"
console.log('Deposit assets:', vault.depositAssets.length);

// Deposit any whitelisted asset
const selectedAsset = vault.depositAssets[0];

const txHash = await sdk.evm.vaultDeposit({
  target: vault.address,
  wallet: userAddress,
  amount: '100',
  depositAsset: selectedAsset.address, // Required for evm-2
  chainId: 1,
  wait: true,
});

Error Handling

try {
  await sdk.evm.vaultDeposit({
    target: vaultAddress,
    wallet: userAddress,
    amount: '100',
    wait: true,
  });
} catch (error) {
  if (error.message.includes('insufficient balance')) {
    console.error('Not enough tokens');
  } else if (error.message.includes('Deposit failed')) {
    console.error('Transaction reverted');
  } else if (error.message.includes('user rejected')) {
    console.error('User cancelled transaction');
  } else {
    console.error('Error:', error.message);
  }
}

Best Practices

1. Always Check Vault Status

const vault = await sdk.getVault({ vault, chainId });

if (vault.isDepositPaused) {
  throw new Error('Deposits are currently paused');
}

if (vault.isWithdrawalPaused) {
  throw new Error('Withdrawals are currently paused');
}

2. Verify Deposit Cap

const vault = await sdk.getVault({ vault, chainId });

const remaining = BigInt(vault.maxSupply.raw) - BigInt(vault.totalSupply.raw);
console.log(
  'Remaining capacity:',
  ethers.formatUnits(remaining, vault.decimals),
);

3. Show User Expected Output

// For standard deposits, use previewDeposit
const vaultContract = new ethers.Contract(
  vaultAddress,
  ['function previewDeposit(uint256) view returns (uint256)'],
  provider,
);

const expectedShares = await vaultContract.previewDeposit(
  ethers.parseUnits('100', vault.decimals),
);

console.log(
  'You will receive:',
  ethers.formatUnits(expectedShares, vault.decimals),
  'shares',
);