Why Combine Para and Paxos Amplify
| Para Wallets | Paxos Amplify |
|---|---|
| Instant onboarding, MPC-secure, white-label | Stablecoin yield across multiple strategies |
| Embedded + external wallet support | Multi-chain support, unified deposit API |
| Email/social login — no seed phrase or browser extension | Audited smart contracts |
Example Use Cases
- Fintech App Integration — Embed stablecoin deposit and yield flows directly in your fintech application with Para’s white-label wallet onboarding.
- Stablecoin Yield Product — Build a consumer-facing earn product where users deposit stablecoins into Amplify vaults through a Para-powered wallet — no browser extension required.
- Treasury Management — Automate treasury yield strategies from Para wallets with programmable deposit and withdrawal rules.
- Multi-Language Backend — Call Amplify contracts directly from Python, Go, Swift, or any language with an Ethereum JSON-RPC library — no JavaScript SDK required.
What You Need
- Para SDK for creating and managing wallets
- EVM-compatible chain such as Ethereum Mainnet
- Amplify API Credentials (
pxl_your_api_key) from support@paxoslabs.com - Amplify SDK (SDK path only) —
@paxoslabs/amplify-sdk
Step-by-Step Integration
- SDK Integration
- Direct Contracts
Step 1: Install Dependencies
npm install @getpara/viem-v2-integration @getpara/react-sdk @paxoslabs/amplify-sdk viem
Step 2: Initialize Para and Amplify
Complete authentication before signing any transactions.import { createParaViemClient, createParaAccount } from "@getpara/viem-v2-integration";
import { ParaWeb } from "@getpara/react-sdk";
import { http, createPublicClient } from "viem";
import { mainnet } from "viem/chains";
import { initAmplifySDK } from "@paxoslabs/amplify-sdk";
// Initialize Para
const para = new ParaWeb("YOUR_PARA_API_KEY");
// Initialize Amplify SDK
await initAmplifySDK("pxl_your_api_key", {
rpcUrls: { [mainnet.id]: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY" },
});
Step 3: Create Para Account and Clients
const account = await createParaAccount(para);
const walletClient = createParaViemClient(para, {
account,
chain: mainnet,
transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"),
});
const publicClient = createPublicClient({
chain: mainnet,
transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"),
});
Step 4: Discover a Vault and Deposit
The SDK auto-detects the optimal authorization method (gasless permit, standard approval, or existing allowance) and handles each path for you.import {
getVaultsByConfig,
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from "@paxoslabs/amplify-sdk";
// Find a vault by yield strategy, chain, and asset
const [vault] = await getVaultsByConfig({
yieldType: YieldType.CORE, // "CORE", "TREASURY", or "FRONTIER"
chainId: mainnet.id,
depositAssetAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
});
const params = {
vaultName: vault.name,
depositAsset: vault.vault.baseTokenAddress,
depositAmount: "1000", // 1000 USDC
to: account.address,
chainId: mainnet.id,
};
// Auto-detect optimal authorization method
const auth = await prepareDepositAuthorization(params);
if (isPermitAuth(auth)) {
// Para signs the EIP-712 permit off-chain (gasless)
const signature = await walletClient.signTypedData({
account,
...auth.permitData,
});
const prepared = await prepareDeposit({
...params,
signature,
deadline: auth.permitData.message.deadline,
});
const hash = await walletClient.writeContract({ ...prepared.txData, account });
await publicClient.waitForTransactionReceipt({ hash });
} else if (isApprovalAuth(auth)) {
// Standard ERC-20 approve followed by deposit
const approvalHash = await walletClient.writeContract({ ...auth.txData, account });
await publicClient.waitForTransactionReceipt({ hash: approvalHash });
const prepared = await prepareDeposit(params);
const depositHash = await walletClient.writeContract({ ...prepared.txData, account });
await publicClient.waitForTransactionReceipt({ hash: depositHash });
} else if (isAlreadyApprovedAuth(auth)) {
// Sufficient allowance — deposit directly
const prepared = await prepareDeposit(params);
const hash = await walletClient.writeContract({ ...prepared.txData, account });
await publicClient.waitForTransactionReceipt({ hash });
}
Step 5: Withdraw from a Vault
import {
prepareWithdrawalAuthorization,
prepareWithdrawal,
isWithdrawApprovalAuth,
} from "@paxoslabs/amplify-sdk";
const withdrawParams = {
vaultName: vault.name,
wantAsset: vault.vault.baseTokenAddress,
withdrawAmount: "500", // 500 Shares
userAddress: account.address,
chainId: mainnet.id,
};
const withdrawAuth = await prepareWithdrawalAuthorization(withdrawParams);
if (isWithdrawApprovalAuth(withdrawAuth)) {
const approvalHash = await walletClient.writeContract({ ...withdrawAuth.txData, account });
await publicClient.waitForTransactionReceipt({ hash: approvalHash });
}
const withdrawTxData = await prepareWithdrawal(withdrawParams);
const withdrawHash = await walletClient.writeContract({ ...withdrawTxData, account });
await publicClient.waitForTransactionReceipt({ hash: withdrawHash });
Step 1: Install Dependencies
npm install @getpara/viem-v2-integration @getpara/react-sdk viem
Step 2: Initialize Para
Complete authentication before signing any transactions.import { createParaViemClient, createParaAccount } from "@getpara/viem-v2-integration";
import { ParaWeb } from "@getpara/react-sdk";
import { http, createPublicClient } from "viem";
import { mainnet } from "viem/chains";
const para = new ParaWeb("YOUR_PARA_API_KEY");
Step 3: Create Para Account and Clients
const account = await createParaAccount(para);
const walletClient = createParaViemClient(para, {
account,
chain: mainnet,
transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"),
});
const publicClient = createPublicClient({
chain: mainnet,
transport: http("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"),
});
Step 4: Discover Contract Addresses
Query the Amplify GraphQL API to get vault and module addresses for your target chain and yield type.const response = await fetch("https://api.paxoslabs.com/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "YOUR_AMPLIFY_API_KEY",
},
body: JSON.stringify({
query: `query {
amplifySdkConfigs(chainId: 1, yieldType: CORE) {
vault {
boringVaultAddress
communityCodeDepositorModuleId
withdrawQueueModuleId
accountantModuleId
supportedAssets { address symbol decimals depositable withdrawable }
}
}
}`,
}),
});
const { data } = await response.json();
const vault = data.amplifySdkConfigs[0].vault;
const depositorAddress = vault.communityCodeDepositorModuleId;
const withdrawQueueAddress = vault.withdrawQueueModuleId;
const accountantAddress = vault.accountantModuleId;
const boringVaultAddress = vault.boringVaultAddress;
const usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
Step 5: Approve and Deposit
const erc20Abi = [
{
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" },
],
name: "approve",
outputs: [{ name: "", type: "bool" }],
stateMutability: "nonpayable",
type: "function",
},
];
const depositorAbi = [
{
inputs: [
{ name: "depositAsset", type: "address" },
{ name: "depositAmount", type: "uint256" },
{ name: "minimumMint", type: "uint256" },
{ name: "to", type: "address" },
{ name: "distributorCode", type: "bytes" },
{
components: [
{ name: "uuid", type: "string" },
{ name: "expiration", type: "uint256" },
{ name: "attester", type: "address" },
{ name: "signature", type: "bytes" },
],
name: "_attestation",
type: "tuple",
},
],
name: "deposit",
outputs: [{ name: "shares", type: "uint256" }],
stateMutability: "nonpayable",
type: "function",
},
];
const depositAmount = 1000000000n; // 1,000 USDC (6 decimals)
// Approve the depositor to spend your USDC
const approvalHash = await walletClient.writeContract({
address: usdcAddress,
abi: erc20Abi,
functionName: "approve",
args: [depositorAddress, depositAmount],
account,
});
await publicClient.waitForTransactionReceipt({ hash: approvalHash });
// Deposit into the vault
const depositHash = await walletClient.writeContract({
address: depositorAddress,
abi: depositorAbi,
functionName: "deposit",
args: [
usdcAddress,
depositAmount,
0n, // minimumMint — see production note below
account.address,
"0x", // distributorCode
{
uuid: "",
expiration: 0n,
attester: "0x0000000000000000000000000000000000000000",
signature: "0x",
},
],
account,
});
await publicClient.waitForTransactionReceipt({ hash: depositHash });
In production, query
Accountant.getRateInQuoteSafe(usdcAddress) to calculate a safe minimumMint with slippage protection instead of passing 0n. See the slippage calculation below.const WAD = 10n ** 18n;
const SLIPPAGE_BPS = 50n; // 0.5%
const accountantAbi = [
{
inputs: [{ name: "quote", type: "address" }],
name: "getRateInQuoteSafe",
outputs: [{ name: "rateInQuote", type: "uint256" }],
stateMutability: "view",
type: "function",
},
] as const;
const rateInQuote = await publicClient.readContract({
address: accountantAddress,
abi: accountantAbi,
functionName: "getRateInQuoteSafe",
args: [usdcAddress],
});
const vaultTokenDecimals = await publicClient.readContract({
address: boringVaultAddress,
abi: [{ inputs: [], name: "decimals", outputs: [{ type: "uint8" }], stateMutability: "view", type: "function" }],
functionName: "decimals",
});
const idealMint = (depositAmount * WAD) / rateInQuote;
const slippageWad = (SLIPPAGE_BPS * WAD) / 10_000n;
const slippageAmount = (idealMint * slippageWad) / WAD;
const minimumMint = vaultTokenDecimals > 18
? (idealMint - slippageAmount) * 10n ** (BigInt(vaultTokenDecimals) - 18n)
: (idealMint - slippageAmount) / 10n ** (18n - BigInt(vaultTokenDecimals));
Step 6: Submit a Withdrawal Order
Withdrawal orders are fulfilled by the Amplify account operator, typically within 24 hours.const withdrawQueueAbi = [
{
inputs: [
{
components: [
{ name: "amountOffer", type: "uint256" },
{ name: "wantAsset", type: "address" },
{ name: "intendedDepositor", type: "address" },
{ name: "receiver", type: "address" },
{ name: "refundReceiver", type: "address" },
{
components: [
{ name: "approvalMethod", type: "uint8" },
{ name: "approvalV", type: "uint8" },
{ name: "approvalR", type: "bytes32" },
{ name: "approvalS", type: "bytes32" },
{ name: "submitWithSignature", type: "bool" },
{ name: "deadline", type: "uint256" },
{ name: "eip2612Signature", type: "bytes" },
],
name: "signatureParams",
type: "tuple",
},
],
name: "params",
type: "tuple",
},
],
name: "submitOrder",
outputs: [{ name: "orderIndex", type: "uint256" }],
stateMutability: "nonpayable",
type: "function",
},
];
const sharesToWithdraw = 500000000000000000000n; // example share amount
// Approve vault shares to the WithdrawQueue
const shareApprovalHash = await walletClient.writeContract({
address: boringVaultAddress,
abi: erc20Abi,
functionName: "approve",
args: [withdrawQueueAddress, sharesToWithdraw],
account,
});
await publicClient.waitForTransactionReceipt({ hash: shareApprovalHash });
// Submit the withdrawal order
const withdrawHash = await walletClient.writeContract({
address: withdrawQueueAddress,
abi: withdrawQueueAbi,
functionName: "submitOrder",
args: [
{
amountOffer: sharesToWithdraw,
wantAsset: usdcAddress,
intendedDepositor: account.address,
receiver: account.address,
refundReceiver: account.address,
signatureParams: {
approvalMethod: 0,
approvalV: 0,
approvalR: "0x0000000000000000000000000000000000000000000000000000000000000000",
approvalS: "0x0000000000000000000000000000000000000000000000000000000000000000",
submitWithSignature: false,
deadline: 0n,
eip2612Signature: "0x",
},
},
],
account,
});
await publicClient.waitForTransactionReceipt({ hash: withdrawHash });
Use
WithdrawQueue.getOrderStatus(orderIndex) to poll for withdrawal completion.Related Resources
Paxos Amplify
Stablecoin yield protocol documentation and API reference
Para Viem Integration
Set up Para wallets with Viem for EVM transaction signing
EIP-712 Typed Data Signing
Sign structured data using the EIP-712 standard with Para wallets