Skip to content

Commit

Permalink
Mint NFT with session key
Browse files Browse the repository at this point in the history
  • Loading branch information
duanyytop committed Dec 23, 2023
1 parent 5abed63 commit 779a65e
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 4 deletions.
78 changes: 76 additions & 2 deletions src/components/EvmAA.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
import {useState} from "react";
import {Hex, stringToBytes} from "viem";
import {Hex, stringToBytes, parseAbi, encodeFunctionData} from "viem";
import {LocalAccountSigner} from "@alchemy/aa-core"
import {SessionKeyProvider, getPermissionFromABI, ParamOperator, constants} from "@zerodev/sdk";
import {useWebApp} from "@vkruglikov/react-telegram-web-app";
import {WebApp} from "@vkruglikov/react-telegram-web-app/lib/core/twa-types";
import { useAaAddress, useCurrentAddress, useUpdateAaAddress } from "../hooks/useAccount";
import { JoySigner } from "../evm-aa/signer";
import { getAAProvider } from "../evm-aa/provider";
import { ECDSAProvider } from "@zerodev/sdk";
import { useEffect } from "react";
import { TEST_SESSION_KEY, ZERO_DEV_PROJECT_ID } from "../env";

// The NFT contract we will be interacting with
const contractAddress = '0x34bE7f35132E97915633BC1fc020364EA5134863'
const contractABI = parseAbi([
'function mint(address _to) public',
'function balanceOf(address owner) external view returns (uint256 balance)'
])

export const EvmAA = () => {
const address = useCurrentAddress();
const aaAddress = useAaAddress()
const updateAaAddress = useUpdateAaAddress();
const [provider, setProvider] = useState<ECDSAProvider>();
const [signature, setSignature] = useState<Hex>();
const [sessionKeyProvider, setSessionKeyProvider] = useState<SessionKeyProvider>();
const [sessionAddress, setSessionAddress] = useState<Hex>();
const webApp = useWebApp() as WebApp;

const [createLoading, setCreateLoading] = useState(false);
const [signLoading, setSignLoading] = useState(false);
const [createSessionLoading, setCreateSessionLoading] = useState(false);
const [sessionMintLoading, setSessionMintLoading] = useState(false);

useEffect(() => {
const init = async () => {
Expand All @@ -29,7 +43,7 @@ export const EvmAA = () => {

const onCreate = async () => {
setCreateLoading(true);
const aaAddr = await provider?.account?.getAddress();
const aaAddr = await provider?.getAddress();
updateAaAddress(aaAddr);
setCreateLoading(false);
};
Expand All @@ -42,6 +56,54 @@ export const EvmAA = () => {
setSignLoading(false)
};

const onCreateSessionKey = async () => {
setCreateSessionLoading(true);
const sessionKey = LocalAccountSigner.privateKeyToAccountSigner(TEST_SESSION_KEY);
const sessionProvider = await SessionKeyProvider.init({
projectId: ZERO_DEV_PROJECT_ID,
defaultProvider: provider,
sessionKey: sessionKey!,
sessionKeyData: {
validAfter: 0,
validUntil: 0,
permissions: [
getPermissionFromABI({
target: contractAddress,
valueLimit: 0n,
abi: contractABI,
functionName: "mint",
args: [
{
operator: ParamOperator.EQUAL,
value: aaAddress!,
},
],
}),
],
paymaster: constants.oneAddress,
},
});
setSessionKeyProvider(sessionProvider)
const addr = await sessionKey.getAddress();
setSessionAddress(addr);
setCreateSessionLoading(false);
};

const mintWithSessionKey = async () => {
setSessionMintLoading(true)
const {hash} = await sessionKeyProvider!.sendUserOperation({
target: contractAddress,
data: encodeFunctionData({
abi: contractABI,
functionName: "mint",
args: [aaAddress!],
}),
});
await sessionKeyProvider!.waitForUserOperationTransaction(hash as Hex);
alert(`Mint NFT with Session Key tx hash: ${hash}`)
setSessionMintLoading(false);
}

return (
<div>
<button className="btn btn-primary capitalize w-[200px]" onClick={onCreate}>
Expand All @@ -61,6 +123,18 @@ export const EvmAA = () => {
<div className="break-words">{signature}</div>
</div>
)}

<button className="btn btn-primary capitalize w-[200px] mt-[24px]" onClick={onCreateSessionKey}>
{createSessionLoading ? <span className="loading loading-spinner loading-md" /> : "Create Session Key"}
</button>
{sessionAddress && (
<div className="mt-[12px]">
<div>{`Session Key Address: ${sessionAddress}`}</div>
<button className="btn btn-primary capitalize w-[240px] mt-[12px]" onClick={mintWithSessionKey}>
{sessionMintLoading ? <span className="loading loading-spinner loading-md" /> : "Mint NFT with Session Key"}
</button>
</div>
)}
</div>
)}
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/env/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const CALLBACK_SERVER_URL = import.meta.env.VITE_APP_CALLBACK_SERVER_URL ?? "";
export const JOYID_APP_URL = import.meta.env.VITE_APP_JOYID_APP_URL ?? "https://testnet.joyid.dev/";
export const JOYID_APP_URL = import.meta.env.VITE_APP_JOYID_APP_URL ?? "https://testnet.joyid.dev";
export const ZERO_DEV_PROJECT_ID = import.meta.env.VITE_APP_ZERO_DEV_PROJECT_ID ?? "";
export const TEST_SESSION_KEY = import.meta.env.VITE_APP_TEST_SESSION_KEY ?? "0x0000000000000000000000000000000000000000000000000000000000000001";
2 changes: 1 addition & 1 deletion src/evm-aa/signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class JoySigner implements SmartAccountSigner {
console.error(error);
}
}
});
});
return promise;
};

Expand Down

0 comments on commit 779a65e

Please sign in to comment.