Skip to main content

Migrating SDK from v1.5 to v2.0

This guide helps you migrate your code from v1.x to v2.0.0-alpha of the Intuition TypeScript packages. This is a major version update with significant breaking changes due to the underlying contract migration from EthMultiVault to MultiVault.

Contract Migration Overview​

The core smart contract has been upgraded from EthMultiVault to MultiVault, introducing significant architectural changes that impact all TypeScript libraries built on top.

Key Contract Changes​

1. ID System Migration​

  • EthMultiVault: Uses uint256 for atom/triple IDs
  • MultiVault: Uses bytes32 for term IDs (atoms and triples are now "terms")

2. Terminology Changes​

  • EthMultiVault: Atoms and Triples as separate entities
  • MultiVault: Unified "Terms" concept (atoms and triples are both terms)
  • EthMultiVault: Vault IDs
  • MultiVault: Term IDs with Curve IDs for bonding curves

3. Bonding Curve Integration​

  • EthMultiVault: Limited bonding curve support
  • MultiVault: Full bonding curve integration with curve IDs for all operations

Breaking Changes Overview​

Package Version Updates​

PackagePrevious VersionNew Version
@0xintuition/protocol1.0.0-alpha.12.0.0
@0xintuition/sdk1.0.0-alpha.32.0.0
@0xintuition/graphql1.0.0-alpha.32.0.0
@0xintuition/cli0.0.22.0.0

1. Contract Migration Impact​

Contract Function Mapping​

The migration from EthMultiVault to MultiVault requires updating all contract interactions. Here's the complete function mapping:

Core Creation Functions​

Atom Creation​
// EthMultiVault
function createAtom(bytes atomUri) payable returns (uint256)
function batchCreateAtom(bytes[] atomUris) payable returns (uint256[])

// MultiVault
function createAtoms(bytes[] data, uint256[] assets) payable returns (bytes32[])
Triple Creation​
// EthMultiVault
function createTriple(uint256 subjectId, uint256 predicateId, uint256 objectId) payable returns (uint256)
function batchCreateTriple(uint256[] subjectIds, uint256[] predicateIds, uint256[] objectIds) payable returns (uint256[])

// MultiVault
function createTriples(bytes32[] subjectIds, bytes32[] predicateIds, bytes32[] objectIds, uint256[] assets) payable returns (bytes32[])

Deposit Functions​

EthMultiVault​
function depositAtom(address receiver, uint256 id) payable returns (uint256)
function depositTriple(address receiver, uint256 id) payable returns (uint256)
function batchDeposit(address receiver, uint256[] termIds, uint256[] amounts) payable returns (uint256[])
MultiVault​
function deposit(address receiver, bytes32 termId, uint256 curveId, uint256 minShares) payable returns (uint256)
function depositBatch(address receiver, bytes32[] termIds, uint256[] curveIds, uint256[] assets, uint256[] minShares) payable returns (uint256[])

Redeem Functions​

EthMultiVault​
function redeemAtom(uint256 shares, address receiver, uint256 id) returns (uint256)
function redeemTriple(uint256 shares, address receiver, uint256 id) returns (uint256)
function batchRedeem(uint256 percentage, address receiver, uint256[] ids) returns (uint256[])
MultiVault​
function redeem(address receiver, bytes32 termId, uint256 curveId, uint256 shares, uint256 minAssets) returns (uint256)
function redeemBatch(address receiver, bytes32[] termIds, uint256[] curveIds, uint256[] shares, uint256[] minAssets) returns (uint256[])

Contract Address Changes: EthMultiVault β†’ MultiVault​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import { EthMultiVaultAbi } from '@0xintuition/protocol'
import { getEthMultiVaultAddress } from '@0xintuition/sdk'

const address = getEthMultiVaultAddress(chainId)

After:

import { intuitionTestnet, MultiVaultAbi } from '@0xintuition/protocol'
import { getMultiVaultAddressFromChainId } from '@0xintuition/sdk'

