Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions wallet-earn/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
COMPASS_WALLET_ADDRESS=<>
PRIVATE_KEY=<>
GAS_SPONSOR_PK=<>
COMPASS_API_KEY=<>
72 changes: 58 additions & 14 deletions wallet-earn/app/api/deposit/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@ export async function POST(request: Request) {
throw new Error("Missing body parameters.");
}

const account = privateKeyToAccount(
// Owner account - signs EIP-712 typed data
const ownerAccount = privateKeyToAccount(
process.env.PRIVATE_KEY as `0x${string}`
);

const walletClient = createWalletClient({
account,
// Sponsor account - pays gas and submits transaction
const sponsorAccount = privateKeyToAccount(
process.env.GAS_SPONSOR_PK as `0x${string}`
);

const sponsorWalletClient = createWalletClient({
account: sponsorAccount,
chain: base,
transport: http(process.env.RPC_URL),
});
Expand All @@ -32,31 +38,69 @@ export async function POST(request: Request) {
apiKeyAuth: process.env.COMPASS_API_KEY,
});

// Step 1: Call earnManage with gas sponsorship enabled
const deposit = await compassApiSDK.earn.earnManage({
owner: account.address,
owner: ownerAccount.address,
chain: CHAIN,
venue: {
type: "VAULT",
vaultAddress,
},
action: "DEPOSIT",
amount,
gasSponsorship: true,
});

const transaction = deposit.transaction as UnsignedTransaction;
// Step 2: Extract EIP-712 typed data
const eip712TypedData = deposit.eip712;

if (!eip712TypedData) {
throw new Error("No EIP-712 typed data returned from earnManage");
}

console.log(transaction)
console.log("EIP-712 Typed Data:", eip712TypedData);

// Step 3: Owner signs the EIP-712 typed data
// Note: SDK returns camelCase keys (safeTx, eip712Domain) but primaryType as "SafeTx"
// We need to normalize the types object to match what viem expects
const normalizedTypes = {
EIP712Domain: (eip712TypedData.types as any).eip712Domain,
SafeTx: (eip712TypedData.types as any).safeTx,
};

const signature = await ownerAccount.signTypedData({
domain: eip712TypedData.domain as any,
types: normalizedTypes,
primaryType: "SafeTx",
message: eip712TypedData.message as any,
});

if (!transaction) {
throw new Error("No transaction returned from earnManage");
console.log("Owner Signature:", signature);

// Step 4: Prepare gas-sponsored transaction
const sponsorGasResponse = await compassApiSDK.gasSponsorship.gasSponsorshipPrepare({
owner: ownerAccount.address,
chain: CHAIN,
eip712: eip712TypedData as any,
signature,
sender: sponsorAccount.address,
});

const sponsoredTransaction = sponsorGasResponse.transaction as UnsignedTransaction;

if (!sponsoredTransaction) {
throw new Error("No transaction returned from gasSponsorshipPrepare");
}

const depositTxHash = await walletClient.sendTransaction({
...(transaction as any),
value: BigInt(transaction.value),
gas: transaction.gas ? BigInt(transaction.gas) : undefined,
maxFeePerGas: BigInt(transaction.maxFeePerGas),
maxPriorityFeePerGas: BigInt(transaction.maxPriorityFeePerGas),
console.log("Sponsored Transaction:", sponsoredTransaction);

// Step 5: Sponsor signs and submits the transaction
const depositTxHash = await sponsorWalletClient.sendTransaction({
...(sponsoredTransaction as any),
value: BigInt(sponsoredTransaction.value),
gas: sponsoredTransaction.gas ? BigInt(sponsoredTransaction.gas) : undefined,
maxFeePerGas: BigInt(sponsoredTransaction.maxFeePerGas),
maxPriorityFeePerGas: BigInt(sponsoredTransaction.maxPriorityFeePerGas),
});

const tx = await publicClient.waitForTransactionReceipt({
Expand Down
72 changes: 59 additions & 13 deletions wallet-earn/app/api/withdraw/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@ export async function POST(request: Request) {
throw new Error("Missing body parameters.");
}

const account = privateKeyToAccount(
// Owner account - signs EIP-712 typed data
const ownerAccount = privateKeyToAccount(
process.env.PRIVATE_KEY as `0x${string}`
);

const walletClient = createWalletClient({
account,
// Sponsor account - pays gas and submits transaction
const sponsorAccount = privateKeyToAccount(
process.env.GAS_SPONSOR_PK as `0x${string}`
);

const sponsorWalletClient = createWalletClient({
account: sponsorAccount,
chain: base,
transport: http(process.env.RPC_URL),
});
Expand All @@ -32,29 +38,69 @@ export async function POST(request: Request) {
apiKeyAuth: process.env.COMPASS_API_KEY,
});

// Step 1: Call earnManage with gas sponsorship enabled
const withdraw = await compassApiSDK.earn.earnManage({
owner: account.address,
owner: ownerAccount.address,
chain: CHAIN,
venue: {
type: "VAULT",
vaultAddress,
},
action: "WITHDRAW",
amount: isAll ? "ALL" : amount,
gasSponsorship: true,
});

// Step 2: Extract EIP-712 typed data
const eip712TypedData = withdraw.eip712;

if (!eip712TypedData) {
throw new Error("No EIP-712 typed data returned from earnManage");
}

console.log("EIP-712 Typed Data:", eip712TypedData);

// Step 3: Owner signs the EIP-712 typed data
// Note: SDK returns camelCase keys (safeTx, eip712Domain) but primaryType as "SafeTx"
// We need to normalize the types object to match what viem expects
const normalizedTypes = {
EIP712Domain: (eip712TypedData.types as any).eip712Domain,
SafeTx: (eip712TypedData.types as any).safeTx,
};

const signature = await ownerAccount.signTypedData({
domain: eip712TypedData.domain as any,
types: normalizedTypes,
primaryType: "SafeTx",
message: eip712TypedData.message as any,
});

const transaction = withdraw.transaction as UnsignedTransaction;
console.log("Owner Signature:", signature);

if (!transaction) {
throw new Error("No transaction returned from earnManage");
// Step 4: Prepare gas-sponsored transaction
const sponsorGasResponse = await compassApiSDK.gasSponsorship.gasSponsorshipPrepare({
owner: ownerAccount.address,
chain: CHAIN,
eip712: eip712TypedData as any,
signature,
sender: sponsorAccount.address,
});

const sponsoredTransaction = sponsorGasResponse.transaction as UnsignedTransaction;

if (!sponsoredTransaction) {
throw new Error("No transaction returned from gasSponsorshipPrepare");
}

const withdrawTxHash = await walletClient.sendTransaction({
...(transaction as any),
value: BigInt(transaction.value),
gas: transaction.gas ? BigInt(transaction.gas) : undefined,
maxFeePerGas: BigInt(transaction.maxFeePerGas),
maxPriorityFeePerGas: BigInt(transaction.maxPriorityFeePerGas),
console.log("Sponsored Transaction:", sponsoredTransaction);

// Step 5: Sponsor signs and submits the transaction
const withdrawTxHash = await sponsorWalletClient.sendTransaction({
...(sponsoredTransaction as any),
value: BigInt(sponsoredTransaction.value),
gas: sponsoredTransaction.gas ? BigInt(sponsoredTransaction.gas) : undefined,
maxFeePerGas: BigInt(sponsoredTransaction.maxFeePerGas),
maxPriorityFeePerGas: BigInt(sponsoredTransaction.maxPriorityFeePerGas),
});

const tx = await publicClient.waitForTransactionReceipt({
Expand Down
2 changes: 1 addition & 1 deletion wallet-earn/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@compass-labs/api-sdk": "^2.0.1",
"@compass-labs/api-sdk": "1.3.5",
"@geist-ui/core": "^2.3.8",
"@radix-ui/react-slider": "^1.3.6",
"@vercel/analytics": "^1.5.0",
Expand Down
Loading