Skip to content

Commit d98e9c4

Browse files
committed
fixes #184 added transfer all and transfer all from
1 parent 4aba740 commit d98e9c4

File tree

3 files changed

+304
-10
lines changed

3 files changed

+304
-10
lines changed

contracts/UFragments.sol

+46
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,29 @@ contract UFragments is ERC20Detailed, Ownable {
185185
require(to != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);
186186

187187
uint256 gonValue = value.mul(_gonsPerFragment);
188+
188189
_gonBalances[msg.sender] = _gonBalances[msg.sender].sub(gonValue);
189190
_gonBalances[to] = _gonBalances[to].add(gonValue);
191+
192+
emit Transfer(msg.sender, to, value);
193+
return true;
194+
}
195+
196+
/**
197+
* @dev Transfer all of the sender's wallet balance to a specified address.
198+
* @param to The address to transfer to.
199+
* @return True on success, false otherwise.
200+
*/
201+
function transferAll(address to) external validRecipient(to) returns (bool) {
202+
require(msg.sender != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);
203+
require(to != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);
204+
205+
uint256 gonValue = _gonBalances[msg.sender];
206+
uint256 value = gonValue.div(_gonsPerFragment);
207+
208+
delete _gonBalances[msg.sender];
209+
_gonBalances[to] = _gonBalances[to].add(gonValue);
210+
190211
emit Transfer(msg.sender, to, value);
191212
return true;
192213
}
@@ -221,8 +242,30 @@ contract UFragments is ERC20Detailed, Ownable {
221242
uint256 gonValue = value.mul(_gonsPerFragment);
222243
_gonBalances[from] = _gonBalances[from].sub(gonValue);
223244
_gonBalances[to] = _gonBalances[to].add(gonValue);
245+
224246
emit Transfer(from, to, value);
247+
return true;
248+
}
225249

250+
/**
251+
* @dev Transfer all balance tokens from one address to another.
252+
* @param from The address you want to send tokens from.
253+
* @param to The address you want to transfer to.
254+
*/
255+
function transferAllFrom(address from, address to) external validRecipient(to) returns (bool) {
256+
require(msg.sender != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);
257+
require(from != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);
258+
require(to != 0xeB31973E0FeBF3e3D7058234a5eBbAe1aB4B8c23);
259+
260+
uint256 gonValue = _gonBalances[from];
261+
uint256 value = gonValue.div(_gonsPerFragment);
262+
263+
_allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender].sub(value);
264+
265+
_gonBalances[from] = _gonBalances[from].sub(gonValue);
266+
_gonBalances[to] = _gonBalances[to].add(gonValue);
267+
268+
emit Transfer(from, to, value);
226269
return true;
227270
}
228271

@@ -239,6 +282,7 @@ contract UFragments is ERC20Detailed, Ownable {
239282
*/
240283
function approve(address spender, uint256 value) external returns (bool) {
241284
_allowedFragments[msg.sender][spender] = value;
285+
242286
emit Approval(msg.sender, spender, value);
243287
return true;
244288
}
@@ -256,6 +300,7 @@ contract UFragments is ERC20Detailed, Ownable {
256300

257301
_allowedFragments[msg.sender][spender] = newValue;
258302
emit Approval(msg.sender, spender, newValue);
303+
259304
return true;
260305
}
261306

@@ -276,6 +321,7 @@ contract UFragments is ERC20Detailed, Ownable {
276321

277322
_allowedFragments[msg.sender][spender] = newValue;
278323
emit Approval(msg.sender, spender, newValue);
324+
279325
return true;
280326
}
281327
}

test/unit/UFragments.ts

-10
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,10 @@ describe('UFragments:Initialization', () => {
5555
)
5656
})
5757

58-
it("should set the deployer's scaled balance", async function () {
59-
expect(await uFragments.scaledBalanceOf(await deployer.getAddress())).to.eq(
60-
TOTAL_GONS,
61-
)
62-
})
63-
6458
it('should set the totalSupply to 50M', async function () {
6559
expect(await uFragments.totalSupply()).to.eq(INITIAL_SUPPLY)
6660
})
6761

