fix: `AllowlistPaymasterAPI`

fix: AllowlistPaymasterAPI

diff --git a/index.ts b/index.ts
index 80f767b..d29f103 100644
--- a/index.ts
+++ b/index.ts
@@ -1,7 +1,6 @@
-// @ts-nocheck
 import { config } from "dotenv";
 import { ThirdwebSDK } from "@thirdweb-dev/sdk";
-import { defaultAbiCoder } from "ethers/lib/utils";
+import { BytesLike, defaultAbiCoder, hexConcat } from "ethers/lib/utils";
 import {
     SmartWallet,
     SmartWalletConfig,
@@ -12,16 +11,19 @@ import { UserOperationStruct } from "@account-abstraction/contracts";
 import { LocalWalletNode } from "@thirdweb-dev/wallets/evm/wallets/local-wallet-node";
 import { CeloAlfajoresTestnet } from "@thirdweb-dev/chains";
 import { claimCeloToken } from "./sdk-calls";
-import { signUserOp } from "./aa-utils";
+import { NotPromise, signUserOp } from "./aa-utils";
 
+// Environment Variables
 config();
 
-const ENTRYPOINT = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789";
+// Address whose signature is required for the UserOperations to be sponsored by the specified Paymaster
+const PAYMASTER_OWNER = "0xf672cd5Ee805B72804bEE9a40BA7b8dc8F573596";
 
+// Address of the paymaster
 const ALLOWLIST_PAYMASTER_ADDRESS =
     "0x34A00151460C7Bec401D3b24fE86E9C152EE8284";
 
-// Only the following UserOperation sender will be allowed
+// Only the following UserOperation senders will be allowed
 const allowList = ["0xdA82D492a49d08cF732A47Acf34efb51BE351dd6"];
 
 class AllowlistPaymaster extends PaymasterAPI {
@@ -32,30 +34,58 @@ class AllowlistPaymaster extends PaymasterAPI {
         this.allowlist = allowlist;
     }
 
+    /**
+     * This function should return the `paymasterAndData` component of the UserOperation which will be then validated by the on-chain paymaster contract
+     *
+     * Any arbitrary logic can be defined here ultimately the return value should be the value that will lead to successful validation on-chain by `validatePaymasterUserOp` function on the paymaster
+     *
+     * The standard (ERC-4337) structure of paymasterAndData is
+     *
+     * [PAYMASTER_ADDRESS (20 bytes)][VALID_UNTIL (uint48 but encoded so 32 bytes)][VALID_AFTER (uint48 but encoded so 32 bytes)][SIGNATURE (bytes)]
+     */
     async getPaymasterAndData(
         userOp: Partial<UserOperationStruct>
     ): Promise<string> {
-        // Ask the paymaster to sign the transaction and return a valid paymasterAndData value.
-        if (allowList.indexOf(userOp.sender as string) != -1) {
-            let signer = new PrivateKeyWallet(process.env.SIGNER_KEY as string);
-            let validUntil = Date.now() / 1000 + 10 * 60;
-            let signature = signUserOp(
-                userOp,
-                signer,
-                ENTRYPOINT,
-                44787,
-                0,
-                validUntil,
-                0
+        // Check if the UserOperation sender is part of the allowList
+        if (this.allowlist.indexOf(userOp.sender as string) != -1) {
+            // The Paymaster Owner in the form of Wallet
+            let wallet = new PrivateKeyWallet(
+                process.env.PAYMASTER_SIGNER_KEY as string
             );
 
-            let paymasterAndData = defaultAbiCoder.encode(
-                ["address", "uint48", "uint48", "bytes"],
-                [ALLOWLIST_PAYMASTER_ADDRESS, validUntil, 0, signature]
+            // A timestamp in UNIX until which the paymaster sponsorship is valid
+            let validUntil = Math.round(Date.now() / 1000) + 10 * 60;
+
+            /**
+             * UserOperation signed by Paymaster Owner
+             *
+             * The current state of UserOperation doesn't have paymasterAndData and a signature so we have Dummy values for those
+             *
+             */
+            let { signature } = signUserOp(
+                userOp as NotPromise<UserOperationStruct>,
+                await wallet.getSigner(), // The paymaster owner in the form of Signer
+                CeloAlfajoresTestnet.chainId,
+                ALLOWLIST_PAYMASTER_ADDRESS,
+                // TODO: get nonce from the paymaster
+                3, // senderNonce (this nonce is subjective to every paymaster and sender)
+                validUntil,
+                0 // validAfter - Timestamp after which the UserOperation sponsorship should be valid
             );
+
+            /**
+             * Concatenating all the paymasterAndData components
+             */
+            let paymasterAndData = hexConcat([
+                ALLOWLIST_PAYMASTER_ADDRESS,
+                defaultAbiCoder.encode(["uint48", "uint48"], [validUntil, 0]),
+                signature as NotPromise<BytesLike>,
+            ]);
+
             return paymasterAndData;
         }
 
+        // If the sender is not part of the list return nothing
         return "";
     }
 }
@@ -74,16 +104,20 @@ const main = async () => {
     try {
         const factoryAddress = factories[chain.chainId];
         console.log("Running on", chain.slug, "with factory", factoryAddress);
-        // Local signer
+
+        // Local Signer for demo purposes
         let localWallet = new LocalWalletNode({
             chain,
         });
+
         await localWallet.loadOrCreate({
             strategy: "mnemonic",
             encryption: false,
         });
+
         const personalWalletAddress = await localWallet.getAddress();
-        console.log("Local signer addr:", personalWalletAddress);
+
+        console.log("Local Signer Address:", personalWalletAddress);
 
         // Create the AA provider
         const config: SmartWalletConfig = {
@@ -91,10 +125,10 @@ const main = async () => {
             gasless: true,
             factoryAddress,
             thirdwebApiKey,
-            paymasterAPI: new AllowlistPaymaster(allowList),
+            paymasterAPI: new AllowlistPaymaster(allowList), // The Custom Paymaster API
         };
 
-        // connect the smart wallet
+        // Connect the smart wallet
         const smartWallet = new SmartWallet(config);
         await smartWallet.connect({
             personalWallet: localWallet,
@@ -103,11 +137,11 @@ const main = async () => {
         const isWalletDeployed = await smartWallet.isDeployed();
         console.log(`Is smart wallet deployed?`, isWalletDeployed);
 
-        // now use the SDK normally
+        // Now use the SDK normally
         const sdk = await ThirdwebSDK.fromWallet(smartWallet, chain);
-        console.log("Smart Account addr:", await sdk.wallet.getAddress());
+        console.log("Smart Account Address:", await sdk.wallet.getAddress());
         console.log(
-            "native balance:",
+            "Native Token Balance:",
             (await sdk.wallet.balance()).displayValue
         );
 

GitHub
sha: 20429007faecd3a262053ebe87466d7178f2028b