const address = getMultiVaultAddressFromChainId(intuitionTestnet.id)

Contract Event Changes​

EthMultiVault Events​

event AtomCreated(address indexed creator, address indexed atomWallet, bytes atomData, uint256 vaultId)
event TripleCreated(address indexed creator, uint256 subjectId, uint256 predicateId, uint256 objectId, uint256 vaultId)

MultiVault Events​

event AtomCreated(address indexed creator, bytes32 indexed termId, bytes atomData, address atomWallet)
event TripleCreated(address indexed creator, bytes32 indexed termId, bytes32 subjectId, bytes32 predicateId, bytes32 objectId)

Data Structure Migration​

ID Handling Update​

Before:

This Before block intentionally preserves the removed v1 numeric-ID shape for historical comparison and is illustrative rather than copy-paste code for the current package.

const atomId: bigint = 123n
const tripleId: bigint = 456n

After:

import type { Hex } from 'viem'

const atomId: Hex =
'0x906527aae4af914b1ac01ff9adfdda5dafde3b5e21f84045e0660b0a15c07769'
const tripleId: Hex =
'0xc4e64dbc3d69293d28259653d9b15d2ab3f6aa1aa0b1a489e5250974cd089730'

Query Functions​

// EthMultiVault
function atoms(uint256 atomId) view returns (bytes)
function getTripleAtoms(uint256 id) view returns (uint256, uint256, uint256)

// MultiVault
function atom(bytes32 atomId) view returns (bytes)
function getAtom(bytes32 atomId) view returns (bytes)
function triple(bytes32 tripleId) view returns (bytes32, bytes32, bytes32)
function getTriple(bytes32 tripleId) view returns (bytes32, bytes32, bytes32)

Share and Asset Conversions​

// EthMultiVault
function convertToShares(uint256 assets, uint256 id) view returns (uint256)
function convertToAssets(uint256 shares, uint256 id) view returns (uint256)

// MultiVault
function convertToShares(bytes32 termId, uint256 curveId, uint256 assets) view returns (uint256)
function convertToAssets(bytes32 termId, uint256 curveId, uint256 shares) view returns (uint256)

New MultiVault Features​

1. Utilization Tracking​

import {
multiVaultGetTotalUtilizationForEpoch,
multiVaultGetUserUtilizationForEpoch,
type ReadConfig,
} from '@0xintuition/protocol'
import type { Address } from 'viem'

async function getEpochUtilization(
config: ReadConfig,
userAddress: Address,
epoch: bigint,
) {
const userUtilization = await multiVaultGetUserUtilizationForEpoch(config, {
args: [userAddress, epoch],
})
const totalUtilization = await multiVaultGetTotalUtilizationForEpoch(config, {
args: [epoch],
})

return { userUtilization, totalUtilization }
}

2. Epoch System​

import {
multiVaultCurrentEpoch,
multiVaultGetUserLastActiveEpoch,
type ReadConfig,
} from '@0xintuition/protocol'
import type { Address } from 'viem'

async function getEpochState(config: ReadConfig, userAddress: Address) {
const currentEpoch = await multiVaultCurrentEpoch(config)
const lastActiveEpoch = await multiVaultGetUserLastActiveEpoch(config, {
args: [userAddress],
})

return { currentEpoch, lastActiveEpoch }
}

3. Enhanced Fee Management​

import { MultiVaultAbi, type WriteConfig } from '@0xintuition/protocol'
import type { Address, Hex } from 'viem'

async function readAndClaimFees(
config: WriteConfig,
atomWallet: Address,
termId: Hex,
epoch: bigint,
) {
const accumulatedFees = await config.publicClient.readContract({
address: config.address,
abi: MultiVaultAbi,
functionName: 'accumulatedAtomWalletDepositFees',
args: [atomWallet],
})
const protocolFees = await config.publicClient.readContract({
address: config.address,
abi: MultiVaultAbi,
functionName: 'accumulatedProtocolFees',
args: [epoch],
})
const { request } = await config.publicClient.simulateContract({
account: config.walletClient.account,
address: config.address,
abi: MultiVaultAbi,
functionName: 'claimAtomWalletDepositFees',
args: [termId],
})
const transactionHash = await config.walletClient.writeContract(request)

return { accumulatedFees, protocolFees, transactionHash }
}

