From 7ad40266428166cedcecc4046b7562e67c9d6160 Mon Sep 17 00:00:00 2001 From: James Duncombe Date: Wed, 14 Feb 2024 11:35:49 +0000 Subject: [PATCH] Adds Paymaster hardhat tasks. --- tasks/paymaster.ts | 107 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/tasks/paymaster.ts b/tasks/paymaster.ts index bb3e8e0a..149c9bda 100644 --- a/tasks/paymaster.ts +++ b/tasks/paymaster.ts @@ -2,8 +2,9 @@ import { task, types } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { ZERO_ADDRESS, deploymentSalt } from "../src/utils"; import { Paymaster } from "../typechain/hardhat-diamond-abi/HardhatDiamondABI.sol"; -import { RelayHub } from "@opengsn/contracts"; +import { RelayHub, StakeManager } from "@opengsn/contracts"; import { BigNumber } from "ethers"; +import { IERC20 } from "../typechain"; // Tasks. @@ -37,13 +38,107 @@ task("paymaster-update-facets", "Updates facets of our Paymaster") }); }); +/** + * This should only be called in development environments. + * I've prefixed this task for now... + * TODO: Split this up... some is for the dev environment and some is for the mainnet environment. +*/ + +interface PaymasterStakeParams { + readonly amount: BigNumber; + readonly stakeTokenAddress: string; + readonly relayHubAddress: string; + readonly relayManagerAddress: string; + readonly relayWorkerAddress: string; + readonly stakeManagerAddress: string; +} + +task("dev-paymaster-relay-setup", "Setup task for the relay.") + .addParam("stakeTokenAddress", "The token to stake with", undefined, types.string) + .addParam("stakeManagerAddress", "The address of the stake manager", undefined, types.string) + .addParam("relayManagerAddress", "The relay manager address", undefined, types.string) + .addParam("relayWorkerAddress", "The relay manager address", undefined, types.string) + .addParam("relayHubAddress", "The RelayHub address", undefined, types.string) + .addParam("amount", "The amount of ETH to stake the RelayHub with", undefined, types.int) + .setAction(async (params: PaymasterStakeParams, hre) => { + const { ethers, getNamedAccounts } = hre; + + // Why user1? + // We're using user1 as it's the owner of the relay hub etc. + const { user1 } = await getNamedAccounts(); + const ownerSigner = await ethers.getSigner(user1); + + const seedAmountForRelayAccounts = ethers.utils.parseEther("0.5"); + + console.log("Depositing ETH/MATIC to relay manager and worker accounts..."); + await (await ownerSigner.sendTransaction({ to: params.relayManagerAddress, value: seedAmountForRelayAccounts })).wait(); + await (await ownerSigner.sendTransaction({ to: params.relayWorkerAddress, value: seedAmountForRelayAccounts })).wait(); + + // Get a handle to the stake token. + const stakeToken = await ethers.getContractAt("IERC20", params.stakeTokenAddress); + + console.log("Approving the stake token..."); + await (await stakeToken.connect(ownerSigner).approve( + params.stakeManagerAddress, params.amount + )).wait(); + + // We can't use the deployment artifact etc for the ABI so manually adding it here. + const stakeManager = await ethers.getContractAt([ + "function stakeForRelayManager(address, address, uint256, uint256) external", + "function authorizeHubByOwner(address relayManager, address relayHub) external" + ], params.stakeManagerAddress); + + const stakeManagerAsOwner = stakeManager.connect(ownerSigner); + + console.log("Authorizing hub..."); + await (await stakeManagerAsOwner.authorizeHubByOwner( + params.relayManagerAddress, + params.relayHubAddress + )).wait(); + + console.log("Staking for relay manager..."); + await (await stakeManagerAsOwner.stakeForRelayManager( + params.stakeTokenAddress, + params.relayManagerAddress, + /* unstakeDelay */ 7 * 24 * 3600, + params.amount + )).wait(); + + console.log("Setup for the relay complete... 🙌"); + }); + + +interface PaymasterSetupParams { + readonly relayHubAddress: string; + readonly trustedForwarderAddress: string; +} + +task("paymaster-setup", "Sets up the Paymaster") + .addParam("relayHubAddress", "The relay hub address", undefined, types.string) + .addParam("trustedForwarderAddress", "The trusted forwarder address", undefined, types.string) + .setAction(async (params: PaymasterSetupParams, hre) => { + + const { ethers, getNamedAccounts } = hre; + const { issuerMember } = await getNamedAccounts(); + const issuerMemberSigner = await ethers.getSigner(issuerMember); + + // Get a handle to the paymaster contract. + const paymaster = await ethers.getContract("Paymaster"); + const issuerPaymaster = paymaster.connect(issuerMemberSigner); + + console.log("Setting trusted forwarder and relay address..."); + await (await issuerPaymaster.setRelayHub(params.relayHubAddress)).wait(); + await (await issuerPaymaster.setTrustedForwarder(params.trustedForwarderAddress)).wait(); + console.log("... done"); + }); interface PaymasterFundParams { readonly amount: BigNumber; } +// Why types.string? Because otherwise this will hit the max safe int size in JS. task("paymaster-fund", "Funds the Paymaster") - .addParam("amount", "The amount of ETH to fund the Paymaster with", undefined, types.int) + .addParam("amount", "The amount of ETH to fund the Paymaster with", undefined, types.string) .setAction(async (params: PaymasterFundParams, hre) => { const { ethers, getNamedAccounts } = hre; const { issuerMember } = await getNamedAccounts(); @@ -60,13 +155,15 @@ task("paymaster-fund", "Funds the Paymaster") throw Error("Paymaster's RelayHub address has not been set!"); } - const relayHub = await ethers.getContractAt("RelayHub", relayHubAddress); + // We don't have access to a deployment artifact for the relay hub so manually adding the ABI here... + const relayHub = await ethers.getContractAt([ + "function balanceOf(address owner) public view returns (uint256)" + ], relayHubAddress); console.log(`Funding RelayHub ${relayHubAddress} with ${params.amount} MATIC...`); // Fund the paymaster. - const tx = await issuerPaymaster.deposit({ value: params.amount }); - await tx.wait(); + await (await issuerPaymaster.deposit({ value: params.amount })).wait(); console.log(`Paymaster balance with relay hub: ${await relayHub.balanceOf(paymaster.address)}`); console.log(`Admin wallet balance: ${await issuerMemberSigner.getBalance()}`);