Migration Guide: v3.x to v4.0
GridPlus SDK v4.0.0 introduces significant improvements focused on modernization, type safety, and developer experience. This guide will help you migrate from v3.x to v4.0.0.
๐จ Breaking Changes Summaryโ
Core Dependency Migrationโ
v3.x used: ethers.js and @ethereumjs/tx
v4.0 uses: viem and zod
This change affects:
- Transaction object format
- Transaction serialization
- Type definitions
- Validation patterns
New Features in v4.0โ
- โ EIP-7702 Support: Account abstraction authorization signing
- โ
Bitcoin XPUB Helpers:
fetchBtcXpub,fetchBtcYpub,fetchBtcZpub - โ Zod Validation: Automatic transaction validation with clear error messages
- โ
CLI Pairing Tool:
npm run pair-devicefor easy setup - โ Viem Integration: Native support for modern Ethereum tooling
- โ Improved Testing: Foundry/Anvil integration for local development
๐ฆ Installationโ
Update Your Dependenciesโ
# Remove old dependencies
npm uninstall ethers @ethereumjs/tx
# Install v4.0
npm install gridplus-sdk@^4.0.0 viem
Update package.jsonโ
{
"dependencies": {
"gridplus-sdk": "^4.0.0",
"viem": "^2.31.0"
}
}
๐ Transaction Signing Migrationโ
v3.x (Ethers.js)โ
import { ethers } from 'ethers';
// Build transaction with ethers
const tx = {
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: ethers.utils.parseEther('0.1'),
gasLimit: 21000,
maxFeePerGas: ethers.utils.parseUnits('20', 'gwei'),
maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'),
nonce: 0,
chainId: 1,
type: 2, // EIP-1559
};
// Sign with SDK
const result = await client.sign({
currency: 'ETH',
data: tx,
});
v4.0 (Viem)โ
import { sign } from 'gridplus-sdk/api/signing';
import { parseEther, parseGwei } from 'viem';
// Build transaction with viem
const tx = {
type: 'eip1559',
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: parseEther('0.1'),
gas: 21000n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 0,
chainId: 1,
};
// Sign with SDK
const result = await sign(tx);
Key Differencesโ
| Aspect | v3.x (Ethers) | v4.0 (Viem) |
|---|---|---|
| Type field | type: 2 | type: 'eip1559' |
| Value parsing | ethers.utils.parseEther() | parseEther() |
| Gas field | gasLimit | gas |
| BigNumber | BigNumber class | Native bigint |
| Import | ethers package | viem package |
๐ Transaction Typesโ
Legacy Transactionsโ
v3.xโ
const tx = {
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: ethers.utils.parseEther('0.1'),
gasPrice: ethers.utils.parseUnits('20', 'gwei'),
gasLimit: 21000,
nonce: 0,
chainId: 1,
type: 0,
};
v4.0โ
const tx = {
type: 'legacy',
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: parseEther('0.1'),
gasPrice: parseGwei('20'),
gasLimit: 21000n,
nonce: 0,
chainId: 1,
};
EIP-1559 Transactionsโ
v3.xโ
const tx = {
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: ethers.utils.parseEther('0.1'),
maxFeePerGas: ethers.utils.parseUnits('20', 'gwei'),
maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'),
gasLimit: 21000,
nonce: 0,
chainId: 1,
type: 2,
};
v4.0โ
const tx = {
type: 'eip1559',
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: parseEther('0.1'),
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
gas: 21000n,
nonce: 0,
chainId: 1,
};
EIP-2930 (Access List)โ
v3.xโ
const tx = {
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: 0,
gasPrice: ethers.utils.parseUnits('20', 'gwei'),
gasLimit: 100000,
nonce: 0,
chainId: 1,
type: 1,
accessList: [
{
address: '0x...',
storageKeys: ['0x...'],
},
],
};
v4.0โ
const tx = {
type: 'eip2930',
to: '0xe242e54155b1abc71fc118065270cecaaf8b7768',
value: 0n,
gasPrice: parseGwei('20'),
gasLimit: 100000n,
nonce: 0,
chainId: 1,
accessList: [
{
address: '0x...',
storageKeys: ['0x...'],
},
],
};
๐ Client Setup & Pairingโ
v3.x Patternโ
import { Client } from 'gridplus-sdk';
const client = new Client({
name: 'My App',
crypto: savedCrypto, // Manually managed
});
const isPaired = await client.connect('ABC123');
if (!isPaired) {
const secret = prompt('Enter pairing code');
await client.pair(secret);
}
v4.0 Pattern (Functional API)โ
import { setup, pair } from 'gridplus-sdk';
const isPaired = await setup({
name: 'My App',
deviceId: 'ABC123',
password: 'my-secure-password',
getStoredClient: () => localStorage.getItem('lattice-client'),
setStoredClient: (client) => localStorage.setItem('lattice-client', client),
});
if (!isPaired) {
const secret = prompt('Enter pairing code');
await pair(secret);
}
Key Improvementsโ
- Automatic state management: Storage callbacks handle persistence
- Simpler API: No manual crypto object management
- Type safety: Full TypeScript support
- Better error messages: Zod validation provides clear feedback
๐ช Bitcoin Address Helpersโ
v3.x (Manual Path Construction)โ
import { fetchAddresses, HARDENED_OFFSET } from 'gridplus-sdk';
// Legacy addresses
const btcLegacy = await fetchAddresses({
startPath: [
HARDENED_OFFSET + 44,
HARDENED_OFFSET + 0,
HARDENED_OFFSET + 0,
0,
0,
],
n: 5,
});
// Segwit addresses
const btcSegwit = await fetchAddresses({
startPath: [
HARDENED_OFFSET + 84,
HARDENED_OFFSET + 0,
HARDENED_OFFSET + 0,
0,
0,
],
n: 5,
});
v4.0 (Convenience Helpers)โ
import {
fetchBtcLegacyAddresses,
fetchBtcSegwitAddresses,
fetchBtcWrappedSegwitAddresses,
fetchBtcXpub,
fetchBtcYpub,
fetchBtcZpub,
} from 'gridplus-sdk/api/addresses';
// Legacy addresses (1...)
const btcLegacy = await fetchBtcLegacyAddresses(5);
// Native Segwit addresses (bc1...)
const btcSegwit = await fetchBtcSegwitAddresses(5);
// Wrapped Segwit addresses (3...)
const btcWrapped = await fetchBtcWrappedSegwitAddresses(5);
// NEW: Extended public keys
const xpub = await fetchBtcXpub(); // Legacy XPUB
const ypub = await fetchBtcYpub(); // Wrapped Segwit YPUB
const zpub = await fetchBtcZpub(); // Native Segwit ZPUB
๐ EIP-7702 Account Abstractionโ
New in v4.0: Sign authorization requests to temporarily delegate EOA logic to a smart contract.
import { signAuthorization, sign } from 'gridplus-sdk/api/signing';
import { parseGwei } from 'viem';
// Step 1: Sign authorization
const auth = await signAuthorization({
address: '0x0000000000219ab540356cBB839Cbe05303d7705',
chainId: 1,
nonce: 0,
});
// Step 2: Use in transaction
const tx = {
type: 'eip7702',
authorizationList: [auth],
to: myEOA,
value: 0n,
data: batchCalldata,
chainId: 1,
nonce: 1,
gas: 200000n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
};
const result = await sign(tx);
โ Validation with Zodโ
New in v4.0: Automatic transaction validation with helpful error messages.
What Gets Validatedโ
- Transaction type matches structure
- Required fields present
- Field types correct (bigint, hex strings, etc.)
- Valid addresses and hashes
- Access lists properly formatted
Example Validation Errorโ
// โ This will throw a clear error
const tx = {
type: 'eip1559',
to: 'invalid-address', // Not a valid hex address
value: '0.1', // Should be bigint, not string
gas: 21000, // Should be bigint (21000n)
// Missing required fields...
};
await sign(tx);
// Error: Invalid transaction:
// - to: Invalid address format
// - value: Expected bigint, received string
// - gas: Expected bigint, received number
// - Missing required field: maxFeePerGas
๐งช Testing Setupโ
v3.xโ
Testing used custom setups without standardized local networks.
v4.0 (Foundry + Anvil)โ
# One-time setup (starts Anvil in background)
npm run setup:anvil
# In another terminal, run tests
npm run test
# Run specific test suites
npm run e2e-eth
npm run e2e-eip7702
npm run e2e-sign
# Cleanup when done
npm run cleanup:anvil
New CLI pairing tool:
npm run pair-device
๐ Import Pathsโ
v3.xโ
import { Client, Constants, Utils } from 'gridplus-sdk';
v4.0 (Modular Imports)โ
// Functional API
import { setup, pair } from 'gridplus-sdk';
import { sign, signMessage, signAuthorization } from 'gridplus-sdk/api/signing';
import { fetchAddresses, fetchBtcXpub } from 'gridplus-sdk/api/addresses';
// Constants and utilities still available
import { Constants, HARDENED_OFFSET } from 'gridplus-sdk';
๐ Quick Migration Checklistโ
- Update
package.jsondependencies - Replace
ethersimports withviem - Change transaction
typefrom number to string (2โ'eip1559') - Rename
gasLimittogas - Convert numbers to
bigint(addnsuffix:21000n) - Replace
parseEther()with viem's version - Update client setup to use
setup()andpair()functions - Consider using new Bitcoin XPUB helpers
- Update test setup to use Foundry/Anvil
- Review validation errors (now powered by Zod)
๐ Additional Resourcesโ
โ Need Help?โ
If you encounter issues during migration:
- Check the GitHub Issues
- Review the test suite for examples
- Consult the signing guide for transaction examples
Common gotchas:
- Forgetting to convert numbers to
bigint - Using
gasLimitinstead ofgas - Numeric transaction types instead of strings
- Missing required fields (Zod will catch these)