Using Compass API with Safe Smart Accounts
This guide demonstrates how to integrate Compass API SDK with Safe Starter Kit SDK to create and use smart accounts for DeFi operations.
Prerequisites
Install Dependencies
Install the required packages:
npm install @safe-global/sdk-starter-kit @compass-labs/api-sdk dotenv
Set Environment Variables
Create a .env
file in your project root:
# .env
ARBITRUM_RPC_URL="your_arbitrum_rpc_url"
SIGNER_PRIVATE_KEY="your_wallet_private_key"
COMPASS_API_KEY="your_compass_api_key"
# If using existing safe:
SAFE_ADDRESS="your_safe_address"
# If creating new safe:
# SIGNER_ADDRESS="your_signer_address"
Implementation Guide
1. Initial Setup
First, import the necessary dependencies and set up environment variables:
import { createSafeClient } from '@safe-global/sdk-starter-kit';
import dotenv from 'dotenv';
import { CompassApiSDK } from '@compass-labs/api-sdk';
import { SafeProvider } from '@safe-global/protocol-kit';
dotenv.config();
const ARBITRUM_RPC_URL = process.env.ARBITRUM_RPC_URL as SafeProvider['provider'];
const SIGNER_PRIVATE_KEY = process.env.SIGNER_PRIVATE_KEY as string;
const COMPASS_API_KEY = process.env.COMPASS_API_KEY as string;
const SAFE_ADDRESS = process.env.SAFE_ADDRESS as string;
2. Create Safe Client
You have two options for setting up your Safe client:
Option A: Use Existing Safe
If you already have a Safe deployed, use its address:
const safeClient = await createSafeClient({
provider: ARBITRUM_RPC_URL,
signer: SIGNER_PRIVATE_KEY,
safeAddress: SAFE_ADDRESS,
});
Option B: Deploy New Safe
To deploy a new Safe, uncomment and use the following code:
// First, uncomment SIGNER_ADDRESS in your .env file
const SIGNER_ADDRESS = process.env.SIGNER_ADDRESS as string;
const safeClient = await createSafeClient({
provider: ARBITRUM_RPC_URL,
signer: SIGNER_PRIVATE_KEY,
safeOptions: {
owners: [SIGNER_ADDRESS],
threshold: 1,
},
});
3. Initialize Compass API SDK
Set up the Compass API SDK for DeFi operations:
const compassApiSDK = new CompassApiSDK({
apiKeyAuth: COMPASS_API_KEY,
});
4. Create and Execute Operations
Here’s an example of increasing allowance and supplying tokens to Aave:
const result = await compassApiSDK.smartAccount.accountBatchedUserOperations({
chain: 'arbitrum:mainnet',
operations: [
{
body: {
actionType: 'ALLOWANCE_INCREASE',
token: 'USDC',
contractName: 'AaveV3Pool',
amount: '3',
},
},
{
body: {
actionType: 'AAVE_SUPPLY',
token: 'USDC',
amount: '3',
},
},
],
});
When deploying a new Safe, it’s recommended to only include the ALLOWANCE_INCREASE
operation in the first transaction. The Safe will not have any tokens initially, so the AAVE_SUPPLY
operation should be executed in a subsequent transaction after funding the Safe with USDC.
5. Process and Execute Transactions
Convert the operations to the format expected by Safe and execute them:
const operations = result.operations.map((op) => ({
to: op.to as `0x${string}`,
data: op.data as `0x${string}`,
value: op.value ? String(op.value) : '0',
}));
const txResult = await safeClient.send({ transactions: operations });
console.log('txResult', txResult);
console.log('txResult.status', txResult.status);
console.log(txResult.transactions?.ethereumTxHash);
6. Multi-Signature Support (Optional)
If your Safe requires multiple signatures, you’ll need to handle the confirmation process:
// Get the transaction hash
const safeTxHash = txResult.transactions?.safeTxHash;
// Create a new safe client for another signer
const newSafeClient = await createSafeClient({
provider: RPC_URL,
signer: OTHER_SIGNER_PRIVATE_KEY,
safeAddress: safeTxHash,
});
// Get pending transactions
const pendingTransactions = await newSafeClient.getPendingTransactions();
// Find and confirm the specific transaction
for (const transaction of pendingTransactions.results) {
if (transaction.safeTxHash === safeTxHash) {
const txResult2 = await newSafeClient.confirm({ safeTxHash });
console.log('Confirmation result:', txResult2);
}
}
Common Operation Examples
Here are some examples of different DeFi operations you can perform:
Token Swaps
{
body: {
actionType: "UNISWAP_EXACT_IN",
tokenIn: "USDC",
tokenOut: "WETH",
amountIn: "100",
amountOutMinimum: "0.05"
}
}
Lending Operations
{
body: {
actionType: "AAVE_SUPPLY",
token: "USDC",
amount: "1000"
}
}
Token Approvals
{
body: {
actionType: "ALLOWANCE_INCREASE",
token: "WETH",
contractName: "UniswapV3Router",
amount: "1"
}
}
Resources