Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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,2 +1,3 @@
COMPASS_WALLET_ADDRESS=<>
PRIVATE_KEY=<>
COMPASS_API_KEY=<>
1 change: 1 addition & 0 deletions wallet-earn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ npm run start
## Environment variables

```
COMPASS_WALLET_ADDRESS=<>
PRIVATE_KEY=<>
COMPASS_API_KEY=<>
```
Expand Down
51 changes: 13 additions & 38 deletions wallet-earn/app/api/deposit/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,54 +32,29 @@ export async function POST(request: Request) {
apiKeyAuth: process.env.COMPASS_API_KEY,
});

const allowance = await compassApiSDK.universal.genericAllowance({
const deposit = await compassApiSDK.earn.earnManage({
owner: account.address,
chain: CHAIN,
user: account.address,
token,
contract: vaultAddress,
venue: {
type: "VAULT",
vaultAddress,
},
action: "DEPOSIT",
amount,
});

if (Number(allowance.amount) < amount) {
const allowance = await compassApiSDK.universal.genericAllowanceSet({
chain: CHAIN,
sender: account.address,
contract: vaultAddress,
amount,
token,
});

const transaction = allowance.transaction as UnsignedTransaction;

const setAllowanceTxHash = await walletClient.sendTransaction({
...(transaction as any),
value: BigInt(transaction.value),
gas: BigInt(transaction.gas),
maxFeePerGas: BigInt(transaction.maxFeePerGas),
maxPriorityFeePerGas: BigInt(transaction.maxPriorityFeePerGas),
});
const transaction = deposit.transaction as UnsignedTransaction;

const tx = await publicClient.waitForTransactionReceipt({
hash: setAllowanceTxHash,
});
console.log(transaction)

if (tx.status !== "success") {
throw new Error("Allowance transaction reverted.");
}
if (!transaction) {
throw new Error("No transaction returned from earnManage");
}

const deposit = await compassApiSDK.erc4626Vaults.vaultsDeposit({
chain: CHAIN,
sender: account.address,
vaultAddress,
amount,
});

const transaction = deposit.transaction as UnsignedTransaction;

const depositTxHash = await walletClient.sendTransaction({
...(transaction as any),
value: BigInt(transaction.value),
gas: BigInt(transaction.gas),
gas: transaction.gas ? BigInt(transaction.gas) : undefined,
maxFeePerGas: BigInt(transaction.maxFeePerGas),
maxPriorityFeePerGas: BigInt(transaction.maxPriorityFeePerGas),
});
Expand Down
61 changes: 61 additions & 0 deletions wallet-earn/app/api/positions/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { CHAIN } from "@/utils/constants";
import { getWalletAddress } from "@/utils/utils";
import { CompassApiSDK } from "@compass-labs/api-sdk";

export async function GET() {
try {
const walletAddress = getWalletAddress();

const compassApiSDK = new CompassApiSDK({
apiKeyAuth: process.env.COMPASS_API_KEY,
});

// Fetch user's earn positions
const positionsResponse = await compassApiSDK.earn.earnPositions({
chain: CHAIN,
userAddress: walletAddress,
offset: 0,
limit: 100,
days: 30,
});

return new Response(JSON.stringify(positionsResponse), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
} catch (error: any) {
console.error("Error fetching earn positions:", error);

// If it's a validation error from the SDK, extract the raw response body
if (error?.rawResponse) {
console.log("Validation failed, extracting raw response body");
try {
const clonedResponse = error.rawResponse.clone();
const rawData = await clonedResponse.json();
return new Response(JSON.stringify(rawData), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
} catch (parseError) {
console.error("Failed to parse raw response:", parseError);
}
}

return new Response(
JSON.stringify({
error: "Failed to fetch earn positions",
details: error instanceof Error ? error.message : String(error)
}),
{
status: 500,
headers: {
"Content-Type": "application/json",
},
}
);
}
}
9 changes: 4 additions & 5 deletions wallet-earn/app/api/token/[token]/route.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { CHAIN } from "@/utils/constants";
import { getWalletAddress } from "@/utils/utils";
import { CompassApiSDK } from "@compass-labs/api-sdk";
import { TokenEnum } from "@compass-labs/api-sdk/models/components";
import { privateKeyToAccount } from "viem/accounts";

export async function GET(
_: Request,
{ params }: { params: Promise<{ token: TokenEnum | `0x${string}` }> }
{ params }: { params: Promise<{ token: string }> }
) {
const { token } = await params;

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletAddress = getWalletAddress();

const compassApiSDK = new CompassApiSDK({
apiKeyAuth: process.env.COMPASS_API_KEY,
Expand All @@ -18,7 +17,7 @@ export async function GET(
const tokenBalance = compassApiSDK.token.tokenBalance({
chain: CHAIN,
token,
user: account.address,
user: walletAddress,
});

const tokenPrice = compassApiSDK.token.tokenPrice({
Expand Down
6 changes: 3 additions & 3 deletions wallet-earn/app/api/vault/[address]/route.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { CHAIN } from "@/utils/constants";
import { getWalletAddress } from "@/utils/utils";
import { CompassApiSDK } from "@compass-labs/api-sdk";
import { privateKeyToAccount } from "viem/accounts";

export async function GET(
_: Request,
{ params }: { params: Promise<{ address: `0x${string}` }> }
) {
const { address } = await params;

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletAddress = getWalletAddress();

const compassApiSDK = new CompassApiSDK({
apiKeyAuth: process.env.COMPASS_API_KEY,
Expand All @@ -17,7 +17,7 @@ export async function GET(
const vaultResponse = await compassApiSDK.erc4626Vaults.vaultsVault({
chain: CHAIN,
vaultAddress: address,
userAddress: account.address,
userAddress: walletAddress,
});

return new Response(JSON.stringify(vaultResponse), {
Expand Down
58 changes: 58 additions & 0 deletions wallet-earn/app/api/vaults/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { CHAIN } from "@/utils/constants";
import { CompassApiSDK } from "@compass-labs/api-sdk";

export async function GET() {
try {
const compassApiSDK = new CompassApiSDK({
apiKeyAuth: process.env.COMPASS_API_KEY,
});

// Call the SDK method - it will validate the response
const vaultsResponse = await compassApiSDK.earn.earnVaults({
chain: CHAIN,
orderBy: "one_month_returns",
direction: "desc",
offset: 0,
limit: 50,
});

return new Response(JSON.stringify(vaultsResponse), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
} catch (error: any) {
console.error("Error fetching vaults:", error);

// If it's a validation error from the SDK, extract the raw response body
if (error?.rawResponse) {
console.log("Validation failed, extracting raw response body");
try {
const clonedResponse = error.rawResponse.clone();
const rawData = await clonedResponse.json();
return new Response(JSON.stringify(rawData), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
} catch (parseError) {
console.error("Failed to parse raw response:", parseError);
}
}

return new Response(
JSON.stringify({
error: "Failed to fetch vaults",
details: error instanceof Error ? error.message : String(error)
}),
{
status: 500,
headers: {
"Content-Type": "application/json",
},
}
);
}
}
61 changes: 16 additions & 45 deletions wallet-earn/app/api/withdraw/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,62 +32,33 @@ export async function POST(request: Request) {
apiKeyAuth: process.env.COMPASS_API_KEY,
});

const auth =
await compassApiSDK.transactionBundler.transactionBundlerAuthorization({
chain: CHAIN,
sender: account.address,
});

const signedAuth = await walletClient.signAuthorization({
account,
contractAddress: auth.address as `0x${string}`,
nonce: auth.nonce,
const withdraw = await compassApiSDK.earn.earnManage({
owner: account.address,
chain: CHAIN,
venue: {
type: "VAULT",
vaultAddress,
},
action: "WITHDRAW",
amount: isAll ? "ALL" : amount,
});

const withdrawWithFee =
await compassApiSDK.transactionBundler.transactionBundlerExecute({
chain: CHAIN,
sender: account.address,
signedAuthorization: {
nonce: signedAuth.nonce,
address: signedAuth.address,
chainId: signedAuth.chainId,
r: signedAuth.r,
s: signedAuth.s,
yParity: signedAuth.yParity as number,
},
actions: [
{
body: {
actionType: "VAULT_WITHDRAW",
vaultAddress,
amount: isAll ? "ALL" : amount,
},
},
{
// Extract 1% fee
body: {
actionType: "TOKEN_TRANSFER",
to: "0xd92710ffFF5c6449ADc1b0B86283eb7dbF37567d",
token,
amount: amount * 0.01,
},
},
],
});
const transaction = withdraw.transaction as UnsignedTransaction;

const transaction = withdrawWithFee.transaction as UnsignedTransaction;
if (!transaction) {
throw new Error("No transaction returned from earnManage");
}

const withdrawWithFeeTxHash = await walletClient.sendTransaction({
const withdrawTxHash = await walletClient.sendTransaction({
...(transaction as any),
value: BigInt(transaction.value),
gas: BigInt(transaction.gas),
gas: transaction.gas ? BigInt(transaction.gas) : undefined,
maxFeePerGas: BigInt(transaction.maxFeePerGas),
maxPriorityFeePerGas: BigInt(transaction.maxPriorityFeePerGas),
});

const tx = await publicClient.waitForTransactionReceipt({
hash: withdrawWithFeeTxHash,
hash: withdrawTxHash,
});

console.log("tx", tx);
Expand Down
11 changes: 5 additions & 6 deletions wallet-earn/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import Screens from "@/components/Screens";
import { cn, generateWalletGradient } from "@/utils/utils";
import { privateKeyToAccount } from "viem/accounts";
import { cn, generateWalletGradient, getWalletAddress } from "@/utils/utils";

export default async function Home() {
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletAddress = getWalletAddress();

return (
<div className="w-screen h-screen flex flex-col items-center justify-center">
Expand All @@ -13,11 +12,11 @@ export default async function Home() {
className={cn(
"w-6 h-6 border border-neutral-200 rounded-full mr-2 outline -outline-offset-2 outline-neutral-900/15"
)}
style={{ background: generateWalletGradient(account.address) }}
style={{ background: generateWalletGradient(walletAddress) }}
/>
{account.address.slice(0, 6)}
{walletAddress.slice(0, 6)}
<span className="text-xs">●●●●</span>
{account.address.slice(-4)}
{walletAddress.slice(-4)}
</div>
<Screens />
</div>
Expand Down
Loading
Loading