Skip to content

Commit

Permalink
Updates Paymaster tasks.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesduncombe committed Mar 5, 2024
1 parent 1185c57 commit 45840ba
Showing 1 changed file with 164 additions and 79 deletions.
243 changes: 164 additions & 79 deletions tasks/paymaster.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
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, StakeManager } from "@opengsn/contracts";
import { Marketplace, Issuer, Paymaster } from "../typechain/hardhat-diamond-abi/HardhatDiamondABI.sol";
import { RelayHub, RelayHub__factory, StakeManager, StakeManager__factory } from "@opengsn/contracts";
import { BigNumber } from "ethers";
import { IERC20 } from "../typechain";

Expand Down Expand Up @@ -38,75 +38,7 @@ 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 stake manager address", undefined, types.string)
.addParam("relayManagerAddress", "The relay manager address", undefined, types.string)
.addParam("relayWorkerAddress", "The relay worker 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>("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<StakeManager>([
"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... 🙌");
});

// Specific tasks for the paymaster - funding etc.

interface PaymasterSetupParams {
readonly relayHubAddress: string;
Expand All @@ -117,7 +49,6 @@ 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);
Expand All @@ -129,16 +60,15 @@ task("paymaster-setup", "Sets up the Paymaster")
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.
// Why types.string for amount? 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.string)
.addParam("amount", "The amount of ETH to fund the Paymaster with (wei)", undefined, types.string)
.setAction(async (params: PaymasterFundParams, hre) => {
const { ethers, getNamedAccounts } = hre;
const { issuerMember } = await getNamedAccounts();
Expand All @@ -155,10 +85,11 @@ task("paymaster-fund", "Funds the Paymaster")
throw Error("Paymaster's RelayHub address has not been set!");
}

// We don't have access to a deployment artifact for the relay hub so manually adding the ABI here...
const relayHub = await ethers.getContractAt<RelayHub>([
"function balanceOf(address owner) public view returns (uint256)"
], relayHubAddress);
// Get a handle to the relay hub.
const relayHub = await ethers.getContractAt<RelayHub>(
abiFromFactory(RelayHub__factory),
relayHubAddress
);

console.log(`Funding RelayHub ${relayHubAddress} with ${params.amount} MATIC...`);

Expand All @@ -169,6 +100,154 @@ task("paymaster-fund", "Funds the Paymaster")
console.log(`Admin wallet balance: ${await issuerMemberSigner.getBalance()}`);
});

interface PaymasterStakeSetupParams {
readonly amount: BigNumber;
readonly stakeTokenAddress: string;
readonly relayHubAddress: string;
readonly relayManagerAddress: string;
}

// Why types.string for amount? Because otherwise this will hit the max safe int size in JS.
task("paymaster-stake-setup", "Stakes the Relay")
.addParam("stakeTokenAddress", "The token to stake with", undefined, types.string)
.addParam("relayManagerAddress", "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 (wei)", undefined, types.string)
.setAction(async (params: PaymasterStakeSetupParams, hre) => {
const { ethers, getNamedAccounts } = hre;

// Why user1?
// We're using user1 as it's the owner of the Relay Hub.
const { user1 } = await getNamedAccounts();
const ownerSigner = await ethers.getSigner(user1);

// Get a handle to the stake token.
const stakeToken = await ethers.getContractAt<IERC20>("IERC20", params.stakeTokenAddress);

// Get a handle to the relay hub.
const relayHub = await ethers.getContractAt<RelayHub>(
abiFromFactory(RelayHub__factory),
params.relayHubAddress
);
const relayHubAsOwner = relayHub.connect(ownerSigner);

console.log("Getting the stake manager address...");
const stakeManagerAddress = await relayHubAsOwner.getStakeManager();

console.log(`Approving the stake token using stake manager at: ${stakeManagerAddress}...`);
await (await stakeToken.connect(ownerSigner).approve(
stakeManagerAddress, params.amount
)).wait();

// Get the configuration and stake info.
const config = await relayHubAsOwner.getConfiguration();
const minimumUnstakeDelay = config.minimumUnstakeDelay;

// Get a handle to the stake manager.
const stakeManager = await ethers.getContractAt<StakeManager>(
abiFromFactory(StakeManager__factory),
stakeManagerAddress
);
const stakeManagerAsOwner = stakeManager.connect(ownerSigner);

// Using the minimum unstake delay as the unstake delay for now.
console.log(`Staking for relay manager at: ${params.relayManagerAddress} with ${params.amount}...`);
await (await stakeManagerAsOwner.stakeForRelayManager(
params.stakeTokenAddress,
params.relayManagerAddress,
minimumUnstakeDelay,
params.amount
)).wait();

// TODO: Check if the hub is already authorized

console.log(`Authorizing hub at: ${params.relayHubAddress}...`);
await (await stakeManagerAsOwner.authorizeHubByOwner(
params.relayManagerAddress,
params.relayHubAddress
)).wait();

console.log("Staking the Relay complete...");
});

