Untitled

 avatar
unknown
plain_text
8 days ago
4.1 kB
3
Indexable
import { Address, createPublicClient, Hex, http, HttpTransport, PublicClient } from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { arbitrum, Chain } from "viem/chains"
import { createKernelAccount, CreateKernelAccountReturnType } from "../accounts/index.js"
import { KernelPluginManager, KernelValidator } from "../types/kernel.js"
import { switchChain } from "viem/actions"

export { KernelEIP1193Provider } from "./KernelEIP1193Provider.js"

const privateKey = generatePrivateKey()
const signer = privateKeyToAccount(privateKey)

// Construct a public client
const publicClient = createPublicClient({
  // Use your own RPC provider (e.g. Infura/Alchemy).
  transport: http(""),
  chain: arbitrum,
})

// Construct a validator
const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
  signer,
  entryPoint,
  kernelVersion
})

// Construct a Kernel account
const account = await createKernelAccount(publicClient, {
  plugins: {
    sudo: ecdsaValidator,
  },
  entryPoint,
  kernelVersion
})

type KernelMultichainParams<TEntryPointVersion extends EntryPointVersion> = {
    chains: [Chain, ...Chain[]],
    entryPoint: TEntryPointVersion,
    kernelVersion: string,
    clientFactory: (chain: Chain) => PublicClient<HttpTransport, Chain>,
    pluginFactory: (chain: Chain) => KernelPluginManager<TEntryPointVersion>;
}

type ServerIntent = {
    openInfos: {
        chain: number;
        amount: bigint;
        address: Address;
        calldata: Hex;
    }[]
    destination: {
        chain: number;
        address: Address;
        calldatas: Hex[];
    }
}

type MultichainKernelClient = CreateKernelAccountReturnType<> & {
    currentChain: Chain;
    switchChain: (chain: Chain) => Promise<void>
    handleServerIntent: (intent: ServerIntent) => Promise<boolean>
}


const clientCache = new Map<number, PublicClient<HttpTransport, Chain>>()
const pluginCache = new Map<number, KernelPluginManager<string>>()
const accountCache = new Map<number, CreateKernelAccountReturnType<string>>()

export function createMultichainKernel<TEntryPointVersion extends EntryPointVersion>(
    {chains, entryPoint, kernelVersion, clientFactory, pluginFactory}: KernelMultichainParams<TEntryPointVersion>
): MultichainKernelClient {
    const getClient = (chain: Chain) => {
        if (clientCache.get(chain.id)) {
            return clientCache.get(chain.id)
        }

        const newClient = clientFactory(chain);
        clientCache.set(chain.id, newClient)
        return newClient;
    }

    const getPluginFactory = (chain: Chain) => {
        if (pluginCache.get(chain.id)) {
            return pluginCache.get(chain.id)
        }

        const newPlugin = pluginFactory(chain);
        pluginCache.set(chain.id, newPlugin)
        return newPlugin;
    }

    const getAccount = (chain: Chain) => {
        if (accountCache.get(chain.id)) {
            return accountCache.get(chain.id)
        }
        
        const client = getClient(currentchain);
        const plugin = getPluginFactory(currentchain);
        return createKernelAccount(client, {
            plugins: plugin,
            entryPoint,
            kernelVersion
          });
    }


    const handleServerIntent = async (intent: ServerIntent) => {
        const waitingPromises: Promise<void>[] = [];


        for (const open of intent.openInfos) {
            const client = await getAccount(open.chain);

            const userOpHash = await client.sendUserUserOp({
                tx: {
                    to: open.address,
                    value: open.amount,
                    data: open.calldata,
                }
            })
            // user op process + wait for user op
            waitingPromises.push(client.waitForUserOp(userOpHash))
        }

        await Promise.all(waitingPromises);
    }

    let currentchain = chains[0];

    let account = getAccount(currentchain);

      return {
        ...acount,
        currentChain: currentchain,
        switchChain: (chain: Chain) => {
            currentchain = chain;
            account = getAccount(chain);
        },

      }
}
Leave a Comment