Deposit and Bridge

Interface

/**
 * Parameters required for preparing a deposit and bridge transaction
 * @interface PrepareDepositAndBridgeTransactionDataParams
 * @property {VaultKey} vaultKey - Unique identifier for the target vault
 * @property {string} depositTokenSymbol - Symbol of the token being deposited
 * @property {string} depositAmount - Amount of assets to deposit as a string
 * @property {number | string} sourceChainId - ID of the chain where the deposit originates
 * @property {number | string} destinationChainId - ID of the chain where tokens will be bridged to
 * @property {Address} userAddress - Ethereum address of the user making the deposit
 * @property {number} [slippage] - Maximum acceptable slippage percentage (defaults to DEFAULT_DEPOSIT_SLIPPAGE)
 */
interface PrepareDepositAndBridgeTransactionDataParams {
  depositAmount: string;
  depositTokenSymbol: string;
  destinationChainId: number | string;
  slippage?: number;
  sourceChainId: number | string;
  userAddress: Address;
  vaultKey: VaultKey;
}

/**
 * Result object containing transaction data for a deposit and bridge operation
 * @interface DepositAndBridgeTransactionData
 * @property {typeof TellerAbi} abi - ABI for the Teller contract
 * @property {Address} address - Address of the Teller contract
 * @property {'depositAndBridge'} functionName - Name of the function to call
 * @property {[Address, bigint, bigint, BridgeData]} args - Arguments for the depositAndBridge function:
 *   - depositAsset: Address of the token being deposited
 *   - depositAmount: Amount of tokens to deposit in base units (e.g., wei)
 *   - minimumMint: Minimum amount of vault tokens to receive after slippage
 *   - bridgeData: Data required for cross-chain bridging
 * @property {number} chainId - ID of the chain where the transaction should be executed
 * @property {bigint} value - Amount of native token to send with the transaction (for bridge fees)
 */
interface DepositAndBridgeTransactionData {
  abi: typeof TellerAbi;
  address: Address;
  functionName: 'depositAndBridge';
  args: [Address, bigint, bigint, BridgeData];
  chainId: number;
  value: bigint;
}

Function Overview

import { prepareDepositAndBridgeData, VaultKeys } from '@molecularlabs/nucleus-frontend';
import { mainnet, optimism } from 'viem/chains';

const COOLVAULT_VAULT_KEY = VaultKeys.COOLVAULT;

// Prepare withdrawal and bridge transaction data
const bridgeAndWithdrawData = await prepareBridgeAndWithdrawTransactionData({
  vaultKey: 'bobaeth',
  sourceChainId: 42161, // Arbitrum
  destinationChainId: mainnet.id, // Ethereum mainnet
  userAddress: '0x1234...', // User's wallet address
  wantTokenSymbol: TokenKey.WETH, // Token to receive
  offerAmount: 1.5, // Amount of vault shares to withdraw
  deadline: // Optional: must be passed in whole day values. ex. 1 for 1 day from now
  slippage: 0.005, // Optional: 0.5% slippage
});

const {
  bridgeTransactionData: {
    abi, // Contract ABI (CrossChainTellerBaseAbi)
    address, // Bridge contract address
    functionName, // Bridge function name
    args, // [bridgeAmount, bridgeContractArg]
    chainId, // Chain ID for the bridge transaction
    value, // Amount of native token to send for bridge fees
  },
  withdrawTransactionData: {
    abi: withdrawAbi, // AtomicQueueAbi
    address: withdrawAddress, // AtomicQueue contract address
    functionName: withdrawFunctionName, // 'updateAtomicRequest'
    args: withdrawArgs, // [offerTokenAddress, wantTokenAddress, userRequest]
    chainId: withdrawChainId, // Chain ID for the withdraw transaction
  }
} = bridgeAndWithdrawData;

Viem Example

import { createPublicClient, http, createWalletClient, custom } from 'viem';
import { mainnet, optimism } from 'viem/chains';
import { prepareDepositAndBridgeData, VaultKeys } from '@molecularlabs/nucleus-frontend';

// Example using Viem with MetaMask
const publicClient = createPublicClient({
  chain: mainnet,
  transport: http()
});

const walletClient = createWalletClient({
  chain: mainnet,
  transport: custom(window.ethereum)
});

const COOLVAULT_VAULT_KEY = VaultKeys.COOLVAULT;

