Skip to content
Merged
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
43 changes: 43 additions & 0 deletions contracts/UFragments.sol
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,28 @@ contract UFragments is ERC20Detailed, Ownable {
require(to != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);

uint256 gonValue = value.mul(_gonsPerFragment);

_gonBalances[msg.sender] = _gonBalances[msg.sender].sub(gonValue);
_gonBalances[to] = _gonBalances[to].add(gonValue);

emit Transfer(msg.sender, to, value);
return true;
}

/**
* @dev Transfer all of the sender's wallet balance to a specified address.
* @param to The address to transfer to.
* @return True on success, false otherwise.
*/
function transferAll(address to) external validRecipient(to) returns (bool) {
require(msg.sender != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);

uint256 gonValue = _gonBalances[msg.sender];
uint256 value = gonValue.div(_gonsPerFragment);

delete _gonBalances[msg.sender];
_gonBalances[to] = _gonBalances[to].add(gonValue);

emit Transfer(msg.sender, to, value);
return true;
}
Expand Down Expand Up @@ -221,8 +241,28 @@ contract UFragments is ERC20Detailed, Ownable {
uint256 gonValue = value.mul(_gonsPerFragment);
_gonBalances[from] = _gonBalances[from].sub(gonValue);
_gonBalances[to] = _gonBalances[to].add(gonValue);

emit Transfer(from, to, value);
return true;
}

/**
* @dev Transfer all balance tokens from one address to another.
* @param from The address you want to send tokens from.
* @param to The address you want to transfer to.
*/
function transferAllFrom(address from, address to) external validRecipient(to) returns (bool) {
require(from != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);

uint256 gonValue = _gonBalances[from];
uint256 value = gonValue.div(_gonsPerFragment);

_allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender].sub(value);

delete _gonBalances[from];
_gonBalances[to] = _gonBalances[to].add(gonValue);

emit Transfer(from, to, value);
return true;
}

Expand All @@ -239,6 +279,7 @@ contract UFragments is ERC20Detailed, Ownable {
*/
function approve(address spender, uint256 value) external returns (bool) {
_allowedFragments[msg.sender][spender] = value;

emit Approval(msg.sender, spender, value);
return true;
}
Expand All @@ -256,6 +297,7 @@ contract UFragments is ERC20Detailed, Ownable {

_allowedFragments[msg.sender][spender] = newValue;
emit Approval(msg.sender, spender, newValue);

return true;
}

Expand All @@ -276,6 +318,7 @@ contract UFragments is ERC20Detailed, Ownable {

_allowedFragments[msg.sender][spender] = newValue;
emit Approval(msg.sender, spender, newValue);

return true;
}
}
10 changes: 0 additions & 10 deletions test/unit/UFragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,10 @@ describe('UFragments:Initialization', () => {
)
})

it("should set the deployer's scaled balance", async function () {
expect(await uFragments.scaledBalanceOf(await deployer.getAddress())).to.eq(
TOTAL_GONS,
)
})

it('should set the totalSupply to 50M', async function () {
expect(await uFragments.totalSupply()).to.eq(INITIAL_SUPPLY)
})

it('should set the scaledTotalSupply', async function () {
expect(await uFragments.scaledTotalSupply()).to.eq(TOTAL_GONS)
})

it('should set the owner', async function () {
expect(await uFragments.owner()).to.eq(await deployer.getAddress())
})
Expand Down
258 changes: 258 additions & 0 deletions test/unit/uFragments_elastic_behavior.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
import { ethers, upgrades, waffle } from 'hardhat'
import { Contract, Signer, BigNumber } from 'ethers'
import { TransactionResponse } from '@ethersproject/providers'
import { expect } from 'chai'

const DECIMALS = 9
const INITIAL_SUPPLY = ethers.utils.parseUnits('50', 6 + DECIMALS)
const MAX_UINT256 = ethers.BigNumber.from(2).pow(256).sub(1)
const MAX_INT256 = ethers.BigNumber.from(2).pow(255).sub(1)
const TOTAL_GONS = MAX_UINT256.sub(MAX_UINT256.mod(INITIAL_SUPPLY))

const toUFrgDenomination = (ample: string): BigNumber =>
ethers.utils.parseUnits(ample, DECIMALS)

const unitTokenAmount = toUFrgDenomination('1')

let token: Contract, owner: Signer, anotherAccount: Signer, recipient: Signer

async function upgradeableToken() {
const [owner, recipient, anotherAccount] = await ethers.getSigners()
const factory = await ethers.getContractFactory('UFragments')
const token = await upgrades.deployProxy(
factory.connect(owner),
[await owner.getAddress()],
{
initializer: 'initialize(address)',
},
)
return { token, owner, recipient, anotherAccount }
}

describe('UFragments:Elastic', () => {
beforeEach('setup UFragments contract', async function () {
;({ token, owner, recipient, anotherAccount } = await waffle.loadFixture(
upgradeableToken,
))
})

describe('scaledTotalSupply', function () {
it('returns the scaled total amount of tokens', async function () {
expect(await token.scaledTotalSupply()).to.eq(TOTAL_GONS)
})
})

describe('scaledBalanceOf', function () {
describe('when the requested account has no tokens', function () {
it('returns zero', async function () {
expect(
await token.scaledBalanceOf(await anotherAccount.getAddress()),
).to.eq(0)
})
})

describe('when the requested account has some tokens', function () {
it('returns the total amount of tokens', async function () {
expect(await token.scaledBalanceOf(await owner.getAddress())).to.eq(
TOTAL_GONS,
)
})
})
})
})

