A proof of concept for sending gasless transactions on the Polygon Mumbai testnet using the ERC-4337 implementation provided by StackUp. Transactions sent by the integration test in this repo will send 0.001 MATIC back to itself and the account balance will remain unchanged -> no gas fees will be charged.
The data
value of the transactions are currently hardcoded to 0x
, but you may perform any transaction an externally owned account is permitted to perform including launching and interacting with smart contracts.
The userop
library will create a smart contract on the first transaction. This contract is used to verify the offchain data signed by the signingkey and execute the transactions. Effectively, it is a proxy for the external account that takes actions on behalf of the user, and its transaction gas is paid by the paymaster
controlled by StackUp.
- This code requires a developer API key from Stackup. A free account will not have access to the paymaster API and transactions will fail. The paymaster API allows for gasless transactions. A gasless transaction allows for the end user to hold no ETH/MATIC in their wallet and still transact on the EVM compatible network.
See .env-template
- The Signing Key used by this must have a balance. Visit the Polygon Faucet and fund your signing key's address. Transactions sent from this address will appear under the "Internal Txns" tab.
You can generate a signing key using the ethers
library:
const wallet = new ethers.Wallet(ethers.utils.randomBytes(32));
console.log(wallet.address); // fund this
console.log(wallet.privateKey); // this is STACKUP_SIGNING_KEY in .env
Use the package manager yarn to install the required dependencies for this project. For now, the userops
package requires yarn for typescript-y things.
yarn install
- Make a copy of the .env.example file and name it .env:
cp .env.example .env
-
Update the .env file with the required API keys and other configuration options.
-
Import the Server class and use it as needed:
const server = new Server();
(async () => {
const address = await server.getAddress();
console.log(`Address: ${address}`);
const amount = "0.001";
const transactionHash = await server.sendTransaction(address, amount);
console.log(`Transaction hash: ${transactionHash}`);
})();
To run the unit and integration tests, execute the following command:
npm test