4. Improved Preview Functions​

import {
multiVaultPreviewAtomCreate,
multiVaultPreviewDeposit,
type WriteConfig,
} from '@0xintuition/protocol'
import type { Hex } from 'viem'

async function previewVaultOperations(
config: WriteConfig,
termId: Hex,
curveId: bigint,
assets: bigint,
) {
const [depositShares, depositAssetsAfterFees] =
await multiVaultPreviewDeposit(config, {
args: [termId, curveId, assets],
})
const [atomShares, atomAssetsAfterFixedFees, atomAssetsAfterFees] =
await multiVaultPreviewAtomCreate(config, {
args: [termId, assets],
})

return {
depositShares,
depositAssetsAfterFees,
atomShares,
atomAssetsAfterFixedFees,
atomAssetsAfterFees,
}
}

2. TypeScript Library Changes​

Protocol Package (@0xintuition/protocol)​

Atom Creation: Singular β†’ Plural​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import {
createAtom,
createAtomCalculateBaseCost,
createAtomEncode,
} from '@0xintuition/protocol'

// Single atom creation
await createAtom(config, { args: [atomUri], value })

// Encoding
const encodedData = createAtomEncode(atomUri)

// Cost calculation
const cost = await createAtomCalculateBaseCost(config)

After:

The payable multiVaultCreateAtoms wrapper is pending the post-publish SDK resync, so this deposit-value-coupled migration example is excluded from copy-paste typechecking until that package shape is available.

import {
multiVaultCreateAtoms,
multiVaultCreateAtomsEncode,
multiVaultGetAtomCost,
type WriteConfig,
} from '@0xintuition/protocol'
import { toHex } from 'viem'

async function createAtoms(config: WriteConfig, atomUris: string[]) {
const atomCost = await multiVaultGetAtomCost(config)
const atomData = atomUris.map((uri) => toHex(uri))
const assets = atomData.map(() => atomCost)
const value = assets.reduce((total, amount) => total + amount, 0n)

const transactionHash = await multiVaultCreateAtoms(config, {
args: [atomData, assets],
value,
})
const encodedData = multiVaultCreateAtomsEncode(atomData, assets)

return { transactionHash, encodedData, atomCost }
}

Triple Creation: Singular β†’ Plural​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import {
createTriple,
createTripleCalculateBaseCost,
createTripleEncode,
} from '@0xintuition/protocol'

await createTriple(config, {
args: [subjectId, predicateId, objectId],
value,
})

const encodedData = createTripleEncode(subjectId, predicateId, objectId)
const cost = await createTripleCalculateBaseCost(config)

After:

The payable multiVaultCreateTriples wrapper is pending the post-publish SDK resync, so this deposit-value-coupled migration example is excluded from copy-paste typechecking until that package shape is available.

import {
multiVaultCreateTriples,
multiVaultCreateTriplesEncode,
multiVaultGetTripleCost,
type WriteConfig,
} from '@0xintuition/protocol'
import type { Hex } from 'viem'

async function createTriples(
config: WriteConfig,
subjectIds: Hex[],
predicateIds: Hex[],
objectIds: Hex[],
) {
if (
subjectIds.length !== predicateIds.length ||
subjectIds.length !== objectIds.length
) {
throw new Error('Subject, predicate, and object arrays must have equal length')
}

const tripleCost = await multiVaultGetTripleCost(config)
const assets = subjectIds.map(() => tripleCost)
const value = assets.reduce((total, amount) => total + amount, 0n)

const transactionHash = await multiVaultCreateTriples(config, {
args: [subjectIds, predicateIds, objectIds, assets],
value,
})
const encodedData = multiVaultCreateTriplesEncode(
subjectIds,
predicateIds,
objectIds,
assets,
)

return { transactionHash, encodedData, tripleCost }
}