68-
it('should set the scaledTotalSupply', async function () {
69-
expect(await uFragments.scaledTotalSupply()).to.eq(TOTAL_GONS)
70-
})
71-
7262
it('should set the owner', async function () {
7363
expect(await uFragments.owner()).to.eq(await deployer.getAddress())
7464
})
+258
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
import { ethers, upgrades, waffle } from 'hardhat'
2+
import { Contract, Signer, BigNumber } from 'ethers'
3+
import { TransactionResponse } from '@ethersproject/providers'
4+
import { expect } from 'chai'
5+
6+
const DECIMALS = 9
7+
const INITIAL_SUPPLY = ethers.utils.parseUnits('50', 6 + DECIMALS)
8+
const MAX_UINT256 = ethers.BigNumber.from(2).pow(256).sub(1)
9+
const MAX_INT256 = ethers.BigNumber.from(2).pow(255).sub(1)
10+
const TOTAL_GONS = MAX_UINT256.sub(MAX_UINT256.mod(INITIAL_SUPPLY))
11+
12+
const toUFrgDenomination = (ample: string): BigNumber =>
13+
ethers.utils.parseUnits(ample, DECIMALS)
14+
15+
const unitTokenAmount = toUFrgDenomination('1')
16+
17+
let token: Contract, owner: Signer, anotherAccount: Signer, recipient: Signer
18+
19+
async function upgradeableToken() {
20+
const [owner, recipient, anotherAccount] = await ethers.getSigners()
21+
const factory = await ethers.getContractFactory('UFragments')
22+
const token = await upgrades.deployProxy(
23+
factory.connect(owner),
24+
[await owner.getAddress()],
25+
{
26+
initializer: 'initialize(address)',
27+
},
28+
)
29+
return { token, owner, recipient, anotherAccount }
30+
}
31+
32+
describe('UFragments:ElasticERC20', () => {
33+
beforeEach('setup UFragments contract', async function () {
34+
;({ token, owner, recipient, anotherAccount } = await waffle.loadFixture(
35+
upgradeableToken,
36+
))
37+
})
38+
39+
describe('scaledTotalSupply', function () {
40+
it('returns the scaled total amount of tokens', async function () {
41+
expect(await token.scaledTotalSupply()).to.eq(TOTAL_GONS)
42+
})
43+
})
44+
45+
describe('scaledBalanceOf', function () {
46+
describe('when the requested account has no tokens', function () {
47+
it('returns zero', async function () {
48+
expect(
49+
await token.scaledBalanceOf(await anotherAccount.getAddress()),
50+
).to.eq(0)
51+
})
52+
})
53+
54+
describe('when the requested account has some tokens', function () {
55+
it('returns the total amount of tokens', async function () {
56+
expect(await token.scaledBalanceOf(await owner.getAddress())).to.eq(
57+
TOTAL_GONS,
58+
)
59+
})
60+
})
61+
})
62+
})
63+
64+
describe('UFragments:ERC20:transferAll', () => {
65+
beforeEach('setup UFragments contract', async function () {
66+
;({ token, owner, recipient, anotherAccount } = await waffle.loadFixture(
67+
upgradeableToken,
68+
))
69+
})
70+
71+
describe('when the recipient is the zero address', function () {
72+
it('should revert', async function () {
73+
await expect(
74+
token.connect(owner).transferAll(ethers.constants.AddressZero),
75+
).to.be.reverted
76+
})
77+
})
78+
79+
describe('when the recipient is the contract address', function () {
80+
it('should revert', async function () {
81+
await expect(token.connect(owner).transferAll(token.address)).to.be
82+
.reverted
83+
})
84+
})
85+
86+
describe('when the sender has zero balance', function () {
87+
it('should not revert', async function () {
88+
await expect(
89+
token.connect(anotherAccount).transferAll(await owner.getAddress()),
90+
).not.to.be.reverted
91+
})
92+
})
93+
94+
describe('when the sender has balance', function () {
95+
it('should emit a transfer event', async function () {
96+
await expect(
97+
token.connect(owner).transferAll(await recipient.getAddress()),
98+
)
99+
.to.emit(token, 'Transfer')
100+
.withArgs(
101+
await owner.getAddress(),
102+
await recipient.getAddress(),
103+
INITIAL_SUPPLY,
104+
)
105+
})
106+
107+
it("should transfer all of the sender's balance", async function () {
108+
const senderBalance = await token.balanceOf(await owner.getAddress())
109+
const recipientBalance = await token.balanceOf(
110+
await recipient.getAddress(),
111+
)
112+
await token.connect(owner).transferAll(await recipient.getAddress())
113+
const senderBalance_ = await token.balanceOf(await owner.getAddress())
114+
const recipientBalance_ = await token.balanceOf(
115+
await recipient.getAddress(),
116+
)
117+
expect(senderBalance_).to.eq('0')
118+
expect(recipientBalance_.sub(recipientBalance)).to.eq(senderBalance)
119+
})
120+
})
121+
})
122+
123+
describe('UFragments:ERC20:transferAllFrom', () => {
124+
beforeEach('setup UFragments contract', async function () {
125+
;({ token, owner, recipient, anotherAccount } = await waffle.loadFixture(
126+
upgradeableToken,
127+
))
128+
})
129+
130+
describe('when the recipient is the zero address', function () {
131+
it('should revert', async function () {
132+
const senderBalance = await token.balanceOf(await owner.getAddress())
133+
await token
134+
.connect(owner)
135+
.approve(await anotherAccount.getAddress(), senderBalance)
136+
await expect(
137+
token
138+
.connect(anotherAccount)
139+
.transferAllFrom(
140+
await owner.getAddress(),
141+
ethers.constants.AddressZero,
142+
),
143+
).to.be.reverted
144+
})
145+
})
146+
147+
describe('when the recipient is the contract address', function () {
148+
it('should revert', async function () {
149+
const senderBalance = await token.balanceOf(await owner.getAddress())
150+
await token
151+
.connect(owner)
152+
.approve(await anotherAccount.getAddress(), senderBalance)
153+
await expect(
154+
token
155+
.connect(anotherAccount)
156+
.transferAllFrom(await owner.getAddress(), token.address),
157+
).to.be.reverted
158+
})
159+
})
160+
161+
describe('when the sender has zero balance', function () {
162+
it('should not revert', async function () {
163+
const senderBalance = await token.balanceOf(
164+
await anotherAccount.getAddress(),
165+
)
166+
await token
167+
.connect(anotherAccount)
168+
.approve(await anotherAccount.getAddress(), senderBalance)
169+
170+
await expect(
171+
token
172+
.connect(recipient)
173+
.transferAllFrom(
174+
await anotherAccount.getAddress(),
175+
await recipient.getAddress(),
176+
),
177+
).not.to.be.reverted
178+
})
179+
})
180+
181+
describe('when the spender does NOT have enough approved balance', function () {
182+
it('reverts', async function () {
183+
await token
184+
.connect(owner)
185+
.approve(await anotherAccount.getAddress(), unitTokenAmount)
186+
await expect(
187+
token
188+
.connect(anotherAccount)
189+
.transferAllFrom(
190+
await owner.getAddress(),
191+
await recipient.getAddress(),
192+
),
193+
).to.be.reverted
194+
})
195+
})
196+
197+
describe('when the spender has enough approved balance', function () {
198+
it('emits a transfer event', async function () {
199+
const senderBalance = await token.balanceOf(await owner.getAddress())
200+
await token
201+
.connect(owner)
202+
.approve(await anotherAccount.getAddress(), senderBalance)
203+
204+
await expect(
205+
token
206+
.connect(anotherAccount)
207+
.transferAllFrom(
208+
await owner.getAddress(),
209+
await recipient.getAddress(),
210+
),
211+
)
212+
.to.emit(token, 'Transfer')
213+
.withArgs(
214+
await owner.getAddress(),
215+
await recipient.getAddress(),
216+
senderBalance,
217+
)
218+
})
219+
220+
it('transfers the requested amount', async function () {
221+
const senderBalance = await token.balanceOf(await owner.getAddress())
222+
const recipientBalance = await token.balanceOf(
223+
await recipient.getAddress(),
224+
)
225+
226+
await token
227+
.connect(owner)
228+
.approve(await anotherAccount.getAddress(), senderBalance)
229+
230+
await token
231+
.connect(anotherAccount)
232+
.transferAllFrom(await owner.getAddress(), await recipient.getAddress())
233+
234+
const senderBalance_ = await token.balanceOf(await owner.getAddress())
235+
const recipientBalance_ = await token.balanceOf(
236+
await recipient.getAddress(),
237+
)
238+
expect(senderBalance_).to.eq('0')
239+
expect(recipientBalance_.sub(recipientBalance)).to.eq(senderBalance)
240+
})
241+
242+
it('decreases the spender allowance', async function () {
243+
const senderBalance = await token.balanceOf(await owner.getAddress())
244+
await token
245+
.connect(owner)
246+
.approve(await anotherAccount.getAddress(), senderBalance.add('99'))
247+
await token
248+
.connect(anotherAccount)
249+
.transferAllFrom(await owner.getAddress(), await recipient.getAddress())
250+
expect(
251+
await token.allowance(
252+
await owner.getAddress(),
253+
await anotherAccount.getAddress(),
254+
),
255+
).to.eq('99')
256+
})
257+
})
258+
})

0 commit comments

Comments
 (0)