Skip to content

Commit

Permalink
Added TokenVault
Browse files Browse the repository at this point in the history
  • Loading branch information
asselstine committed May 18, 2022
1 parent f1e2b71 commit b78d0cd
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 0 deletions.
60 changes: 60 additions & 0 deletions contracts/TokenVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.6;

import "@pooltogether/owner-manager-contracts/contracts/Manageable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
* @title PoolTogether Vault
* @author PoolTogether Inc Team
*/
contract Vault is Manageable {
using SafeERC20 for IERC20;

mapping(address => bool) public approved;

/**
* @notice Constructs Vault
* @param _owner Owner address
*/
constructor(address _owner) Ownable(_owner) {}

function setApproved(address _account, bool _approved) external onlyOwner {
approved[_account] = _approved;
}

/**
* @notice Decrease allowance of ERC20 tokens held by this contract.
* @dev Only callable by the owner or asset manager.
* @dev Current allowance should be computed off-chain to avoid any underflow.
* @param token Address of the ERC20 token to decrease allowance for
* @param spender Address of the spender of the tokens
* @param amount Amount of tokens to decrease allowance by
*/
function decreaseERC20Allowance(
IERC20 token,
address spender,
uint256 amount
) external onlyManagerOrOwner {
token.safeDecreaseAllowance(spender, amount);
}

/**
* @notice Increase allowance of ERC20 tokens held by this contract.
* @dev Only callable by the owner or asset manager.
* @dev Current allowance should be computed off-chain to avoid any overflow.
* @param token Address of the ERC20 token to increase allowance for
* @param spender Address of the spender of the tokens
* @param amount Amount of tokens to increase allowance by
*/
function increaseERC20Allowance(
IERC20 token,
address spender,
uint256 amount
) external onlyManagerOrOwner {
require(approved[spender], "Spender must be approved");
token.safeIncreaseAllowance(spender, amount);
}
}
76 changes: 76 additions & 0 deletions test/TokenVault.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import { expect } from 'chai';
import { deployMockContract } from 'ethereum-waffle';
import { Contract, Signer } from 'ethers';
import { ethers, artifacts } from 'hardhat';

const newDebug = require('debug');

const debug = newDebug('pt:Vault.test.ts');

const { getSigners } = ethers;

describe('Vault', () => {
let vault: Contract;
let token: Contract;

let wallet1: SignerWithAddress;
let wallet2: SignerWithAddress;
let wallet3: SignerWithAddress;
let wallet4: SignerWithAddress;

beforeEach(async () => {
[wallet1, wallet2, wallet3, wallet4] = await getSigners();

const IERC20Artifact = await artifacts.readArtifact('IERC20');
token = await deployMockContract(wallet1 as Signer, IERC20Artifact.abi);

const VaultFactory = await ethers.getContractFactory('Vault', wallet1);
vault = await VaultFactory.deploy(wallet1.address);
});

describe('constructor', () => {
it('should set the owner', async () => {
expect(await vault.owner()).to.equal(wallet1.address)
})
})

describe('setApproval()', () => {
it('should allow the owner to approve accounts', async () => {
await vault.setApproved(wallet2.address, true)
expect(await vault.approved(wallet2.address)).to.equal(true)
})
})

describe('increaseERC20Allowance()', () => {
it('should allow owners to increase approval amount', async () => {
await vault.setApproved(wallet2.address, true)
await token.mock.allowance.withArgs(vault.address, wallet2.address).returns('0')
await token.mock.approve.withArgs(wallet2.address, '1111').returns(true)
await vault.increaseERC20Allowance(token.address, wallet2.address, '1111')
})

it('should allow managers to increase approval amount', async () => {
await vault.setManager(wallet3.address)
await vault.setApproved(wallet2.address, true)
await token.mock.allowance.withArgs(vault.address, wallet2.address).returns('0')
await token.mock.approve.withArgs(wallet2.address, '1111').returns(true)
await vault.connect(wallet3).increaseERC20Allowance(token.address, wallet2.address, '1111')
})
})

describe('decreaseERC20Allowance()', () => {
it('should allow manager to decrease approval amount', async () => {
await token.mock.allowance.withArgs(vault.address, wallet2.address).returns('1111')
await token.mock.approve.withArgs(wallet2.address, '111').returns(true)
await vault.decreaseERC20Allowance(token.address, wallet2.address, '1000')
})

it('should allow manager to decrease approval amount', async () => {
await vault.setManager(wallet3.address)
await token.mock.allowance.withArgs(vault.address, wallet2.address).returns('1111')
await token.mock.approve.withArgs(wallet2.address, '0').returns(true)
await vault.connect(wallet3).decreaseERC20Allowance(token.address, wallet2.address, '1111')
})
})
});

0 comments on commit b78d0cd

Please sign in to comment.