Skip to content

Instantly share code, notes, and snippets.

@TABASCOatw
Created October 10, 2023 22:41
Show Gist options
  • Save TABASCOatw/3a658e39daf2df1ecded271cd5e32390 to your computer and use it in GitHub Desktop.
Save TABASCOatw/3a658e39daf2df1ecded271cd5e32390 to your computer and use it in GitHub Desktop.
Building a user operation with Particle (+ Biconomy for paymaster) and sending to Pimlico's bundler
import React, { useState, useEffect } from 'react';
import Web3 from 'web3';
import { ParticleNetwork } from '@particle-network/auth';
import { AvalancheTestnet } from "@particle-network/chains";
import { ParticleProvider } from "@particle-network/provider";
import { SmartAccount } from '@particle-network/aa';
import './App.css';
const config = {
projectId: process.env.REACT_APP_PROJECT_ID,
clientKey: process.env.REACT_APP_CLIENT_KEY,
appId: process.env.REACT_APP_APP_ID,
};
const pimlicoApiKey = process.env.REACT_APP_PIMLICO_KEY;
const pimlicoEndpoint = `https://api.pimlico.io/v1/avalanche-fuji/rpc?apikey=${pimlicoApiKey}`;
const entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
const App = () => {
const [userInfo, setUserInfo] = useState(null);
const [avaxBalance, setAvaxBalance] = useState(null);
const particle = new ParticleNetwork({
...config,
chainName: AvalancheTestnet.name,
chainId: AvalancheTestnet.id,
wallet: { displayWalletEntry: true, uiMode: 'dark' },
});
const smartAccount = new SmartAccount(new ParticleProvider(particle.auth), {
...config,
networkConfig: [
{ dappAPIKey: process.env.REACT_APP_BICONOMY_KEY, chainId: AvalancheTestnet.id }
],
});
particle.setERC4337(true);
window.web3 = new Web3(new ParticleProvider(particle.auth));
useEffect(() => {
if (userInfo) fetchAvaxBalance();
}, [userInfo]);
const fetchAvaxBalance = async () => {
const address = await smartAccount.getAddress();
const balance = await window.web3.eth.getBalance(address);
setAvaxBalance(window.web3.utils.fromWei(balance, 'ether'));
};
const handleLogin = async (authType) => setUserInfo(await particle.auth.login({ preferredAuthType: authType }));
const executeUserOp = async () => {
try {
const [signerAddress] = await window.web3.eth.getAccounts();
const tx = { to: '0x000000000000000000000000000000000000dEaD', value: window.web3.utils.toWei('0.0001', 'ether'), from: signerAddress };
const userOpBundle = await smartAccount.buildUserOperation({ tx });
userOpBundle.userOp.signature = await window.web3.eth.personal.sign(userOpBundle.userOpHash, signerAddress, '');
console.log("User operation sent with hash:", await sendUserOpThroughPimlico(userOpBundle.userOp));
} catch (error) {
console.error('Error:', error);
}
};
const sendUserOpThroughPimlico = userOp => new Promise((resolve, reject) => {
new Web3(new Web3.providers.HttpProvider(pimlicoEndpoint)).currentProvider.send(
{ jsonrpc: "2.0", id: 1, method: "eth_sendUserOperation", params: [userOp, entryPoint] },
(err, result) => err ? reject(err) : resolve(result.result)
);
});
return (
<div className="App">
{!userInfo ? (
<>
<button onClick={() => handleLogin('google')}>Sign in with Google</button>
<button onClick={() => handleLogin('twitter')}>Sign in with Twitter</button>
</>
) : (
<div>
<h2>{userInfo.name}</h2>
<small>{avaxBalance} ETH</small>
<button onClick={executeUserOp}>Execute User Operation</button>
</div>
)}
</div>
);
};
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment