-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
upgrade script and transaction on V2
- Loading branch information
1 parent
16c0f73
commit d4c395e
Showing
3 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters