diff --git a/examples/nft-quest-contracts/deploy/deploy.ts b/examples/nft-quest-contracts/deploy/deploy.ts index 102bb304..12ce4fc5 100644 --- a/examples/nft-quest-contracts/deploy/deploy.ts +++ b/examples/nft-quest-contracts/deploy/deploy.ts @@ -1,11 +1,8 @@ import { formatEther, parseEther } from "ethers"; -import fs from "fs"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; -import path from "path"; import { deployContract, getProvider, getWallet } from "./utils"; -export default async function (hre: HardhatRuntimeEnvironment) { +export default async function () { const provider = getProvider(); const baseTokenURI = "https://nft.zksync.dev/nft/metadata.json"; @@ -16,24 +13,6 @@ export default async function (hre: HardhatRuntimeEnvironment) { console.log("NFT CONTRACT: ", await nftContract.getAddress()); console.log("PAYMASTER CONTRACT: ", await paymasterContract.getAddress()); - if (hre.network.config.ethNetwork.includes("localhost")) { - // Update the .env.local file with the contract addresses for NFT Quest app - const envFilePath = path.join(__dirname, "../../nft-quest/.env.local"); - - // Check if the .env.local file exists, if not, create it - if (!fs.existsSync(envFilePath)) { - fs.writeFileSync(envFilePath, "", { encoding: "utf8" }); - console.log(`.env.local file has been created at ${envFilePath}`); - } - const nftContractAddress = await nftContract.getAddress(); - const paymasterContractAddress = await paymasterContract.getAddress(); - - const envContent = `NUXT_PUBLIC_CONTRACTS_NFT=${nftContractAddress}\nNUXT_PUBLIC_CONTRACTS_PAYMASTER=${paymasterContractAddress}\n`; - - fs.writeFileSync(envFilePath, envContent, { encoding: "utf8" }); - console.log(`.env.local file has been updated at ${envFilePath}`); - } - // fund the paymaster contract with enough ETH to pay for transactions const wallet = getWallet(); await ( diff --git a/examples/nft-quest/README.md b/examples/nft-quest/README.md index 16da1531..ec19a42b 100644 --- a/examples/nft-quest/README.md +++ b/examples/nft-quest/README.md @@ -15,13 +15,9 @@ pnpm nx deploy contracts pnpm nx deploy:local nft-quest-contracts ``` -The contract addresses for the NFT Quest app will be set in `.env.local`. This -.env file will override the values set in the `runtimeConfig` in -`nuxt.config.ts`. - -You may also need to update the contract addresses for the Auth Server in -`/packages/auth-server/stores/client.ts` under the -`contractsByChain[zksyncInMemoryNode.id]` +Contract addresses are defined in the `/packages/auth-server/abi` directory. For +local development using In Memory Node, edit the contracts' `addressByChain` for +`260`. ```sh # Start the website and Auth Server diff --git a/examples/nft-quest/abi/index.ts b/examples/nft-quest/abi/index.ts new file mode 100644 index 00000000..cd46abe3 --- /dev/null +++ b/examples/nft-quest/abi/index.ts @@ -0,0 +1,2 @@ +export * as Nft from "./nft"; +export * as Paymaster from "./paymaster"; diff --git a/examples/nft-quest/abi/ZeekNFTQuest.ts b/examples/nft-quest/abi/nft.ts similarity index 97% rename from examples/nft-quest/abi/ZeekNFTQuest.ts rename to examples/nft-quest/abi/nft.ts index 162d1d24..05ddb710 100644 --- a/examples/nft-quest/abi/ZeekNFTQuest.ts +++ b/examples/nft-quest/abi/nft.ts @@ -1,4 +1,11 @@ -export const ZeekNftQuestAbi = [ +import type { AddressByChain } from "./types"; + +export const addressByChain: AddressByChain = { + 300: "0x4D533d3B20b50b57268f189F93bFaf8B39c36AB6", + 260: "0x111C3E89Ce80e62EE88318C2804920D4c96f92bb", +}; + +export const Abi = [ { inputs: [ { diff --git a/examples/nft-quest/abi/paymaster.ts b/examples/nft-quest/abi/paymaster.ts new file mode 100644 index 00000000..9489e092 --- /dev/null +++ b/examples/nft-quest/abi/paymaster.ts @@ -0,0 +1,6 @@ +import type { AddressByChain } from "./types"; + +export const addressByChain: AddressByChain = { + 300: "0x60eef092977DF2738480a6986e2aCD10236b1FA7", + 260: "0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021", +}; diff --git a/examples/nft-quest/abi/types.d.ts b/examples/nft-quest/abi/types.d.ts new file mode 100644 index 00000000..d8d743f6 --- /dev/null +++ b/examples/nft-quest/abi/types.d.ts @@ -0,0 +1,5 @@ +import type { Address } from "viem"; + +export type AddressByChain = { + [k in SupportedChainId]: Address; +}; diff --git a/examples/nft-quest/composables/useMintNft.ts b/examples/nft-quest/composables/useMintNft.ts index bd630811..c4d4c65f 100644 --- a/examples/nft-quest/composables/useMintNft.ts +++ b/examples/nft-quest/composables/useMintNft.ts @@ -2,20 +2,25 @@ import { waitForTransactionReceipt, writeContract } from "@wagmi/core"; import type { Address } from "viem"; import { getGeneralPaymasterInput } from "viem/zksync"; +import { Nft, Paymaster } from "~/abi"; +import type { SupportedChainId } from "~/stores/connector"; + export const useMintNft = async (_address: MaybeRef
) => { const address = toRef(_address); return await useAsyncData("mintZeek", async () => { const runtimeConfig = useRuntimeConfig(); const { wagmiConfig } = storeToRefs(useConnectorStore()); + const chainId = runtimeConfig.public.defaultChainId as SupportedChainId; const mintingForAddress = address.value; + const transactionHash = await writeContract(wagmiConfig.value, { - address: runtimeConfig.public.contracts.nft as Address, - abi: nftAbi, + address: Nft.addressByChain[chainId] as Address, + abi: Nft.Abi, functionName: "mint", args: [mintingForAddress], - paymaster: runtimeConfig.public.contracts.paymaster as Address, + paymaster: Paymaster.addressByChain[chainId] as Address, paymasterInput: getGeneralPaymasterInput({ innerInput: "0x" }), }); diff --git a/examples/nft-quest/index.d.ts b/examples/nft-quest/index.d.ts index 0e56b52a..06dc9283 100644 --- a/examples/nft-quest/index.d.ts +++ b/examples/nft-quest/index.d.ts @@ -1,12 +1,6 @@ -import type { Chain } from "viem"; - declare module "nuxt/schema" { interface PublicRuntimeConfig { - chain: Chain; - contracts: { - nft: `0x${string}`; - paymaster: `0x${string}`; - }; + defaultChainId: number; baseUrl: string; authServerUrl: string; explorerUrl: string; diff --git a/examples/nft-quest/nuxt.config.ts b/examples/nft-quest/nuxt.config.ts index 05a85510..032d2b21 100644 --- a/examples/nft-quest/nuxt.config.ts +++ b/examples/nft-quest/nuxt.config.ts @@ -19,11 +19,7 @@ export default defineNuxtConfig({ $production: { runtimeConfig: { public: { - chain: zksyncSepoliaTestnet, - contracts: { - nft: "0x4D533d3B20b50b57268f189F93bFaf8B39c36AB6", - paymaster: "0x60eef092977DF2738480a6986e2aCD10236b1FA7", - }, + defaultChainId: zksyncSepoliaTestnet.id, baseUrl: "https://nft.zksync.dev", authServerUrl: "https://auth-test.zksync.dev/confirm", explorerUrl: "https://sepolia.explorer.zksync.io", @@ -57,11 +53,7 @@ export default defineNuxtConfig({ }, runtimeConfig: { public: { - chain: zksyncInMemoryNode, - contracts: { - nft: "0x111C3E89Ce80e62EE88318C2804920D4c96f92bb", - paymaster: "0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021", - }, + defaultChainId: zksyncInMemoryNode.id, baseUrl: "http://localhost:3006", authServerUrl: "http://localhost:3002/confirm", explorerUrl: "http://localhost:3010", diff --git a/examples/nft-quest/stores/connector.ts b/examples/nft-quest/stores/connector.ts index 50a1a06c..a052acf5 100644 --- a/examples/nft-quest/stores/connector.ts +++ b/examples/nft-quest/stores/connector.ts @@ -1,20 +1,24 @@ import { connect, createConfig, type CreateConnectorFn, disconnect, getAccount, http, reconnect, watchAccount } from "@wagmi/core"; -import { zksyncInMemoryNode, zksyncLocalNode, zksyncSepoliaTestnet } from "@wagmi/core/chains"; -import { type Address, type Hash, parseEther } from "viem"; +import { zksyncInMemoryNode, zksyncSepoliaTestnet } from "@wagmi/core/chains"; +import { type Address, parseEther } from "viem"; import { callPolicy, zksyncSsoConnector } from "zksync-sso/connector"; -import { ZeekNftQuestAbi } from "@/abi/ZeekNFTQuest"; +import { Nft } from "~/abi"; + +export type SupportedChainId = (typeof supportedChains)[number]["id"]; + +const supportedChains = [ + zksyncSepoliaTestnet, + zksyncInMemoryNode, +] as const; export const useConnectorStore = defineStore("connector", () => { const runtimeConfig = useRuntimeConfig(); - const supportedChains = [ - zksyncSepoliaTestnet, - zksyncInMemoryNode, - zksyncLocalNode, - ] as const; - const chain = supportedChains.filter((x) => x.id == runtimeConfig.public.chain.id)[0]; + + const chainId = runtimeConfig.public.defaultChainId; + const chain = supportedChains.filter((x) => x.id == chainId)[0]; type SupportedChainId = (typeof supportedChains)[number]["id"]; - if (!chain) throw new Error(`Chain with id ${runtimeConfig.public.chain.id} was not found in supported chains list`); + if (!chain) throw new Error(`Chain with id ${chainId} was not found in supported chains list`); const connector = zksyncSsoConnector({ metadata: { @@ -25,8 +29,8 @@ export const useConnectorStore = defineStore("connector", () => { feeLimit: parseEther("0.001"), contractCalls: [ callPolicy({ - address: runtimeConfig.public.contracts.nft as Hash, - abi: ZeekNftQuestAbi, + address: Nft.addressByChain[chainId], + abi: Nft.Abi, functionName: "mint", }), ], diff --git a/examples/nft-quest/utils/abi.ts b/examples/nft-quest/utils/abi.ts deleted file mode 100644 index ff3e0a10..00000000 --- a/examples/nft-quest/utils/abi.ts +++ /dev/null @@ -1,21 +0,0 @@ -export const nftAbi = [ - { - inputs: [ - { - internalType: "address", - name: "to", - type: "address", - }, - ], - name: "mint", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ] as const, - stateMutability: "nonpayable", - type: "function", - }, -]; diff --git a/packages/auth-server/abi/index.ts b/packages/auth-server/abi/index.ts new file mode 100644 index 00000000..c8c66e7f --- /dev/null +++ b/packages/auth-server/abi/index.ts @@ -0,0 +1,2 @@ +export * as NFTQuest from "./nft-quest"; +export * as SSO from "./sso"; diff --git a/packages/auth-server/abi/nft-quest/index.ts b/packages/auth-server/abi/nft-quest/index.ts new file mode 100644 index 00000000..cd46abe3 --- /dev/null +++ b/packages/auth-server/abi/nft-quest/index.ts @@ -0,0 +1,2 @@ +export * as Nft from "./nft"; +export * as Paymaster from "./paymaster"; diff --git a/packages/auth-server/abi/ZeekNFTQuest.ts b/packages/auth-server/abi/nft-quest/nft.ts similarity index 97% rename from packages/auth-server/abi/ZeekNFTQuest.ts rename to packages/auth-server/abi/nft-quest/nft.ts index 162d1d24..a92be8d4 100644 --- a/packages/auth-server/abi/ZeekNFTQuest.ts +++ b/packages/auth-server/abi/nft-quest/nft.ts @@ -1,4 +1,11 @@ -export const ZeekNftQuestAbi = [ +import type { AddressByChain } from "../types"; + +export const addressByChain: AddressByChain = { + 300: "0x4D533d3B20b50b57268f189F93bFaf8B39c36AB6", + 260: "0x111C3E89Ce80e62EE88318C2804920D4c96f92bb", +}; + +export const Abi = [ { inputs: [ { diff --git a/packages/auth-server/abi/nft-quest/paymaster.ts b/packages/auth-server/abi/nft-quest/paymaster.ts new file mode 100644 index 00000000..f33cbb0b --- /dev/null +++ b/packages/auth-server/abi/nft-quest/paymaster.ts @@ -0,0 +1,351 @@ +import type { AddressByChain } from "../types"; + +export const addressByChain: AddressByChain = { + 300: "0x60eef092977DF2738480a6986e2aCD10236b1FA7", + 260: "0x4B5DF730c2e6b28E17013A1485E5d9BC41Efe021", +}; + +export const Abi = [ + { + inputs: [ + { + internalType: "address", + name: "nftContractAddress", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + inputs: [], + name: "MINT_SELECTOR", + outputs: [ + { + internalType: "bytes4", + name: "", + type: "bytes4", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "ZEEK_NFT_CONTRACT_ADDRESS", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes", + name: "_context", + type: "bytes", + }, + { + components: [ + { + internalType: "uint256", + name: "txType", + type: "uint256", + }, + { + internalType: "uint256", + name: "from", + type: "uint256", + }, + { + internalType: "uint256", + name: "to", + type: "uint256", + }, + { + internalType: "uint256", + name: "gasLimit", + type: "uint256", + }, + { + internalType: "uint256", + name: "gasPerPubdataByteLimit", + type: "uint256", + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256", + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256", + }, + { + internalType: "uint256", + name: "paymaster", + type: "uint256", + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "uint256[4]", + name: "reserved", + type: "uint256[4]", + }, + { + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + internalType: "bytes", + name: "signature", + type: "bytes", + }, + { + internalType: "bytes32[]", + name: "factoryDeps", + type: "bytes32[]", + }, + { + internalType: "bytes", + name: "paymasterInput", + type: "bytes", + }, + { + internalType: "bytes", + name: "reservedDynamic", + type: "bytes", + }, + ], + internalType: "struct Transaction", + name: "_transaction", + type: "tuple", + }, + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + { + internalType: "enum ExecutionResult", + name: "_txResult", + type: "uint8", + }, + { + internalType: "uint256", + name: "_maxRefundedGas", + type: "uint256", + }, + ], + name: "postTransaction", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + { + components: [ + { + internalType: "uint256", + name: "txType", + type: "uint256", + }, + { + internalType: "uint256", + name: "from", + type: "uint256", + }, + { + internalType: "uint256", + name: "to", + type: "uint256", + }, + { + internalType: "uint256", + name: "gasLimit", + type: "uint256", + }, + { + internalType: "uint256", + name: "gasPerPubdataByteLimit", + type: "uint256", + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256", + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256", + }, + { + internalType: "uint256", + name: "paymaster", + type: "uint256", + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "uint256[4]", + name: "reserved", + type: "uint256[4]", + }, + { + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + internalType: "bytes", + name: "signature", + type: "bytes", + }, + { + internalType: "bytes32[]", + name: "factoryDeps", + type: "bytes32[]", + }, + { + internalType: "bytes", + name: "paymasterInput", + type: "bytes", + }, + { + internalType: "bytes", + name: "reservedDynamic", + type: "bytes", + }, + ], + internalType: "struct Transaction", + name: "_transaction", + type: "tuple", + }, + ], + name: "validateAndPayForPaymasterTransaction", + outputs: [ + { + internalType: "bytes4", + name: "magic", + type: "bytes4", + }, + { + internalType: "bytes", + name: "context", + type: "bytes", + }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { + internalType: "address payable", + name: "_to", + type: "address", + }, + ], + name: "withdraw", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + stateMutability: "payable", + type: "receive", + }, +]; diff --git a/packages/auth-server/abi/sso/account-factory.ts b/packages/auth-server/abi/sso/account-factory.ts new file mode 100644 index 00000000..eda77a29 --- /dev/null +++ b/packages/auth-server/abi/sso/account-factory.ts @@ -0,0 +1,6 @@ +import type { AddressByChain } from "../types"; + +export const addressByChain: AddressByChain = { + 300: "0xf9a9fFF7E55F4375FF5f736c58e29B7D4d68aEfb", + 260: "0xd7385ba726A7b72933E63FCb0Dfee8Bcae63478c", +}; diff --git a/packages/auth-server/abi/sso/account-paymaster.ts b/packages/auth-server/abi/sso/account-paymaster.ts new file mode 100644 index 00000000..8ac1dcfc --- /dev/null +++ b/packages/auth-server/abi/sso/account-paymaster.ts @@ -0,0 +1,6 @@ +import type { AddressByChain } from "../types"; + +export const addressByChain: AddressByChain = { + 300: "0x0cE4c9b3eA74971210C114cc136eAE41148C8B5a", + 260: "0x9966A2f99e4A7ae9FBd6b7111568219B7C0e8E27", +}; diff --git a/packages/auth-server/abi/sso/index.ts b/packages/auth-server/abi/sso/index.ts new file mode 100644 index 00000000..6986ada7 --- /dev/null +++ b/packages/auth-server/abi/sso/index.ts @@ -0,0 +1,4 @@ +export * as AccountFactory from "./account-factory"; +export * as AccountPaymaster from "./account-paymaster"; +export * as Passkey from "./passkey"; +export * as Session from "./session"; diff --git a/packages/auth-server/abi/sso/passkey.ts b/packages/auth-server/abi/sso/passkey.ts new file mode 100644 index 00000000..ab9c99ff --- /dev/null +++ b/packages/auth-server/abi/sso/passkey.ts @@ -0,0 +1,6 @@ +import type { AddressByChain } from "../types"; + +export const addressByChain: AddressByChain = { + 300: "0x86F20D0701c54019F2f58d0f69767A27BA3E724C", + 260: "0x96b5403Bc85469AA3F387Bb468DFFd0fb8A3F767", +}; diff --git a/packages/auth-server/abi/sso/session.ts b/packages/auth-server/abi/sso/session.ts new file mode 100644 index 00000000..24d31fd5 --- /dev/null +++ b/packages/auth-server/abi/sso/session.ts @@ -0,0 +1,6 @@ +import type { AddressByChain } from "../types"; + +export const addressByChain: AddressByChain = { + 300: "0x21fe79B31bE4c54c6B4e13303B379Cd4e4fa9489", + 260: "0x24ceE718D848063d09d2BeaCe31553524AcD366F", +}; diff --git a/packages/auth-server/abi/types.d.ts b/packages/auth-server/abi/types.d.ts new file mode 100644 index 00000000..d8d743f6 --- /dev/null +++ b/packages/auth-server/abi/types.d.ts @@ -0,0 +1,5 @@ +import type { Address } from "viem"; + +export type AddressByChain = { + [k in SupportedChainId]: Address; +}; diff --git a/packages/auth-server/components/dashboard/assets.vue b/packages/auth-server/components/dashboard/assets.vue index eb37f760..fa56a518 100644 --- a/packages/auth-server/components/dashboard/assets.vue +++ b/packages/auth-server/components/dashboard/assets.vue @@ -75,7 +75,7 @@ import { type Address, formatUnits } from "viem"; const runtimeConfig = useRuntimeConfig(); const { address } = useAccountStore(); -const chainId = runtimeConfig.public.chainId as SupportedChainId; +const chainId = runtimeConfig.public.defaultChainId as SupportedChainId; const assets = ref(null); const showLimit = 5; diff --git a/packages/auth-server/components/nft/zeek-nft-quest.vue b/packages/auth-server/components/nft/zeek-nft-quest.vue index ef0560a8..31e5fc84 100644 --- a/packages/auth-server/components/nft/zeek-nft-quest.vue +++ b/packages/auth-server/components/nft/zeek-nft-quest.vue @@ -45,12 +45,12 @@