Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions contracts/tests/SampleVRC25Upgradable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;

import "../VRC25Upgradable.sol";

contract SampleVRC25Upgradable is VRC25Upgradable {
using Address for address;
event Hello(address sender);

constructor() public {
__VRC25_init("Example Fungible Token", "EFT", 0);
}

function init() public {

}

/**
* @notice Calculate fee required for action related to this token
* @param value Amount of fee
*/
function _estimateFee(uint256 value) internal view override returns (uint256) {
return value + minFee();
}

function sayHello() public {
_chargeFeeFrom(msg.sender, address(0), estimateFee(0));

emit Hello(msg.sender);
}

function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
return interfaceId == type(IVRC25).interfaceId || super.supportsInterface(interfaceId);
}

/**
* @notice Issues `amount` tokens to the designated `address`.
*
* Can only be called by the current owner.
*/
function mint(address recipient, uint256 amount) external onlyOwner returns (bool) {
_mint(recipient, amount);
return true;
}
}
2 changes: 1 addition & 1 deletion tests/SampleVRC25.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ async function createPermit(token: SampleVRC25, owner: Signer, spenderAddress: s
const chainId = await hhe.ethers.provider.send('eth_chainId', []);

const domain: EIP712Domain = {
name: "VRC25Permit",
name: "VRC25",
version: "1",
chainId: chainId,
verifyingContract: token.address,
Expand Down
149 changes: 149 additions & 0 deletions tests/SampleVRC25Upgradable.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Import the necessary dependencies
import hhe from 'hardhat';
import { Signer, BigNumber } from 'ethers';
import { expect } from 'chai';
import { SampleVRC25Upgradable } from '../typechain-types';
import { ECDSASignature, EIP712Domain, EIP712TypeDefinition } from './EIP712';
import { time } from '@nomicfoundation/hardhat-network-helpers';

const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';

describe('SampleVRC25 token', async function() {
let owner: Signer;
let ownerAddress: string;
let sender: Signer;
let senderAddress: string;
let recipient: Signer;
let recipientAddress: string;
let c98Token: SampleVRC25Upgradable;
let minFee = hhe.ethers.utils.parseEther('1');
let snapshot: any;

before(async function() {
[owner, sender, recipient] = await hhe.ethers.getSigners();
ownerAddress = await owner.getAddress();
senderAddress = await sender.getAddress();
recipientAddress = await recipient.getAddress();
const tokenFactory = await hhe.ethers.getContractFactory('SampleVRC25Upgradable');
c98Token = await tokenFactory.connect(owner).deploy();
await c98Token.deployed();
});

beforeEach(async function() {
snapshot = await hhe.ethers.provider.send('evm_snapshot', []);
});

afterEach(async function() {
await hhe.ethers.provider.send('evm_revert', [snapshot]);
});

it('cannot set fee without ownership', async function() {
await expect(c98Token.connect(recipient).setFee(minFee))
.to.be.revertedWith('VRC25: caller is not the owner');
});

it('check ownership', async function() {
expect(await c98Token.owner()).to.equal(ownerAddress);
});

it('should transfer ownership', async function() {
await c98Token.transferOwnership(recipientAddress);
expect(await c98Token.owner()).to.equal(ownerAddress);
await c98Token.connect(recipient).acceptOwnership();
expect(await c98Token.owner()).to.equal(recipientAddress);
});

it('cannot transfer ownership without ownership', async function() {
await expect(c98Token.connect(recipient).transferOwnership(recipientAddress))
.to.be.revertedWith('VRC25: caller is not the owner');
});

it('should mint tokens', async function() {
const amount = hhe.ethers.utils.parseEther('1000');
const balanceBefore = await c98Token.balanceOf(recipientAddress);
await c98Token.connect(owner).mint(recipientAddress, amount);
const balanceAfter = await c98Token.balanceOf(recipientAddress);
expect(balanceAfter).to.equal(balanceBefore.add(amount));
});

it('cannot mint without ownership', async function() {
await expect(c98Token.connect(recipient).mint(ownerAddress, hhe.ethers.utils.parseEther('1')))
.to.be.revertedWith('VRC25: caller is not the owner');
});

it('should burn tokens without fee', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
const amount = hhe.ethers.utils.parseEther('100');
await c98Token.setFee(0);
const balanceBefore = await c98Token.balanceOf(senderAddress);
await c98Token.connect(sender).burn(amount);
const balanceAfter = await c98Token.balanceOf(senderAddress);
expect(balanceAfter).to.equal(balanceBefore.sub(amount));
});

it('cannot burn exceeds balance', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
const amount = hhe.ethers.utils.parseEther('1001');
await expect(c98Token.connect(owner).burn(amount))
.to.be.revertedWith('VRC25: insuffient balance');
});

it('should transfer tokens', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
const initialSenderBalance = hhe.ethers.utils.parseEther('1000');
const transferAmount = hhe.ethers.utils.parseEther('500');
const fee = await c98Token.estimateFee(transferAmount);
const initialRecipientBalance = hhe.ethers.BigNumber.from(0);
const ownerBalance = await c98Token.balanceOf(senderAddress);
const recipientBalance = await c98Token.balanceOf(recipientAddress);
expect(ownerBalance).to.equal(initialSenderBalance);
expect(recipientBalance).to.equal(initialRecipientBalance);
await c98Token.connect(sender).transfer(recipientAddress, transferAmount);
expect(await c98Token.balanceOf(senderAddress)).to.equal(initialSenderBalance.sub(transferAmount.add(fee)));
expect(await c98Token.balanceOf(recipientAddress)).to.equal(initialRecipientBalance.add(transferAmount));
});

it('cannot transfer exceeds balance', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
const amount = hhe.ethers.utils.parseEther('1001');
await expect(c98Token.connect(sender).transfer(recipientAddress, amount))
.to.be.revertedWith('VRC25: insuffient balance');
});

