Preview for AA

We're also capable of providing a fully-enriched preview of a 4337 userOp, allowing you to provide the same level of pre-sign experience if you're running an AA wallet.

Let's see how to do that.

const axios = require('axios');

const API_BASE_URL = 'https://foresight.noves.fi';

// Set your API Key as an env var or directly as a string
const NOVES_API_KEY = process.env.NOVES_API_KEY;

async function previewUserOp(chain, userOp, blockNumber) {
    try {
        const url = blockNumber
            ? `${API_BASE_URL}/evm/${chain}/preview4337?blockNumber=${blockNumber}`
            : `${API_BASE_URL}/evm/${chain}/preview4337`;

        const response = await axios.post(
            url,
            { userOp: userOp },
            {
                headers: {
                    apiKey: NOVES_API_KEY,
                },
            }
        );
        return response.data;
    } catch (error) {
        console.error('Error previewing user operation:', error);
        return null;
    }
}

const chain = 'optimism';
const blockNumber = 108675291; // Just for demonstration purposes. In most cases you won't be passing a blockNumber as it will be real-time.

// Sample userOp object
const userOp = {
    sender: '0x24747e7f4766e63c33f1B8215BabF93D4A560Ed7',
    nonce: 1,
    initCode: '0x',
    callData:
        '0x51945447000000000000000000000000b2bbfc07948fedeb5935316203c33ce70bef57d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e42e7ba6ef000000000000000000000000000000000000000000000000000000000000547100000000000000000000000024747e7f4766e63c33f1b8215babf93d4a560ed70000000000000000000000000000000000000000000000004563918244f40000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000126b11a39f27b3fb4c7bf7c2ca7d13dc1b24357a217164dcbeb088781726ff82803e35d7eabd4e837dea77232e3eaa7d590558e0f006b8c1d71d194a688e3535fbf02b7791991299ae3b195807e99403640b1850448f21543486dee8dc961b29345d5d2b9a5a548e9f54665a5eb53f868168efc2fdbe205e96c5eab2e1dda32ae6794c8b941eb86fc7ba914ee886cb3e957fb8253cbc99cd2b17bb453fb92b0d0f677821522c14690c55a1d86d2ac5482e6ebe1efe5e6d4aabd3374d1c9cef43891b4eb88e28314768631895e164161e152a18e364c9931c04d6c1f0f9a202f387c2ab78c35b2f2bb5cbe54a437fe40db0b21dc2d4e2a1dd62059e9ff6d55cb03e71c17ee4c3412e82194344fc6f3f9466b57d94704ab8abec1afd946d124d3d04923bd7c9ea8eb22f3d0d00976ea62c9bf3d0de24a8123a9bcc838da6708ca597318e09f512dbad34ef034bc4a0e6606ed4114371e7c3df697d46e9cfe052e4206ea45d9056cc6e86f01536c1dff45c0b9e59bdaec8c1ec2b48aef05940df74d07cb0d0cebed54886ebc4d183c5bd7036bfe0e264c6668911dc284dc42ee4c6fbd157981d3c42915785cdd4ffc0d5524375046de5dffcdce9e6b9b29036be1cda00a766b592903554e74bcde94404fe38578677816eb963ea258617a24578f19a8f07c51549090ca864ded6b67372254cd43f80a036b3e3b022545bc8961d17448b0237ff2825d1d04e73210d4cc2642178608d55c3cfe2d91856802fc02b5c5ead40442895c5a32c9db0132aa89ad587873d578b7e36724608f602ab0db4164900000000000000000000000000000000000000000000000000000000',
    callGasLimit: 278449,
    verificationGasLimit: 109585,
    preVerificationGas: 24438325,
    maxFeePerGas: 9200011,
    maxPriorityFeePerGas: 9200011,
    signature:
        '0x00000000b82f846b0ffbae6c3422f6a0873e7e89cec92c69087ebac4f8999425c2b7d57659b7add34d47483519ae65e776e57e2e13c7108426e4fa9e7c0474c0fd43ba6f1c',
    paymasterAndData:
        '0x4df91e173a6cdc74efef6fc72bb5df1e8a8d75820000000000000000000000000000000000000000000000000000000064e85da500000000000000000000000000000000000000000000000000000000000000005975b9956a9ce934154d7bb50aae8b81f75b31c22edf448f63b8e276f54ecc654014724d56e869bcbd0f6a2aae04cda9428c6e8ca44d7c1a6f00014a92bcbac01c',
};

console.log(JSON.stringify(userOp));

previewUserOp(chain, userOp, blockNumber).then((data) => {
    console.log(JSON.stringify(data, null, 2));
});

See how we're passing a blockNumber to preview the transaction as of a certain block. This is done only for the sake of demonstration (to guarantee that you'll always get the same result, as the state of the blockchain will be fixed at that block).

In real-world scenarios, you'd be passing the userOp from your user and previewing that with the current state of the blockchain. To preview using current state, simply don't pass any blockNumber ;)

The output of this particular preview will be:

{
    "txTypeVersion": 2,
    "chain": "optimism",
    "accountAddress": "0x24747e7f4766e63c33f1B8215BabF93D4A560Ed7",
    "classificationData": {
        "type": "claimRewards",
        "source": {
            "type": "human"
        },
        "description": "Will claim 5 CYBER in rewards.",
        "sent": [],
        "received": [
            {
                "action": "rewardsReceived",
                "from": {
                    "name": null,
                    "address": "0xB2BbFC07948fedeB5935316203C33ce70beF57d0"
                },
                "to": {
                    "name": "This wallet",
                    "address": "0x24747e7f4766e63c33f1B8215BabF93D4A560Ed7"
                },
                "amount": "5",
                "token": {
                    "symbol": "CYBER",
                    "name": "CyberConnect",
                    "decimals": 18,
                    "address": "0x14778860e937f509e651192a90589de711fb88a9"
                }
            }
        ]
    }
}

Now you can get a fully-enriched pre-sign experience for your AA wallet!