describe('UFragments:Elastic:transferAll', () => {
beforeEach('setup UFragments contract', async function () {
;({ token, owner, recipient, anotherAccount } = await waffle.loadFixture(
upgradeableToken,
))
})

describe('when the recipient is the zero address', function () {
it('should revert', async function () {
await expect(
token.connect(owner).transferAll(ethers.constants.AddressZero),
).to.be.reverted
})
})

describe('when the recipient is the contract address', function () {
it('should revert', async function () {
await expect(token.connect(owner).transferAll(token.address)).to.be
.reverted
})
})

describe('when the sender has zero balance', function () {
it('should not revert', async function () {
await expect(
token.connect(anotherAccount).transferAll(await owner.getAddress()),
).not.to.be.reverted
})
})

describe('when the sender has balance', function () {
it('should emit a transfer event', async function () {
await expect(
token.connect(owner).transferAll(await recipient.getAddress()),
)
.to.emit(token, 'Transfer')
.withArgs(
await owner.getAddress(),
await recipient.getAddress(),
INITIAL_SUPPLY,
)
})

it("should transfer all of the sender's balance", async function () {
const senderBalance = await token.balanceOf(await owner.getAddress())
const recipientBalance = await token.balanceOf(
await recipient.getAddress(),
)
await token.connect(owner).transferAll(await recipient.getAddress())
const senderBalance_ = await token.balanceOf(await owner.getAddress())
const recipientBalance_ = await token.balanceOf(
await recipient.getAddress(),
)
expect(senderBalance_).to.eq('0')
expect(recipientBalance_.sub(recipientBalance)).to.eq(senderBalance)
})
})
})

describe('UFragments:Elastic:transferAllFrom', () => {
beforeEach('setup UFragments contract', async function () {
;({ token, owner, recipient, anotherAccount } = await waffle.loadFixture(
upgradeableToken,
))
})

describe('when the recipient is the zero address', function () {
it('should revert', async function () {
const senderBalance = await token.balanceOf(await owner.getAddress())
await token
.connect(owner)
.approve(await anotherAccount.getAddress(), senderBalance)
await expect(
token
.connect(anotherAccount)
.transferAllFrom(
await owner.getAddress(),
ethers.constants.AddressZero,
),
).to.be.reverted
})
})

describe('when the recipient is the contract address', function () {
it('should revert', async function () {
const senderBalance = await token.balanceOf(await owner.getAddress())
await token
.connect(owner)
.approve(await anotherAccount.getAddress(), senderBalance)
await expect(
token
.connect(anotherAccount)
.transferAllFrom(await owner.getAddress(), token.address),
).to.be.reverted
})
})

describe('when the sender has zero balance', function () {
it('should not revert', async function () {
const senderBalance = await token.balanceOf(
await anotherAccount.getAddress(),
)
await token
.connect(anotherAccount)
.approve(await anotherAccount.getAddress(), senderBalance)

await expect(
token
.connect(recipient)
.transferAllFrom(
await anotherAccount.getAddress(),
await recipient.getAddress(),
),
).not.to.be.reverted
})
})

describe('when the spender does NOT have enough approved balance', function () {
it('reverts', async function () {
await token
.connect(owner)
.approve(await anotherAccount.getAddress(), unitTokenAmount)
await expect(
token
.connect(anotherAccount)
.transferAllFrom(
await owner.getAddress(),
await recipient.getAddress(),
),
).to.be.reverted
})
})

describe('when the spender has enough approved balance', function () {
it('emits a transfer event', async function () {
const senderBalance = await token.balanceOf(await owner.getAddress())
await token
.connect(owner)
.approve(await anotherAccount.getAddress(), senderBalance)

await expect(
token
.connect(anotherAccount)
.transferAllFrom(
await owner.getAddress(),
await recipient.getAddress(),
),
)
.to.emit(token, 'Transfer')
.withArgs(
await owner.getAddress(),
await recipient.getAddress(),
senderBalance,
)
})

it('transfers the requested amount', async function () {
const senderBalance = await token.balanceOf(await owner.getAddress())
const recipientBalance = await token.balanceOf(
await recipient.getAddress(),
)

await token
.connect(owner)
.approve(await anotherAccount.getAddress(), senderBalance)

await token
.connect(anotherAccount)
.transferAllFrom(await owner.getAddress(), await recipient.getAddress())

const senderBalance_ = await token.balanceOf(await owner.getAddress())
const recipientBalance_ = await token.balanceOf(
await recipient.getAddress(),
)
expect(senderBalance_).to.eq('0')
expect(recipientBalance_.sub(recipientBalance)).to.eq(senderBalance)
})

it('decreases the spender allowance', async function () {
const senderBalance = await token.balanceOf(await owner.getAddress())
await token
.connect(owner)
.approve(await anotherAccount.getAddress(), senderBalance.add('99'))
await token
.connect(anotherAccount)
.transferAllFrom(await owner.getAddress(), await recipient.getAddress())
expect(
await token.allowance(
await owner.getAddress(),
await anotherAccount.getAddress(),
),
).to.eq('99')
})
})
})