-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Igor Stadnyk
committed
Jul 14, 2024
1 parent
d82bf9a
commit dd81893
Showing
8 changed files
with
1,613 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
ACCOUNT_PK= | ||
ENDPOINT_URL=https://api.pimlico.io/v2/sepolia/rpc?apikey=<API_KEY> | ||
RPC_URL=https://rpc.ankr.com/eth_sepolia | ||
SIMPLE_ACCOUNT_FACTORY_ADDRESS= | ||
MODULE_ADDRESS= | ||
SIGNATURE= |
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,14 @@ | ||
# Hardhat files | ||
cache | ||
artifacts | ||
|
||
|
||
dist | ||
.env | ||
coverage | ||
coverage.json | ||
typechain | ||
typechain-types | ||
*.d.ts | ||
.npmrc | ||
.DS_Store |
Large diffs are not rendered by default.
Oops, something went wrong.
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,31 @@ | ||
import { createClient, createPublicClient, createWalletClient, http } from "viem"; | ||
import { sepolia } from "viem/chains"; | ||
import { bundlerActions, ENTRYPOINT_ADDRESS_V07 } from "permissionless"; | ||
import { pimlicoBundlerActions, pimlicoPaymasterActions } from "permissionless/actions/pimlico.js"; | ||
import { privateKeyToAccount } from "viem/accounts"; | ||
|
||
const account = privateKeyToAccount(process.env.ACCOUNT_PK) | ||
|
||
const walletClient = createWalletClient({ | ||
account, | ||
chain: sepolia, | ||
transport: http(process.env.RPC_UR), | ||
}) | ||
|
||
const publicClient = createPublicClient({ | ||
chain: sepolia, | ||
transport: http(process.env.RPC_UR), | ||
}) | ||
|
||
const bundlerClient = createClient({ | ||
transport: http(process.env.ENDPOINT_URL), | ||
chain: sepolia, | ||
}) | ||
.extend(bundlerActions(ENTRYPOINT_ADDRESS_V07)) | ||
.extend(pimlicoBundlerActions(ENTRYPOINT_ADDRESS_V07)) | ||
|
||
|
||
const paymasterClient = createClient({ | ||
transport: http(process.env.ENDPOINT_UR), | ||
chain: sepolia, | ||
}).extend(pimlicoPaymasterActions(ENTRYPOINT_ADDRESS_V07)) |
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,99 @@ | ||
import { encodeFunctionData } from "viem"; | ||
import { ENTRYPOINT_ADDRESS_V07, getSenderAddress, signUserOperationHashWithECDSA } from "permissionless"; | ||
import { sepolia } from "viem/chains"; | ||
import { bundlerClient, paymasterClient, walletClient } from "./clients.js" | ||
|
||
export async function execBackup({ owner, name}) { | ||
const factory = process.env.SIMPLE_ACCOUNT_FACTORY_ADDRESSS | ||
const factoryData = encodeFunctionData({ | ||
abi: [ | ||
{ | ||
inputs: [ | ||
{ name: "owner", type: "address" }, | ||
{ name: "salt", type: "uint256" }, | ||
], | ||
name: "createAccount", | ||
outputs: [{ name: "ret", type: "address" }], | ||
stateMutability: "nonpayable", | ||
type: "function", | ||
}, | ||
], | ||
args: [walletClient.account.address, 0n], | ||
}) | ||
|
||
const senderAddress = await getSenderAddress(publicClient, { | ||
factory, | ||
factoryData, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
}) | ||
|
||
const execBackupCallData = encodeFunctionData({ | ||
address: process.env.MOUDLE_ADDRESS, | ||
abi, | ||
functionName: "executeBackup", | ||
args: [owner, name] | ||
}); | ||
|
||
const callData = encodeFunctionData({ | ||
abi: [{ | ||
inputs: [ | ||
{ name: "dest", type: "address" }, | ||
{ name: "value", type: "uint256" }, | ||
{ name: "func", type: "bytes" }, | ||
], | ||
name: "execute", | ||
outputs: [], | ||
stateMutability: "nonpayable", | ||
type: "function", | ||
}, | ||
], | ||
args: [process.env.MOUDLE_ADDRESS, 0, execBackupCallData], | ||
}) | ||
|
||
|
||
const gasPrice = await bundlerClient.getUserOperationGasPrice() | ||
|
||
const userOperation = { | ||
sender: senderAddress, | ||
nonce: 0n, | ||
factory: factory, | ||
factoryData, | ||
callData, | ||
maxFeePerGas: gasPrice.fast.maxFeePerGas, | ||
maxPriorityFeePerGas: gasPrice.fast.maxPriorityFeePerGas, | ||
// dummy signature, needs to be there so the SimpleAccount doesn't immediately revert because of invalid signature length | ||
signature: process.env.signature, | ||
} | ||
|
||
const sponsorUserOperationResult = await paymasterClient.sponsorUserOperation({ | ||
userOperation, | ||
}) | ||
|
||
const sponsoredUserOperation = { | ||
...userOperation, | ||
...sponsorUserOperationResult, | ||
} | ||
|
||
|
||
const signature = await signUserOperationHashWithECDSA({ | ||
account: walletClient.account, | ||
userOperation: sponsoredUserOperation, | ||
chainId: sepolia.id, | ||
entryPoint: ENTRYPOINT_ADDRESS_V07, | ||
}) | ||
sponsoredUserOperation.signature = signature | ||
|
||
|
||
const userOperationHash = await bundlerClient.sendUserOperation({ | ||
userOperation: sponsoredUserOperation, | ||
}) | ||
|
||
try { | ||
const receipt = await bundlerClient.waitForUserOperationReceipt({ | ||
hash: userOperationHash, | ||
}) | ||
const txHash = receipt.receipt.transactionHash | ||
} catch (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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import fs from 'fs'; | ||
import { publicClient } from './clients.js'; | ||
import { execBackup } from './executor.js'; | ||
import { CronJob } from 'cron'; | ||
import dotenv from 'dotenv'; | ||
|
||
// Load environment variables | ||
dotenv.config(); | ||
|
||
export const abi = JSON.parse(fs.readFileSync('./abi.json', 'utf8')).abi; | ||
|
||
async function getAllUsers() { | ||
let users = []; | ||
let index = 0; | ||
|
||
while (true) { | ||
try { | ||
const user = await publicClient.readContract({ | ||
address: process.env.MODULE_ADDRESS, | ||
abi, | ||
functionName: 'users', | ||
args: [index], | ||
}); | ||
|
||
console.log('USER', user); | ||
users.push(user); | ||
index++; | ||
} catch (e) { | ||
console.log('No more users found, stopping search.'); | ||
break; | ||
} | ||
} | ||
|
||
return users; | ||
} | ||
|
||
async function execBackups() { | ||
try { | ||
const users = await getAllUsers(); | ||
console.log('Users:', users); | ||
|
||
for (const user of users) { | ||
try { | ||
const userBackupsNames = await publicClient.readContract({ | ||
address: process.env.MODULE_ADDRESS, | ||
abi, | ||
functionName: 'getBackups', | ||
args: [user], | ||
}); | ||
|
||
for (const backupName of userBackupsNames) { | ||
try { | ||
const fullBackup = await publicClient.readContract({ | ||
address: process.env.MODULE_ADDRESS, | ||
abi, | ||
functionName: 'getBackup', | ||
args: [user, backupName], | ||
}); | ||
|
||
if (fullBackup.unlockAt <= Math.floor(Date.now() / 1000)) { | ||
console.log(`Executing backup for user ${user} with name ${backupName}`); | ||
await execBackup({ owner: user, name: backupName }); | ||
} | ||
} catch (e) { | ||
console.error(`Error fetching or executing backup for user ${user} and backup ${backupName}:`, e); | ||
if (e.name !== 'WaitForUserOperationReceiptTimeoutError') { | ||
throw e; | ||
} | ||
} | ||
} | ||
} catch (e) { | ||
console.error(`Error fetching backups for user ${user}:`, e); | ||
} | ||
} | ||
} catch (e) { | ||
console.error('Error during execBackups:', e); | ||
process.exit(1); // Terminate process with error code | ||
} | ||
} | ||
|
||
new CronJob('*/30 * * * *', execBackups).start(); | ||
|
||
execBackups() | ||
.then((res) => console.log('Initial execution complete:', res)) | ||
.catch((err) => console.error('Error during initial execution:', err)); |
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,19 @@ | ||
{ | ||
"name": "test-app", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "smart-account.ts", | ||
"type": "module", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "bun run index.js" | ||
}, | ||
"author": "", | ||
"license": "ISC", | ||
"dependencies": { | ||
"@rhinestone/module-sdk": "^0.1.2", | ||
"cron": "^3.1.7", | ||
"permissionless": "^0.1.39", | ||
"viem": "^2.17.3" | ||
} | ||
} |
Oops, something went wrong.