Deposit and Redeem Simplification​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import {
depositAtom,
depositAtomEncode,
depositTriple,
depositTripleEncode,
redeemAtom,
redeemAtomEncode,
redeemTriple,
redeemTripleEncode,
} from '@0xintuition/protocol'

// Separate functions for atoms and triples
await depositAtom(config, { args: [receiver, atomId], value })
await depositTriple(config, { args: [receiver, tripleId], value })
await redeemAtom(config, { args: [shares, receiver, atomId] })
await redeemTriple(config, { args: [shares, receiver, tripleId] })

After:

The payable deposit wrapper is pending the post-publish SDK resync, so this deposit-value-coupled migration example is excluded from copy-paste typechecking until that package shape is available.

import type { Address, Hex } from 'viem'

// Prepare the current MultiVault inputs without calling the pending SDK wrapper.
function prepareVaultCalls(
receiver: Address,
termId: Hex,
curveId: bigint,
assets: bigint,
minShares: bigint,
shares: bigint,
minAssets: bigint,
) {
const depositCall = {
args: [receiver, termId, curveId, minShares],
value: assets,
} as const
const redeemArgs = [
receiver,
termId,
curveId,
shares,
minAssets,
] as const

return { depositCall, redeemArgs }
}

Batch Operations Renamed​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import {
batchCreateAtom,
batchCreateTriple,
batchDepositCurve,
batchRedeemCurve,
} from '@0xintuition/protocol'

After:

import {
multiVaultCreateAtoms, // Replaces batchCreateAtom
multiVaultCreateTriples, // Replaces batchCreateTriple
multiVaultDepositBatch, // Replaces batchDepositCurve
multiVaultRedeemBatch, // Replaces batchRedeemCurve
} from '@0xintuition/protocol'

Multicall Function Name​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import { multiCallIntuitionConfigs } from '@0xintuition/protocol'

const config = await multiCallIntuitionConfigs({ address, publicClient })

After:

import {
multiVaultMultiCallIntuitionConfigs,
type ReadConfig,
} from '@0xintuition/protocol'

async function getMultiVaultConfig(config: ReadConfig) {
return multiVaultMultiCallIntuitionConfigs(config)
}

Removed EthMultiVault API​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import { EthMultiVault } from '@0xintuition/protocol'

const ethMultiVault = new EthMultiVault({ publicClient, walletClient })
const result = await ethMultiVault.createAtom('hello')

After:

The payable multiVaultCreateAtoms wrapper is pending the post-publish SDK resync, so this deposit-value-coupled migration example is excluded from copy-paste typechecking until that package shape is available.

import {
getMultiVaultAddressFromChainId,
intuitionTestnet,
multiVaultCreateAtoms,
multiVaultGetAtomCost,
type WriteConfig,
} from '@0xintuition/protocol'
import { toHex } from 'viem'

async function createHelloAtom(
clients: Omit<WriteConfig, 'address'>,
) {
const config: WriteConfig = {
...clients,
address: getMultiVaultAddressFromChainId(intuitionTestnet.id),
}
const atomCost = await multiVaultGetAtomCost(config)

return multiVaultCreateAtoms(config, {
args: [[toHex('hello')], [atomCost]],
value: atomCost,
})
}

Bonding Curve Integration​

The new MultiVault contract requires curve IDs for all operations:

import {
multiVaultGetBondingCurveConfig,
type ReadConfig,
} from '@0xintuition/protocol'

async function getDefaultCurveId(config: ReadConfig) {
const { defaultCurveId } = await multiVaultGetBondingCurveConfig(config)
return defaultCurveId
}

Pass that curve ID to deposit and redeem operations. The payable deposit wrapper is pending the post-publish SDK resync, so this value-forwarding example is excluded from copy-paste typechecking until that package shape is available.

import {
multiVaultDeposit,
multiVaultGetBondingCurveConfig,
type WriteConfig,
} from '@0xintuition/protocol'
import type { Address, Hex } from 'viem'

async function depositWithDefaultCurve(
config: WriteConfig,
receiver: Address,
termId: Hex,
assets: bigint,
minShares: bigint,
) {
const { defaultCurveId } = await multiVaultGetBondingCurveConfig(config)

return multiVaultDeposit(config, {
args: [receiver, termId, defaultCurveId, minShares],
value: assets,
})
}

Migration Steps​

Step 1: Update Function Calls​

Creating Atoms​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

const atomId = await ethMultiVault.createAtom(atomData, { value: fee })

After:

The payable multiVaultCreateAtoms wrapper is pending the post-publish SDK resync, so this deposit-value-coupled migration example is excluded from copy-paste typechecking until that package shape is available.

import {
multiVaultCreateAtoms,
type WriteConfig,
} from '@0xintuition/protocol'
import type { Hex } from 'viem'

async function createMigratedAtom(
config: WriteConfig,
atomData: Hex,
assets: bigint,
) {
return multiVaultCreateAtoms(config, {
args: [[atomData], [assets]],
value: assets,
})
}
Depositing​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

const shares = await ethMultiVault.depositAtom(receiver, atomId, {
value: assets,
})

After:

The payable deposit wrapper is pending the post-publish SDK resync, so this value-forwarding migration example is excluded from copy-paste typechecking until that package shape is available.

import { multiVaultDeposit, type WriteConfig } from '@0xintuition/protocol'
import type { Address, Hex } from 'viem'

async function depositIntoMigratedVault(
config: WriteConfig,
receiver: Address,
termId: Hex,
curveId: bigint,
assets: bigint,
minShares: bigint,
) {
return multiVaultDeposit(config, {
args: [receiver, termId, curveId, minShares],
value: assets,
})
}
Redeeming​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

const assets = await ethMultiVault.redeemAtom(shares, receiver, atomId)

After:

import { multiVaultRedeem, type WriteConfig } from '@0xintuition/protocol'
import type { Address, Hex } from 'viem'

async function redeemFromMigratedVault(
config: WriteConfig,
receiver: Address,
termId: Hex,
curveId: bigint,
shares: bigint,
minAssets: bigint,
) {
return multiVaultRedeem(config, {
args: [receiver, termId, curveId, shares, minAssets],
})
}

3. SDK Package Changes (@0xintuition/sdk)​

SDK read helpers use the mainnet GraphQL API by default. Configure the endpoint once before the migrated read examples; use API_URL_DEV for Intuition Testnet or API_URL_PROD for Mainnet:

import { configureSdk } from '@0xintuition/sdk'
import { API_URL_DEV } from '@0xintuition/graphql'

configureSdk({ apiUrl: API_URL_DEV })

SDK atom creation helpers dynamically fetch and forward the required atom base cost. Any optional amount is an additional TRUST/tTRUST deposit (signal), not the base cost itself.

API Function Renaming​

Before:

This Before block intentionally preserves the removed v1 API for historical comparison and is illustrative rather than copy-paste code for the current package.

import { getAtom, getTriple } from '@0xintuition/sdk'

const atomData = await getAtom('124862')
const tripleData = await getTriple('54670')

After:

import {
configureSdk,
getAtomDetails,
getTripleDetails,
} from '@0xintuition/sdk'
import { API_URL_DEV } from '@0xintuition/graphql'

configureSdk({ apiUrl: API_URL_DEV })

const atomData = await getAtomDetails(
'0x906527aae4af914b1ac01ff9adfdda5dafde3b5e21f84045e0660b0a15c07769',
)
const tripleData = await getTripleDetails(
'0xc4e64dbc3d69293d28259653d9b15d2ab3f6aa1aa0b1a489e5250974cd089730',
)

Triple Creation Parameter Changes​

Before:

This Before block preserves the pre-v3 call shape of createTripleStatement for historical comparison. The helper still exists and is payable, so this deposit-value-coupled example is excluded from copy-paste typechecking pending the post-publish SDK resync.

import { createTripleStatement } from '@0xintuition/sdk'

const triple = await createTripleStatement(config, {
args: [subjectVaultId, predicateVaultId, objectVaultId],
depositAmount: 1000000000000000000n, // Optional
})

After:

The payable createTripleStatement example is pending the post-publish SDK resync, so this deposit-value-coupled migration example is excluded from copy-paste typechecking until that package shape is available.

import {
createTripleStatement,
type WriteConfig,
} from '@0xintuition/sdk'
import type { Hex } from 'viem'

async function createMigratedTriple(
config: WriteConfig,
subjectId: Hex,
predicateId: Hex,
objectId: Hex,
) {
const assets = 1000000000000000000n

return createTripleStatement(config, {
args: [[subjectId], [predicateId], [objectId], [assets]],
value: assets,
})
}

4. Configuration Changes​

EthMultiVault Config​

struct GeneralConfig {
address admin;
address protocolMultisig;
uint256 feeDenominator;
uint256 minDeposit;
uint256 minShare;
uint256 atomUriMaxLength;
uint256 decimalPrecision;
uint256 minDelay;
}

MultiVault Config​

struct GeneralConfig {
address admin;
address protocolMultisig;
uint256 feeDenominator;
address trustBonding; // New
uint256 minDeposit;
uint256 minShare;
uint256 atomDataMaxLength; // Renamed
uint256 decimalPrecision;
// minDelay removed
}

5. Removed Functions​

The following functions have been removed and replaced:

Protocol Package​

  • createAtom β†’ createAtoms
  • createTriple β†’ createTriples
  • batchCreateAtom β†’ createAtoms
  • batchCreateTriple β†’ createTriples
  • depositAtom / depositTriple β†’ deposit
  • redeemAtom / redeemTriple β†’ redeem
  • createAtomCalculateBaseCost β†’ getAtomCost
  • createTripleCalculateBaseCost β†’ getTripleCost
  • All curve-specific functions β†’ depositBatch / redeemBatch
  • atoms-by-hash.ts file completely removed

SDK Package​

  • createThing β†’ createAtomFromThing
  • createEthereumAccount β†’ createAtomFromEthereumAccount
  • getEthMultiVaultAddress β†’ getMultiVaultAddressFromChainId
  • getAtom β†’ getAtomDetails
  • getTriple β†’ getTripleDetails

6. Breaking Changes Summary​

  1. All IDs changed from uint256 to bytes32
  2. Curve ID parameter required for most operations
  3. Batch functions have different signatures
  4. Event structures updated
  5. Some functions renamed or merged
  6. New slippage protection with minShares/minAssets parameters

7. Best Practices​

  1. Always use the default curve ID unless you have specific bonding curve requirements
  2. Implement proper slippage protection with min/max parameters
  3. Handle the new epoch system for utilization tracking
  4. Update your event listeners to match new event structures
  5. Use preview functions to estimate outcomes before transactions

πŸ“ Summary​

This major version update consolidates and simplifies the API while adding new functionality. The main changes are:

  • Contract Migration: EthMultiVault β†’ MultiVault with architectural improvements
  • ID System: Changed from uint256 to bytes32 for all term identifiers
  • Bonding Curves: Full integration requiring curve IDs for all operations
  • Singular β†’ Plural: Functions now support batch operations by default
  • Unified APIs: Simplified deposit/redeem functions for all vault types
  • Enhanced Features: New utilization tracking, epoch system, and preview functions
  • Event Updates: Improved event parsing with new event structures

Take your time with the migration and test thoroughly. The new API is more powerful and consistent, providing a better developer experience.