diff

作成日 差分は期限切れになりません
18 削除
146
25 追加
153
import "dotenv/config"
import "dotenv/config"
import {
import {
createKernelAccount,
createKernelAccount,
createZeroDevPaymasterClient,
createZeroDevPaymasterClient,
createKernelAccountClient,
createKernelAccountClient,
addressToEmptyAccount,
} from "@zerodev/sdk"
} from "@zerodev/sdk"
import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator"
import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator"
import {
import {
signerToSessionKeyValidator,
signerToSessionKeyValidator,
ParamOperator,
ParamOperator,
serializeSessionKeyAccount,
serializeSessionKeyAccount,
deserializeSessionKeyAccount,
deserializeSessionKeyAccount,
oneAddress,
oneAddress,
} from "@zerodev/session-key"
} from "@zerodev/session-key"
import { UserOperation } from "permissionless"
import { UserOperation } from "permissionless"
import {
import {
http,
http,
Hex,
Hex,
createPublicClient,
createPublicClient,
parseAbi,
parseAbi,
encodeFunctionData,
encodeFunctionData,
Address,
} from "viem"
} from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { polygonMumbai } from "viem/chains"
import { polygonMumbai } from "viem/chains"


if (
if (
!process.env.BUNDLER_RPC ||
!process.env.BUNDLER_RPC ||
!process.env.PAYMASTER_RPC ||
!process.env.PAYMASTER_RPC ||
!process.env.PRIVATE_KEY
!process.env.PRIVATE_KEY
) {
) {
throw new Error("BUNDLER_RPC or PAYMASTER_RPC or PRIVATE_KEY is not set")
throw new Error("BUNDLER_RPC or PAYMASTER_RPC or PRIVATE_KEY is not set")
}
}


const publicClient = createPublicClient({
const publicClient = createPublicClient({
chain: polygonMumbai,
transport: http(process.env.BUNDLER_RPC),
transport: http(process.env.BUNDLER_RPC),
})
})


const signer = privateKeyToAccount(process.env.PRIVATE_KEY as Hex)
const signer = privateKeyToAccount(process.env.PRIVATE_KEY as Hex)
const contractAddress = "0x34bE7f35132E97915633BC1fc020364EA5134863"
const contractAddress = "0x34bE7f35132E97915633BC1fc020364EA5134863"
const contractABI = parseAbi([
const contractABI = parseAbi([
"function mint(address _to) public",
"function mint(address _to) public",
"function balanceOf(address owner) external view returns (uint256 balance)",
"function balanceOf(address owner) external view returns (uint256 balance)",
])
])
const sessionPrivateKey = generatePrivateKey()
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey)

const createSessionKey = async () => {


const createSessionKey = async (sessionKeyAddress: Address) => {
const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
signer,
signer,
})
})


const masterAccount = await createKernelAccount(publicClient, {
const masterAccount = await createKernelAccount(publicClient, {
plugins: {
plugins: {
sudo: ecdsaValidator,
sudo: ecdsaValidator,
},
},
})
})
console.log("Account address:", masterAccount.address)
console.log("Account address:", masterAccount.address)


// Create an "empty account" as the signer -- you only need the public
// key (address) to do this.
const emptySessionKeySigner = addressToEmptyAccount(sessionKeyAddress)

