Skip to content

Commit

Permalink
upgrade script and transaction on V2
Browse files Browse the repository at this point in the history
  • Loading branch information
livingrockrises committed Sep 29, 2023
1 parent 16c0f73 commit d4c395e
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 0 deletions.
2 changes: 2 additions & 0 deletions backend-node/scripts/gasless/mintNFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
import config from "../../config.json";
import { ECDSAOwnershipValidationModule, MultiChainValidationModule, DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_MULTICHAIN_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE } from "@biconomy/modules";

// V1 script link : https://github.com/bcnmy/sdk-examples/blob/1ccc595710cfb60a98df18f86dcfeb9a671dbb2f/backend-node/scripts/gasless/mintNFT.ts

export const mintNft = async () => {

// ------------------------STEP 1: Initialise Biconomy Smart Account SDK--------------------------------//
Expand Down
235 changes: 235 additions & 0 deletions backend-node/scripts/gasless/upgradeV1toV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
import { ethers } from "ethers";
import chalk from "chalk";
import {
BiconomySmartAccount,
BiconomySmartAccountV2,
DEFAULT_ENTRYPOINT_ADDRESS,
} from "@biconomy/account";
import { Bundler } from "@biconomy/bundler";
import { BiconomyPaymaster } from "@biconomy/paymaster";
import {
IHybridPaymaster,
PaymasterMode,
SponsorUserOperationDto,
} from "@biconomy/paymaster";
import { ECDSAOwnershipValidationModule, MultiChainValidationModule, DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_MULTICHAIN_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE } from "@biconomy/modules";
import config from "../../config.json";

export const upgradeAndMintNft = async () => {

// ------------------------STEP 1: Initialise Biconomy Smart Account SDK--------------------------------//

// get EOA address from wallet provider
let provider = new ethers.providers.JsonRpcProvider(config.rpcUrl);
let signer = new ethers.Wallet(config.privateKey, provider);
const eoa = await signer.getAddress();
console.log(chalk.blue(`EOA address: ${eoa}`));

// create bundler and paymaster instances
const bundler = new Bundler({
bundlerUrl: config.bundlerUrl,
chainId: config.chainId,
entryPointAddress: DEFAULT_ENTRYPOINT_ADDRESS,
});

const paymaster = new BiconomyPaymaster({
paymasterUrl: config.biconomyPaymasterUrl
});

// Biconomy smart account config
// Note that paymaster and bundler are optional. You can choose to create new instances of this later and make account API use
const biconomySmartAccountConfig = {
signer: signer,
chainId: config.chainId,
rpcUrl: config.rpcUrl,
paymaster: paymaster,
bundler: bundler,
};

// create biconomy smart account instance
const biconomyAccount = new BiconomySmartAccount(biconomySmartAccountConfig);

// passing accountIndex is optional, by default it will be 0. You may use different indexes for generating multiple counterfactual smart accounts for the same user
const biconomySmartAccount = await biconomyAccount.init( {accountIndex: config.accountIndex} );


// ------------------------STEP 2: Build Partial User op from your user Transaction/s Request --------------------------------//


// mint NFT
// Please note that for sponsorship, policies have to be added on the Biconomy dashboard https://dashboard.biconomy.io/
// in this case it will be whitelisting NFT contract and method safeMint()

// 1. for native token transfer no policy is required. you may add a webhook to have custom control over this
// 2. If no policies are added every transaction will be sponsored by your paymaster
// 3. If you add policies, then only transactions that match the policy will be sponsored by your paymaster

// generate mintNft data
const nftInterface = new ethers.utils.Interface([
"function safeMint(address _to)",
]);

// passing accountIndex is optional, by default it will be 0
// it should match with the index used to initialise the SDK Biconomy Smart Account instance
const scwAddress = await biconomySmartAccount.getSmartAccountAddress(config.accountIndex);
console.log('scwAddress', scwAddress)

// Here we are minting NFT to smart account address itself
const data = nftInterface.encodeFunctionData("safeMint", [scwAddress]);

const nftAddress = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e"; // Todo // use from config
const transaction = {
to: nftAddress,
data: data,
};


const tx = await biconomySmartAccount.getUpdateImplementationData()
console.log('update tx', tx)


const moduleSetupData = await biconomySmartAccount.getModuleSetupData()
console.log('moduleSetupData', moduleSetupData)


const partialUserOp = await biconomySmartAccount.updateImplementationUserOp()
console.log('requiredUserOp', partialUserOp)



// build partial userOp
// let partialUserOp = await biconomySmartAccount.buildUserOp([transaction]);


// ------------------------STEP 3: Get Paymaster and Data from Biconomy Paymaster --------------------------------//


const biconomyPaymaster =
biconomySmartAccount.paymaster as IHybridPaymaster<SponsorUserOperationDto>;

// Here it is meant to act as Sponsorship/Verifying paymaster hence we send mode: PaymasterMode.SPONSORED which is must
let paymasterServiceData: SponsorUserOperationDto = {
mode: PaymasterMode.SPONSORED,
// optional params...
};

try {
const paymasterAndDataResponse =
await biconomyPaymaster.getPaymasterAndData(
partialUserOp,
paymasterServiceData
);
partialUserOp.paymasterAndData = paymasterAndDataResponse.paymasterAndData;
} catch (e) {
console.log("error received ", e);
}


// ------------------------STEP 4: Sign the UserOp and send to the Bundler--------------------------------//

console.log(chalk.blue(`userOp: ${JSON.stringify(partialUserOp, null, "\t")}`));

// Below function gets the signature from the user (signer provided in Biconomy Smart Account)
// and also send the full op to attached bundler instance

try {
const userOpResponse = await biconomySmartAccount.sendUserOp(partialUserOp);
console.log(chalk.green(`userOp Hash: ${userOpResponse.userOpHash}`));
const transactionDetails = await userOpResponse.wait();
console.log(
chalk.blue(
`transactionDetails: ${JSON.stringify(transactionDetails, null, "\t")}`
)
);
} catch (e) {
console.log("error received ", e);
}

const ecdsaModule = await ECDSAOwnershipValidationModule.create({
signer: signer,
moduleAddress: DEFAULT_ECDSA_OWNERSHIP_MODULE
})

// Biconomy smart account config
// Note that paymaster and bundler are optional. You can choose to create new instances of this later and make account API use
const biconomySmartAccountConfigV2 = {
chainId: config.chainId,
rpcUrl: config.rpcUrl,
paymaster: paymaster,
bundler: bundler,
entryPointAddress: DEFAULT_ENTRYPOINT_ADDRESS,
defaultValidationModule: ecdsaModule,
activeValidationModule: ecdsaModule,
senderAddress: await biconomySmartAccount.getSmartAccountAddress(config.accountIndex)
};

// create biconomy smart account instance
const biconomySmartAccountV2 = await BiconomySmartAccountV2.create(biconomySmartAccountConfigV2);

// build partial userOp
let partialUserOp2 = await biconomySmartAccountV2.buildUserOp([transaction]);

const biconomyPaymaster2 =
biconomySmartAccountV2.paymaster as IHybridPaymaster<SponsorUserOperationDto>;

// Here it is meant to act as Sponsorship/Verifying paymaster hence we send mode: PaymasterMode.SPONSORED which is must
let paymasterServiceData2: SponsorUserOperationDto = {
mode: PaymasterMode.SPONSORED,
smartAccountInfo: {
name: 'BICONOMY',
version: '2.0.0'
},
// optional params...
calculateGasLimits: true
};

try {
const paymasterAndDataResponse =
await biconomyPaymaster2.getPaymasterAndData(
partialUserOp2,
paymasterServiceData
);
partialUserOp2.paymasterAndData = paymasterAndDataResponse.paymasterAndData;

if (
paymasterAndDataResponse.callGasLimit &&
paymasterAndDataResponse.verificationGasLimit &&
paymasterAndDataResponse.preVerificationGas
) {

// Returned gas limits must be replaced in your op as you update paymasterAndData.
// Because these are the limits paymaster service signed on to generate paymasterAndData
// If you receive AA34 error check here..

partialUserOp2.callGasLimit = paymasterAndDataResponse.callGasLimit;
partialUserOp2.verificationGasLimit =
paymasterAndDataResponse.verificationGasLimit;
partialUserOp2.preVerificationGas =
paymasterAndDataResponse.preVerificationGas;
}
} catch (e) {
console.log("error received ", e);
}


// ------------------------STEP 4: Sign the UserOp and send to the Bundler--------------------------------//

console.log(chalk.blue(`userOp: ${JSON.stringify(partialUserOp, null, "\t")}`));

// Below function gets the signature from the user (signer provided in Biconomy Smart Account)
// and also send the full op to attached bundler instance

try {
const userOpResponse = await biconomySmartAccountV2.sendUserOp(partialUserOp2);
console.log(chalk.green(`userOp Hash: ${userOpResponse.userOpHash}`));
const transactionDetails = await userOpResponse.wait();
console.log(
chalk.blue(
`transactionDetails: ${JSON.stringify(transactionDetails, null, "\t")}`
)
);
} catch (e) {
console.log("error received ", e);
}

};
17 changes: 17 additions & 0 deletions backend-node/scripts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { batchMintNftPayERC20 } from "./erc20/batchMintNFT";
import { batchMintNftTrySponsorshipOtherwisePayERC20 } from "./hybrid-fallback/batchMintNFT";
import { mintNftTrySponsorshipOtherwisePayERC20 } from "./hybrid-fallback/mintNFT";
import { multiChainMint } from "./gasless/multiChainSend.ts";
import { upgradeAndMintNft } from "./gasless/upgradeV1toV2.ts";

yargs
.scriptName(chalk.green("smartAccount"))
Expand Down Expand Up @@ -159,6 +160,22 @@ yargs
}
}
)
.command(
"upgradeScript",
chalk.blue("Upgrade V1 to V2"),
{
mode: {
describe: chalk.cyan("Paymaster mode"),
demandOption: false,
type: "string",
},
},
(argv) => {
console.log(chalk.magenta("Minting an NFT token to the SmartAccountV2 after upgrade..."));
upgradeAndMintNft();

}
)
.command(
"multiChainMint",
chalk.blue("Mint nft token"),
Expand Down

0 comments on commit d4c395e

Please sign in to comment.