Add InterchainGasPaymaster (#285)

* Add InterchainGasPaymaster

* Underscore leaf index parameter

* Add event section comment
pull/292/head
Trevor Porter 3 years ago committed by GitHub
parent a9b509e973
commit fad3739409
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      solidity/core/contracts/InterchainGasPaymaster.sol
  2. 1
      solidity/core/hardhat.config.ts
  3. 76
      solidity/core/test/interchainGasPaymaster.test.ts

@ -0,0 +1,49 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;
// ============ External Imports ============
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title InterchainGasPaymaster
* @notice Manages payments on a source chain to cover gas costs of proving
* & processing messages on destination chains.
* @dev This contract is only intended for paying for messages sent via a specific
* Outbox contract on the same source chain.
*/
contract InterchainGasPaymaster is Ownable {
// ============ Events ============
/**
* @notice Emitted when a payment is made for a message's gas costs.
* @param leafIndex The index of the message in the Outbox merkle tree.
* @param amount The amount of native tokens paid.
*/
event GasPayment(uint256 indexed leafIndex, uint256 amount);
// ============ Constructor ============
// solhint-disable-next-line no-empty-blocks
constructor() Ownable() {}
// ============ External Functions ============
/**
* @notice Deposits the msg.value as a payment for the proving & processing
* of a message on its destination chain.
* @param _leafIndex The index of the message in the Outbox merkle tree.
*/
function payGasFor(uint256 _leafIndex) external payable {
emit GasPayment(_leafIndex, msg.value);
}
/**
* @notice Transfers the entire native token balance to the owner of the contract.
* @dev The owner must be able to receive native tokens.
*/
function claim() external {
// Transfer the entire balance to owner.
(bool success, ) = owner().call{value: address(this).balance}("");
require(success, "!transfer");
}
}

@ -1,5 +1,6 @@
import "solidity-coverage";
import "@typechain/hardhat";
import "@nomiclabs/hardhat-ethers";
import "@nomiclabs/hardhat-waffle";
import "hardhat-gas-reporter";

@ -0,0 +1,76 @@
import { ethers } from 'hardhat';
import { expect } from 'chai';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import {
InterchainGasPaymaster,
InterchainGasPaymaster__factory,
} from '../types';
const LEAF_INDEX = 4321;
const PAYMENT_AMOUNT = 123456789;
const OWNER = '0xdeadbeef00000000000000000000000000000000';
describe('InterchainGasPaymaster', async () => {
let paymaster: InterchainGasPaymaster, signer: SignerWithAddress;
before(async () => {
[signer] = await ethers.getSigners();
});
beforeEach(async () => {
const paymasterFactory = new InterchainGasPaymaster__factory(signer);
paymaster = await paymasterFactory.deploy();
});
describe('#payGasFor', async () => {
it('deposits the value into the contract', async () => {
const paymasterBalanceBefore = await signer.provider!.getBalance(
paymaster.address,
);
await paymaster.payGasFor(LEAF_INDEX, { value: PAYMENT_AMOUNT });
const paymasterBalanceAfter = await signer.provider!.getBalance(
paymaster.address,
);
expect(paymasterBalanceAfter.sub(paymasterBalanceBefore)).equals(
PAYMENT_AMOUNT,
);
});
it('emits the GasPayment event', async () => {
await expect(paymaster.payGasFor(LEAF_INDEX, { value: PAYMENT_AMOUNT }))
.to.emit(paymaster, 'GasPayment')
.withArgs(LEAF_INDEX, PAYMENT_AMOUNT);
});
});
describe('#claim', async () => {
it('sends the entire balance of the contract to the owner', async () => {
// First pay some ether into the contract
await paymaster.payGasFor(LEAF_INDEX, { value: PAYMENT_AMOUNT });
// Set the owner to a different address so we aren't paying gas with the same
// address we want to observe the balance of
await paymaster.transferOwnership(OWNER);
const ownerBalanceBefore = await signer.provider!.getBalance(OWNER);
expect(ownerBalanceBefore).equals(0);
const paymasterBalanceBefore = await signer.provider!.getBalance(
paymaster.address,
);
expect(paymasterBalanceBefore).equals(PAYMENT_AMOUNT);
await paymaster.claim();
const ownerBalanceAfter = await signer.provider!.getBalance(OWNER);
expect(ownerBalanceAfter).equals(PAYMENT_AMOUNT);
const paymasterBalanceAfter = await signer.provider!.getBalance(
paymaster.address,
);
expect(paymasterBalanceAfter).equals(0);
});
});
});
Loading…
Cancel
Save