const sessionKeyValidator = await signerToSessionKeyValidator(publicClient, {
const sessionKeyValidator = await signerToSessionKeyValidator(publicClient, {
signer: sessionKeySigner,
signer: emptySessionKeySigner,
validatorData: {
validatorData: {
paymaster: oneAddress,
paymaster: oneAddress,
permissions: [
permissions: [
{
{
target: contractAddress,
target: contractAddress,
// Maximum value that can be transferred. In this case we
// Maximum value that can be transferred. In this case we
// set it to zero so that no value transfer is possible.
// set it to zero so that no value transfer is possible.
valueLimit: BigInt(0),
valueLimit: BigInt(0),
// Contract abi
// Contract abi
abi: contractABI,
abi: contractABI,
// Function name
// Function name
functionName: "mint",
functionName: "mint",
// An array of conditions, each corresponding to an argument for
// An array of conditions, each corresponding to an argument for
// the function.
// the function.
args: [
args: [
{
{
// In this case, we are saying that the session key can only mint
// In this case, we are saying that the session key can only mint
// NFTs to the account itself
// NFTs to the account itself
operator: ParamOperator.EQUAL,
operator: ParamOperator.EQUAL,
value: masterAccount.address,
value: masterAccount.address,
},
},
],
],
},
},
],
],
},
},
})
})


const sessionKeyAccount = await createKernelAccount(publicClient, {
const sessionKeyAccount = await createKernelAccount(publicClient, {
plugins: {
plugins: {
sudo: ecdsaValidator,
sudo: ecdsaValidator,
regular: sessionKeyValidator,
regular: sessionKeyValidator,
},
},
})
})


// Include the private key when you serialize the session key
return await serializeSessionKeyAccount(sessionKeyAccount)
return await serializeSessionKeyAccount(sessionKeyAccount, sessionPrivateKey)
}
}


const useSessionKey = async (serializedSessionKey: string) => {
const useSessionKey = async (serializedSessionKey: string, sessionKeySigner: any) => {
const sessionKeyAccount = await deserializeSessionKeyAccount(publicClient, serializedSessionKey)
const sessionKeyAccount = await deserializeSessionKeyAccount(publicClient, serializedSessionKey, sessionKeySigner)


const kernelClient = createKernelAccountClient({
const kernelClient = createKernelAccountClient({
account: sessionKeyAccount,
account: sessionKeyAccount,
chain: polygonMumbai,
chain: polygonMumbai,
transport: http(process.env.BUNDLER_RPC),
transport: http(process.env.BUNDLER_RPC),
sponsorUserOperation: async ({ userOperation }): Promise<UserOperation> => {
sponsorUserOperation: async ({ userOperation }): Promise<UserOperation> => {
const kernelPaymaster = createZeroDevPaymasterClient({
const kernelPaymaster = createZeroDevPaymasterClient({
chain: polygonMumbai,
chain: polygonMumbai,
transport: http(process.env.PAYMASTER_RPC),
transport: http(process.env.PAYMASTER_RPC),
})
})
return kernelPaymaster.sponsorUserOperation({
return kernelPaymaster.sponsorUserOperation({
userOperation,
userOperation,
})
})
},
},
})
})


const userOpHash = await kernelClient.sendUserOperation({
const userOpHash = await kernelClient.sendUserOperation({
userOperation: {
userOperation: {
callData: await sessionKeyAccount.encodeCallData({
callData: await sessionKeyAccount.encodeCallData({
to: contractAddress,
to: contractAddress,
value: BigInt(0),
value: BigInt(0),
data: encodeFunctionData({
data: encodeFunctionData({
abi: contractABI,
abi: contractABI,
functionName: "mint",
functionName: "mint",
args: [sessionKeyAccount.address],
args: [sessionKeyAccount.address],
}),
}),
}),
}),
},
},
})
})


console.log("userOp hash:", userOpHash)
console.log("userOp hash:", userOpHash)
}
}


const main = async () => {
const main = async () => {


// The owner creates a session key, serializes it, and shares it with the agent.
// The agent creates a public-private key pair and sends
const serializedSessionKey = await createSessionKey()
// the public key (address) to the owner.
const sessionPrivateKey = generatePrivateKey()
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey)


// The agent reconstructs the session key using the serialized value
// The owner authorizes the public key by signing it and sending
await useSessionKey(serializedSessionKey)
// back the signature
const serializedSessionKey = await createSessionKey(sessionKeySigner.address)

// The agent constructs a full session key
await useSessionKey(serializedSessionKey, sessionKeySigner)


}
}


main()
main()