/**
* This should only be called in development environments.
*/

interface DevPaymasterFundRelayParams {
readonly relayManagerAddress: string;
readonly relayWorkerAddress: string;
}

task("dev-fund-manager-and-worker", "Fund the manager and worker accounts")
.addParam("relayManagerAddress", "The relay manager address", undefined, types.string)
.addParam("relayWorkerAddress", "The relay worker address", undefined, types.string)
.setAction(async (params: DevPaymasterFundRelayParams, hre) => {
// Guard for non-dev environments.
const { name: netName } = hre.network;
if (netName !== "dev") {
throw new Error("This task should only be called in development environments.");
}

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);

console.log("Owner address: ", ownerSigner.address);

const seedAmountForRelayAccounts = ethers.utils.parseEther("0.2");

console.log("Depositing ETH/MATIC to relay manager and worker accounts...");
console.log(`Relay manager at: ${params.relayManagerAddress}...`);
await (await ownerSigner.sendTransaction({ to: params.relayManagerAddress, value: seedAmountForRelayAccounts })).wait();
console.log(`Relay worker at: ${params.relayWorkerAddress}...`);
await (await ownerSigner.sendTransaction({ to: params.relayWorkerAddress, value: seedAmountForRelayAccounts })).wait();
});

/**
* This should only be called in development environments.
*/

interface DevPaymasterAddMembersParams {
readonly trustedForwarderAddress: string;
readonly gaslessAccounts: string[];
}

task("dev-paymaster-add-members", "Adds members to the marketplace etc - for dev testing")
.addParam("trustedForwarderAddress", "The relay manager address", undefined, types.string)
.addParam("gaslessAccounts", "The relay manager address", undefined, types.string)
.setAction(async (params: DevPaymasterAddMembersParams, hre) => {
// Guard for non-dev environments.
const { name: netName } = hre.network;
if (netName !== "dev") {
throw new Error("This task should only be called in development environments.");
}

console.log("Adding members to the issuer and marketplace contracts...");

const { ethers, getNamedAccounts } = hre;
const { issuerMember } = await getNamedAccounts();
const issuerMemberSigner = await ethers.getSigner(issuerMember);

const issuer = await ethers.getContract<Issuer>("Issuer");
const issuerIssuer = issuer.connect(issuerMemberSigner);

const marketplace = await ethers.getContract<Marketplace>("Marketplace");
const issuerMarketplace = marketplace.connect(issuerMemberSigner);

await Promise.all(params.gaslessAccounts.map(async (gaslessAccount) => {
await (await issuerIssuer.addMember(gaslessAccount)).wait();
await (await issuerMarketplace.addMember(gaslessAccount)).wait();
}));

console.log("Adding the trusted forwarder...", params.trustedForwarderAddress);

await (await issuerMarketplace.setTrustedForwarder(params.trustedForwarderAddress)).wait();
});

// Reusable functions and constants.

const PAYMASTER_FACETS = [
Expand Down Expand Up @@ -212,4 +291,10 @@ const deployPaymaster = async (
return await ethers.getContract<Paymaster>("Paymaster");
};

// TODO: Tidy this up... any is too slack.
const abiFromFactory = (factory: any): [string] => {
return new ethers.utils.Interface(factory.abi)
.format(ethers.utils.FormatTypes.simple);
};

export { PAYMASTER_FACETS, deployPaymaster };

0 comments on commit 45840ba

Please sign in to comment.