async function depositAndBridgeToVault() {
  try {
    // Get user's address
    const [address] = await walletClient.requestAddresses();

    // Prepare deposit and bridge data
    const depositAndBridgeData = await prepareDepositAndBridgeTransactionData({
      vaultKey: COOLVAULT_VAULT_KEY,
      depositTokenSymbol: 'WETH',
      depositAmount: '1.0', // Depositing 1 WETH
      sourceChainId: mainnet.id, // Ethereum Mainnet
      destinationChainId: optimism.id, // Optimism
      userAddress: address,
      slippage: 0.01 // 1% slippage
    });

    // Send the transaction
    const hash = await walletClient.writeContract({
      ...depositAndBridgeData,
      value: depositAndBridgeData.value // Include bridge fee
    });
    
    // Wait for transaction
    const receipt = await publicClient.waitForTransactionReceipt({ hash });
    
    console.log('Deposit and bridge successful:', receipt);
  } catch (error) {
    console.error('Deposit and bridge failed:', error);
  }
}

Wagmi Example

import { useState } from 'react';
import { useAccount, useContractWrite, usePrepareContractWrite, useWaitForTransaction } from 'wagmi';
import { useQuery } from '@tanstack/react-query';
import { mainnet, optimism } from 'viem/chains';
import { prepareDepositAndBridgeData, VaultKeys } from '@molecularlabs/nucleus-frontend';

const COOLVAULT_VAULT_KEY = VaultKeys.COOLVAULT;

function DepositAndBridgeForm() {
  const { address } = useAccount();
  const [amount, setAmount] = useState('');
  
  // Fetch deposit data
  const { data: depositData, isLoading: isPreparingDeposit, error: prepareError } = useQuery({
    queryKey: ['prepareDepositAndBridge', COOLVAULT_VAULT_KEY, amount, address],
    queryFn: async () => {
      if (!amount || !address) return null;
      
      return prepareDepositAndBridgeData({
        vaultKey: COOLVAULT_VAULT_KEY,
        depositTokenSymbol: 'WETH',
        depositAmount: amount,
        sourceChainId: mainnet.id, // Ethereum Mainnet
        destinationChainId: optimism.id, // Optimism
        userAddress: address,
        slippage: 0.01 // optional
      });
    },
    enabled: Boolean(amount && address),
  });

  // Prepare the contract write
  const { config, error: prepareWriteError } = usePrepareContractWrite({
    address: depositData?.address,
    abi: depositData?.abi,
    functionName: depositData?.functionName,
    args: depositData?.args,
    value: depositData?.value,
    enabled: Boolean(depositData),
  });

  // Handle the contract write
  const { write, data: writeData, error: writeError } = useContractWrite(config);

  // Handle transaction status
  const { isLoading: isTransactionPending, isSuccess } = useWaitForTransaction({
    hash: writeData?.hash,
  });

  // Combine all errors
  const error = prepareError || prepareWriteError || writeError;

  return (
    <div className="max-w-md mx-auto p-6 bg-white rounded-xl shadow-lg">
      <h2 className="text-2xl font-bold mb-6">Deposit and Bridge WETH</h2>
      
      {/* Amount Input */}
      <div className="mb-4">
        <label className="block text-sm font-medium text-gray-700 mb-2">
          Amount (WETH)
        </label>
        <input
          type="number"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="0.0"
          className="w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
          disabled={isTransactionPending}
        />
      </div>

      {/* Bridge Details */}
      <div className="mb-6 text-sm text-gray-600">
        <p>From: Ethereum Mainnet</p>
        <p>To: Optimism</p>
        <p>Slippage: 1%</p>
      </div>

      {/* Action Button */}
      <button
        onClick={() => write?.()}
        disabled={!write || isPreparingDeposit || isTransactionPending}
        className={`w-full py-3 px-4 rounded-lg font-medium text-white
          ${(!write || isPreparingDeposit || isTransactionPending)
            ? 'bg-gray-400'
            : 'bg-blue-600 hover:bg-blue-700'
          } transition-colors`}
      >
        {isPreparingDeposit ? (
          'Preparing...'
        ) : isTransactionPending ? (
          'Processing...'
        ) : (
          'Deposit and Bridge'
        )}
      </button>

      {/* Status Messages */}
      {isSuccess && (
        <div className="mt-4 p-4 bg-green-100 text-green-700 rounded-lg">
          Transaction successful! Your tokens are being bridged.
        </div>
      )}

      {error && (
        <div className="mt-4 p-4 bg-red-100 text-red-700 rounded-lg">
          {error.message}
        </div>
      )}

      {/* Transaction Progress */}
      {isTransactionPending && (
        <div className="mt-4">
          <div className="h-2 w-full bg-gray-200 rounded-full overflow-hidden">
            <div className="h-full bg-blue-600 animate-pulse rounded-full" />
          </div>
          <p className="text-sm text-gray-600 mt-2">
            Bridging in progress. Please wait...
          </p>
        </div>
      )}
    </div>
  );
}

export default DepositAndBridgeForm;

Last updated