import {
DepositAuthMethod,
fetchSupportedAssets,
prepareApproveWithdrawTxData,
prepareDepositAuthorization,
prepareDepositTxData,
prepareDepositWithPermitTxData,
prepareWithdrawTxData,
YieldType,
type SupportedAsset as AmplifySupportedAsset,
} from "@paxoslabs/amplify-sdk";
import { usePrivy } from "@privy-io/react-auth";
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { encodeFunctionData, isAddress, type Address } from "viem";
import { mainnet } from "viem/chains";
import "./App.css";
import { useAmplify } from "./hooks/use-amplify";
import { useWalletSession } from "./hooks/use-wallet-session";
function App() {
useAmplify();
const { ready, authenticated, login, logout, wallet } = useWalletSession();
const { sendTransaction } = usePrivy();
const [status, setStatus] = useState<string | null>(null);
const [selectedAsset, setSelectedAsset] =
useState<AmplifySupportedAsset | null>(null);
const {
data: supportedAssets,
isLoading: isLoadingSupportedAssets,
isError: isErrorSupportedAssets,
} = useQuery({
queryKey: ["amplify-vaults", mainnet.id],
enabled: authenticated,
queryFn: () =>
fetchSupportedAssets({
yieldType: YieldType.PRIME,
}),
});
console.log(supportedAssets);
if (!ready) {
return <p>Loading Privy…</p>;
}
if (!authenticated || !wallet) {
return <button onClick={login}>Connect with Privy</button>;
}
if (isLoadingSupportedAssets) {
return <p>Loading assets...</p>;
}
if (isErrorSupportedAssets) {
return <p>Error loading assets</p>;
}
const owner = wallet.address as `0x${string}`;
const chainId = mainnet.id;
const handleAssetChange = (address: Address) => {
if (!isAddress(address)) {
console.error("Invalid asset address");
return;
}
setSelectedAsset(
supportedAssets?.find((asset) => asset.address === address) ?? null,
);
};
async function handleDeposit() {
const params = {
yieldType: YieldType.PRIME,
depositToken: selectedAsset?.address as `0x${string}`,
depositAmount: "100",
recipientAddress: owner,
chainId,
};
// Step 1: Get authorization method
setStatus("Checking authorization...");
const auth = await prepareDepositAuthorization(params);
// Step 2: Handle based on method
switch (auth.method) {
case DepositAuthMethod.PERMIT: {
setStatus("Please sign permit...");
const provider = await wallet.getEthereumProvider();
const signature = (await provider.request({
method: "eth_signTypedData_v4",
params: [
owner,
JSON.stringify({
domain: auth.permitData.domain,
types: auth.permitData.types,
primaryType: auth.permitData.primaryType,
message: auth.permitData.message,
}),
],
})) as `0x${string}`;
setStatus("Submitting deposit...");
const permitTx = await prepareDepositWithPermitTxData({
...params,
signature,
deadline: BigInt(auth.permitData.message.deadline),
});
// Extract and encode the permit deposit data
const {
abi: permitAbi,
functionName: permitFn,
args: permitArgs,
} = permitTx.data;
await sendTransaction({
chainId: permitTx.chainId,
to: permitTx.address,
data: encodeFunctionData({
abi: permitAbi,
functionName: permitFn,
args: permitArgs,
}),
});
setStatus("Deposit complete!");
break;
}
case DepositAuthMethod.APPROVAL: {
setStatus("Approving token spend...");
const {
abi: approvalAbi,
functionName: approvalFn,
args: approvalArgs,
} = auth.txData;
await sendTransaction({
chainId: chainId,
to: auth.txData.address,
data: encodeFunctionData({
abi: approvalAbi,
functionName: approvalFn,
args: approvalArgs,
}),
});
setStatus("Submitting deposit...");
const depositTx = await prepareDepositTxData(params);
const {
abi: depositAbi,
functionName: depositFn,
args: depositArgs,
} = depositTx;
await sendTransaction({
chainId: depositTx.chainId,
to: depositTx.address,
data: encodeFunctionData({
abi: depositAbi,
functionName: depositFn,
args: depositArgs,
}),
});
setStatus("Deposit complete!");
break;
}
case DepositAuthMethod.ALREADY_APPROVED: {
setStatus("Submitting deposit...");
const directTx = await prepareDepositTxData(params);
const { abi, functionName, args } = directTx;
await sendTransaction({
chainId: directTx.chainId,
to: directTx.address,
data: encodeFunctionData({ abi, functionName, args }),
});
setStatus("Deposit complete!");
break;
}
}
}
async function handleWithdraw() {
setStatus("Preparing withdrawal...");
const approval = await prepareApproveWithdrawTxData({
chainId,
wantAssetAddress: selectedAsset?.address as `0x${string}`,
yieldType: YieldType.PRIME,
});
setStatus("Approving withdrawal...");
await sendTransaction({
chainId,
to: approval.address,
data: encodeFunctionData({
abi: approval.abi,
functionName: approval.functionName,
args: approval.args,
}),
});
const withdraw = await prepareWithdrawTxData({
yieldType: YieldType.PRIME,
wantAssetAddress: selectedAsset?.address as `0x${string}`,
offerAmount: "1",
chainId,
});
setStatus("Submitting withdrawal...");
const {
abi: withdrawAbi,
functionName: withdrawFn,
args: withdrawArgs,
} = withdraw;
await sendTransaction({
chainId: withdraw.chainId,
to: withdraw.address,
data: encodeFunctionData({
abi: withdrawAbi,
functionName: withdrawFn,
args: withdrawArgs,
}),
});
setStatus("Withdrawal complete!");
}
return (
<main>
<h1>Amplify Earn Starter</h1>
<p>{wallet.address}</p>
{status && <p>{status}</p>}
<div>
<select
value={selectedAsset?.symbol ?? ""}
onChange={(e) => {
handleAssetChange(e.target.value as Address);
}}
>
{supportedAssets?.map((asset) => (
<option key={asset.address} value={asset.address}>
{asset.symbol}
</option>
))}
</select>
</div>
<div>
<div>
<button onClick={handleDeposit}>Deposit</button>
<button onClick={handleWithdraw}>Withdraw</button>
</div>
</div>
<button onClick={logout}>Disconnect</button>
</main>
);
}
export default App;