it('cannot transfer to the zero address', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
const transferAmount = hhe.ethers.utils.parseEther('500');
await expect(c98Token.connect(sender).transfer(ZERO_ADDRESS, transferAmount))
.to.be.revertedWith('VRC25: transfer to the zero address');
});

it('should approve tokens', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
const beforeAllowance = await c98Token.allowance(senderAddress, recipientAddress);
const amount = hhe.ethers.utils.parseEther('1000');
await c98Token.connect(owner).setFee(minFee);
await expect(await c98Token.connect(sender).approve(recipientAddress, amount))
.changeTokenBalance(c98Token, owner, minFee);
const afterAllowance = await c98Token.allowance(senderAddress, recipientAddress);
expect(afterAllowance).to.equal(beforeAllowance.add(amount));
});

it('cannot approve to the zero address', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
await expect(c98Token.connect(owner).approve(ZERO_ADDRESS, '1'))
.to.be.revertedWith('VRC25: approve to the zero address');
});

it('should transferFrom successful', async function() {
await c98Token.connect(owner).mint(senderAddress, hhe.ethers.utils.parseEther('1000'));
const balanceBefore = await c98Token.balanceOf(recipientAddress);
const amount = hhe.ethers.utils.parseEther('100');
await c98Token.connect(sender).approve(recipientAddress, hhe.ethers.utils.parseEther('200'));
expect(await c98Token.allowance(senderAddress, recipientAddress)).to.equal(hhe.ethers.utils.parseEther('200'));
await c98Token.connect(recipient).transferFrom(senderAddress, recipientAddress, amount);
const fee = await c98Token.estimateFee(amount);
expect(await c98Token.allowance(senderAddress, recipientAddress)).to.equal(hhe.ethers.utils.parseEther('200').sub(amount).sub(fee));
const balanceAfter = await c98Token.balanceOf(recipientAddress);
expect(balanceAfter).to.equal(balanceBefore.add(amount));
});
});