Skip to content

Commit 62c4467

Browse files
brandonilesBrandon Iles
andauthored
Add burn and burnFrom (#2)
* burn, burnFrom Co-authored-by: Brandon Iles <brandon@ampleforth.org>
1 parent b995bae commit 62c4467

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

contracts/Forth.sol

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,49 @@ contract Forth {
131131
_moveDelegates(address(0), delegates[dst], amount);
132132
}
133133

134+
/**
135+
* @notice Destroys `amount` tokens from the caller
136+
* @param rawAmount The number of tokens to burn
137+
*/
138+
function burn(uint256 rawAmount) external {
139+
uint96 amount = safe96(rawAmount, "Forth::burn: rawAmount exceeds 96 bits");
140+
_burn(msg.sender, amount);
141+
}
142+
143+
/**
144+
* @notice Destroys `amount` tokens from `account`, deducting from the caller's allowance
145+
* @param account The address of the account to burn from
146+
* @param rawAmount The number of tokens to burn
147+
*/
148+
function burnFrom(address account, uint256 rawAmount) external {
149+
uint96 amount = safe96(rawAmount, "Forth::burnFrom: rawAmount exceeds 96 bits");
150+
151+
uint96 decreasedAllowance =
152+
sub96(allowances[account][msg.sender], amount, "Forth::burnFrom: amount exceeds allowance");
153+
allowances[account][msg.sender] = decreasedAllowance;
154+
emit Approval(account, msg.sender, decreasedAllowance);
155+
156+
_burn(account, amount);
157+
}
158+
159+
/**
160+
* @notice Destroys `amount` tokens from `account`, reducing the total supply
161+
* @param account The address of the account to burn from
162+
* @param amount The number of tokens to burn
163+
*/
164+
function _burn(address account, uint96 amount) internal {
165+
require(account != address(0), "Forth::_burn: burn from the zero address");
166+
167+
uint96 supply = safe96(totalSupply, "Forth::_burn: old supply exceeds 96 bits");
168+
totalSupply = sub96(supply, amount, "Forth::_burn: amount exceeds totalSupply");
169+
170+
balances[account] = sub96(balances[account], amount, "Forth::_burn: amount exceeds balance");
171+
emit Transfer(account, address(0), amount);
172+
173+
// move delegates
174+
_moveDelegates(delegates[account], address(0), amount);
175+
}
176+
134177
/**
135178
* @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
136179
* @param account The address of the account holding the funds

test/Forth.spec.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,76 @@ describe('Forth', () => {
126126
'Forth::mint: exceeded mint cap'
127127
)
128128
})
129+
130+
it('burn', async () => {
131+
const { timestamp: now } = await provider.getBlock('latest')
132+
const forth = await deployContract(wallet, Forth, [wallet.address, wallet.address, now + 60 * 60])
133+
const supply = await forth.totalSupply()
134+
135+
// burn 0
136+
let balanceBefore = await forth.balanceOf(wallet.address)
137+
await forth.connect(wallet).burn(0)
138+
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore)
139+
expect(await forth.totalSupply()).to.be.eq(supply)
140+
141+
// burn non-zero
142+
await forth.connect(wallet).burn(1)
143+
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore.sub(1))
144+
expect(await forth.totalSupply()).to.be.eq(supply.sub(1))
145+
146+
// burn > totalSupply
147+
await expect(forth.connect(wallet).burn(supply + 2)).to.be.revertedWith('Forth::_burn: amount exceeds totalSupply')
148+
149+
// burn > balance
150+
await forth.connect(wallet).transfer(other0.address, 100)
151+
balanceBefore = await forth.balanceOf(wallet.address)
152+
await expect(forth.connect(wallet).burn(balanceBefore.add(1))).to.be.revertedWith(
153+
'Forth::_burn: amount exceeds balance'
154+
)
155+
})
156+
157+
it('burnFrom', async () => {
158+
const { timestamp: now } = await provider.getBlock('latest')
159+
const forth = await deployContract(wallet, Forth, [wallet.address, wallet.address, now + 60 * 60])
160+
const supply = await forth.totalSupply()
161+
162+
// burn 0
163+
let balanceBefore = await forth.balanceOf(wallet.address)
164+
await forth.connect(other0).burnFrom(wallet.address, 0)
165+
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore)
166+
expect(await forth.totalSupply()).to.be.eq(supply)
167+
168+
// burn non-zero
169+
await forth.connect(wallet).approve(other0.address, 100)
170+
await forth.connect(other0).burnFrom(wallet.address, 1)
171+
expect(await forth.balanceOf(wallet.address)).to.be.eq(balanceBefore.sub(1))
172+
expect(await forth.totalSupply()).to.be.eq(supply.sub(1))
173+
174+
// burn > approval
175+
balanceBefore = await forth.balanceOf(wallet.address)
176+
await forth.connect(wallet).approve(other0.address, 100)
177+
await expect(forth.connect(other0).burnFrom(wallet.address, 101)).to.be.revertedWith(
178+
'Forth::burnFrom: amount exceeds allowance'
179+
)
180+
181+
// burn > totalSupply
182+
balanceBefore = await forth.balanceOf(wallet.address)
183+
await forth.connect(wallet).approve(other0.address, balanceBefore.add(1))
184+
await expect(forth.connect(other0).burnFrom(wallet.address, balanceBefore.add(1))).to.be.revertedWith(
185+
'Forth::_burn: amount exceeds totalSupply'
186+
)
187+
188+
// burn > balance
189+
await forth.connect(wallet).transfer(other0.address, 100)
190+
balanceBefore = await forth.balanceOf(wallet.address)
191+
await forth.connect(wallet).approve(other0.address, balanceBefore.add(1))
192+
await expect(forth.connect(other0).burnFrom(wallet.address, balanceBefore.add(1))).to.be.revertedWith(
193+
'Forth::_burn: amount exceeds balance'
194+
)
195+
196+
// Zero Address
197+
await expect(forth.connect(wallet).burnFrom('0x0000000000000000000000000000000000000000', 0)).to.be.revertedWith(
198+
'Forth::_burn: burn from the zero address'
199+
)
200+
})
129201
})

0 commit comments

Comments
 (0)