Skip to content

Commit

Permalink
Transition dca dapp to base sepolia (#708)
Browse files Browse the repository at this point in the history
* change chain to baseSepolia

* refactor userOpBuilder and cosigner service

* update DonutContract address

* chores:run prettier

* fix functionName
  • Loading branch information
KannuSingh authored Sep 18, 2024
1 parent 4cceabb commit 65c5723
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 255 deletions.
7 changes: 4 additions & 3 deletions advanced/dapps/dca-dapp-demo/src/app/api/dca/execute/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { CoSignerApiError } from "@/utils/WalletConnectCosignerUtils";
import { NextResponse } from "next/server";
import { encodeFunctionData, parseEther } from "viem";
import { GrantPermissionsReturnType } from "viem/experimental";
import { sepolia } from "viem/chains";
import { baseSepolia } from "viem/chains";
import { DCAFormSchemaType } from "@/schema/DCAFormSchema";

export async function POST(request: Request) {
Expand All @@ -20,7 +20,8 @@ export async function POST(request: Request) {
permissions: GrantPermissionsReturnType;
pci: string;
} = await request.json();
const APPLICATION_PRIVATE_KEY = process.env.APPLICATION_PRIVATE_KEY as `0x${string}`;
const APPLICATION_PRIVATE_KEY = process.env
.APPLICATION_PRIVATE_KEY as `0x${string}`;

try {
if (!APPLICATION_PRIVATE_KEY) {
Expand Down Expand Up @@ -61,7 +62,7 @@ export async function POST(request: Request) {
ecdsaPrivateKey: APPLICATION_PRIVATE_KEY,
pci,
permissions,
chain: sepolia,
chain: baseSepolia,
actions: purchaseDonutCallDataExecution,
});

Expand Down
3 changes: 2 additions & 1 deletion advanced/dapps/dca-dapp-demo/src/app/api/signer/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { privateKeyToAccount } from "viem/accounts";

export function GET() {
try {
const APPLICATION_PRIVATE_KEY = process.env.APPLICATION_PRIVATE_KEY as `0x${string}`;
const APPLICATION_PRIVATE_KEY = process.env
.APPLICATION_PRIVATE_KEY as `0x${string}`;
const account = privateKeyToAccount(APPLICATION_PRIVATE_KEY);

return NextResponse.json({ key: account.publicKey });
Expand Down
5 changes: 2 additions & 3 deletions advanced/dapps/dca-dapp-demo/src/hooks/useDCA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
hexStringToBase64,
} from "../utils/EncodingUtils";
import { walletActionsErc7715 } from "viem/experimental";
import { createPublicClient, custom } from "viem";
import { createPublicClient, custom, zeroAddress } from "viem";
import { WalletConnectCosigner } from "../utils/WalletConnectCosignerUtils";
import { useDcaApplicationContext } from "../context/DcaApplicationContextProvider";
import { DCAFormSchemaType } from "@/schema/DCAFormSchema";
Expand Down Expand Up @@ -83,8 +83,7 @@ export function useDCA() {
},
},
signerData: {
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
userOpBuilder: approvedPermissions.signerData?.userOpBuilder!,
userOpBuilder: zeroAddress,
},
permissionsContext: approvedPermissions.permissionsContext,
factory: approvedPermissions.factory || "",
Expand Down
128 changes: 0 additions & 128 deletions advanced/dapps/dca-dapp-demo/src/utils/ChainsUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,110 +8,6 @@ function getBlockchainApiRpcUrl(chainId: number) {
return `https://rpc.walletconnect.org/v1/?chainId=eip155:${chainId}&projectId=${process.env["NEXT_PUBLIC_PROJECT_ID"]}`;
}

export const mainnet = {
chainId: 1,
name: "Ethereum",
currency: "ETH",
explorerUrl: "https://etherscan.io",
rpcUrl: getBlockchainApiRpcUrl(1),
};

export const arbitrum = {
chainId: 42161,
name: "Arbitrum",
currency: "ETH",
explorerUrl: "https://arbiscan.io",
rpcUrl: getBlockchainApiRpcUrl(42161),
};

export const avalanche = {
chainId: 43114,
name: "Avalanche",
currency: "AVAX",
explorerUrl: "https://snowtrace.io",
rpcUrl: getBlockchainApiRpcUrl(43114),
};

export const binanceSmartChain = {
chainId: 56,
name: "Binance Smart Chain",
currency: "BNB",
explorerUrl: "https://bscscan.com",
rpcUrl: getBlockchainApiRpcUrl(56),
};

export const optimism = {
chainId: 10,
name: "Optimism",
currency: "ETH",
explorerUrl: "https://optimistic.etherscan.io",
rpcUrl: getBlockchainApiRpcUrl(10),
};

export const polygon = {
chainId: 137,
name: "Polygon",
currency: "MATIC",
explorerUrl: "https://polygonscan.com",
rpcUrl: getBlockchainApiRpcUrl(137),
};

export const gnosis = {
chainId: 100,
name: "Gnosis",
currency: "xDAI",
explorerUrl: "https://gnosis.blockscout.com",
rpcUrl: getBlockchainApiRpcUrl(100),
};

export const zkSync = {
chainId: 324,
name: "ZkSync",
currency: "ETH",
explorerUrl: "https://explorer.zksync.io",
rpcUrl: getBlockchainApiRpcUrl(324),
};

export const zora = {
chainId: 7777777,
name: "Zora",
currency: "ETH",
explorerUrl: "https://explorer.zora.energy",
rpcUrl: getBlockchainApiRpcUrl(7777777),
};

export const celo = {
chainId: 42220,
name: "Celo",
currency: "CELO",
explorerUrl: "https://explorer.celo.org/mainnet",
rpcUrl: getBlockchainApiRpcUrl(42220),
};

export const base = {
chainId: 8453,
name: "Base",
currency: "BASE",
explorerUrl: "https://basescan.org",
rpcUrl: getBlockchainApiRpcUrl(8453),
};

export const aurora = {
chainId: 1313161554,
name: "Aurora",
currency: "ETH",
explorerUrl: "https://explorer.aurora.dev",
rpcUrl: getBlockchainApiRpcUrl(1313161554),
};

export const sepolia = {
chainId: 11155111,
name: "Sepolia",
currency: "ETH",
explorerUrl: "https://sepolia.etherscan.io",
rpcUrl: getBlockchainApiRpcUrl(11155111),
};

export const baseSepolia = {
chainId: 84532,
name: "Base Sepolia",
Expand All @@ -120,30 +16,6 @@ export const baseSepolia = {
rpcUrl: getBlockchainApiRpcUrl(84532),
};

export const solana = {
chainId: "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
name: "Solana",
currency: "SOL",
explorerUrl: "https://solscan.io",
rpcUrl: "https://rpc.walletconnect.org/v1",
};

export const solanaTestnet = {
chainId: "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z",
name: "Solana Testnet",
currency: "SOL",
explorerUrl: "https://explorer.solana.com/?cluster=testnet",
rpcUrl: "https://rpc.walletconnect.org/v1",
};

export const solanaDevnet = {
chainId: "EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
name: "Solana Devnet",
currency: "SOL",
explorerUrl: "https://explorer.solana.com/?cluster=devnet",
rpcUrl: "https://rpc.walletconnect.org/v1",
};

export function getChain(id: number) {
const chains = Object.values(viemChains) as viemChains.Chain[];

Expand Down
2 changes: 1 addition & 1 deletion advanced/dapps/dca-dapp-demo/src/utils/DCAUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function getSampleAsyncDCAPermissions(
target: donutContractAddress,
abi: donutContractAbi,
valueLimit: parseEther("10").toString(),
functionName: "function purchase()",
functionName: "purchase(uint256)",
},
policies: [],
},
Expand Down
2 changes: 1 addition & 1 deletion advanced/dapps/dca-dapp-demo/src/utils/DonutContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ export const abi = [
},
];

export const address = "0xfcfCFD8D9f4A23D8DD11b03b212B69262A3ba1b8";
export const address = "0x2E65BAfA07238666c3b239E94F32DaD3cDD6498D";
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import { type GrantPermissionsReturnType } from "viem/experimental";
import { bigIntReplacer } from "./CommonUtils";
import { signMessage } from "viem/accounts";
import { type Chain } from "viem";
import { WalletConnectCosigner } from "./WalletConnectCosignerUtils";
import {
buildUserOp,
sendUserOp,
type Call,
type FillUserOpResponse,
} from "./UserOpBuilderServiceUtils";

export type MultikeySigner = {
Expand All @@ -16,102 +15,52 @@ export type MultikeySigner = {
};
};

async function prepareUserOperationWithPermissions(args: {
export async function executeActionsWithECDSAAndCosignerPermissions(args: {
actions: Call[];
ecdsaPrivateKey: `0x${string}`;
chain: Chain;
permissions: GrantPermissionsReturnType;
}): Promise<FillUserOpResponse> {
const { actions, chain, permissions } = args;
pci: string;
}): Promise<`0x${string}`> {
const { ecdsaPrivateKey, actions, chain, permissions, pci } = args;
if (!pci) {
throw new Error("No WC_COSIGNER PCI data available");
}
if (!permissions) {
throw new Error("No permissions available");
}
const { signerData, permissionsContext } = permissions;

if (
!signerData?.userOpBuilder ||
!signerData.submitToAddress ||
!permissionsContext
) {
if (!signerData?.submitToAddress || !permissionsContext) {
throw new Error(
`Invalid permissions ${JSON.stringify(permissions, bigIntReplacer)}`,
);
}
const accountAddress = signerData.submitToAddress;

const filledUserOp = await buildUserOp({
account: signerData.submitToAddress,
account: accountAddress,
chainId: chain.id,
calls: actions,
capabilities: {
permissions: { context: permissionsContext as `0x${string}` },
},
});

return filledUserOp;
}

async function signUserOperationWithECDSAKey(args: {
ecdsaPrivateKey: `0x${string}`;
userOpHash: `0x${string}`;
}): Promise<`0x${string}`> {
const { ecdsaPrivateKey, userOpHash } = args;
const userOp = filledUserOp.userOp;

const dappSignatureOnUserOp = await signMessage({
const dappSignature = await signMessage({
privateKey: ecdsaPrivateKey,
message: { raw: userOpHash },
message: { raw: filledUserOp.hash },
});
userOp.signature = dappSignature;

return dappSignatureOnUserOp;
}

export async function executeActionsWithECDSAAndCosignerPermissions(args: {
actions: Call[];
ecdsaPrivateKey: `0x${string}`;
chain: Chain;
permissions: GrantPermissionsReturnType;
pci: string;
}): Promise<`0x${string}`> {
const { ecdsaPrivateKey, actions, chain, permissions, pci } = args;
const accountAddress = permissions?.signerData?.submitToAddress;
if (!accountAddress) {
throw new Error(`Unable to get account details from granted permission`);
}

if (!pci) {
throw new Error("No WC_COSIGNER PCI data available");
}
const caip10Address = `eip155:${chain?.id}:${accountAddress}`;
const filledUserOp = await prepareUserOperationWithPermissions({
actions,
chain,
permissions,
});
const userOp = filledUserOp.userOp;

const dappSignature = await signUserOperationWithECDSAKey({
ecdsaPrivateKey,
userOpHash: filledUserOp.hash,
const sendUserOpResponse = await sendUserOp({
userOp,
pci,
chainId: chain.id,
permissionsContext: permissionsContext as `0x${string}`,
});

userOp.signature = dappSignature;
const walletConnectCosigner = new WalletConnectCosigner();
const cosignResponse = await walletConnectCosigner.coSignUserOperation(
caip10Address,
{
pci,
userOp: {
...userOp,
callData: userOp.callData,
callGasLimit: BigInt(userOp.callGasLimit),
nonce: BigInt(userOp.nonce),
preVerificationGas: BigInt(userOp.preVerificationGas),
verificationGasLimit: BigInt(userOp.verificationGasLimit),
sender: userOp.sender,
signature: userOp.signature,
maxFeePerGas: BigInt(userOp.maxFeePerGas),
maxPriorityFeePerGas: BigInt(userOp.maxPriorityFeePerGas),
},
},
);
console.log("Cosign response:", cosignResponse);
return cosignResponse.receipt as `0x${string}`;
return sendUserOpResponse.userOpId;
}
Loading

0 comments on commit 65c5723

Please sign in to comment.