Skip to content

Commit

Permalink
Merge branch 'main' into mike/update_consts_manager
Browse files Browse the repository at this point in the history
# Conflicts:
#	contracts/sfc/SFC.sol
  • Loading branch information
Mike-CZ committed Jan 31, 2025
2 parents 4d29843 + 05eba01 commit 6b738b0
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 9 deletions.
24 changes: 16 additions & 8 deletions contracts/sfc/SFC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
// values
error ZeroAmount();
error ZeroRewards();
error ValueTooLarge();

// pubkeys
error PubkeyUsedByOtherValidator();
Expand Down Expand Up @@ -216,7 +217,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
);
event ClaimedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards);
event RestakedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards);
event BurntFTM(uint256 amount);
event BurntNativeTokens(uint256 amount);
event UpdatedSlashingRefundRatio(uint256 indexed validatorID, uint256 refundRatio);
event RefundedSlashedLegacyDelegation(address indexed delegator, uint256 indexed validatorID, uint256 amount);
event AnnouncedRedirection(address indexed from, address indexed to);
Expand Down Expand Up @@ -459,9 +460,12 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
emit TreasuryFeesResolved(fees);
}

/// burnFTM allows SFC to burn an arbitrary amount of FTM tokens.
function burnFTM(uint256 amount) external onlyOwner {
_burnFTM(amount);
/// Burn native tokens by sending them to the SFC contract.
function burnNativeTokens() external payable {
if (msg.value == 0) {
revert ZeroAmount();
}
_burnNativeTokens(msg.value);
}

/// Issue tokens to the issued tokens recipient as a counterparty to the burnt FTM tokens.
Expand Down Expand Up @@ -753,7 +757,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
if (!sent) {
revert TransferFailed();
}
_burnFTM(penalty);
_burnNativeTokens(penalty);

emit Withdrawn(delegator, toValidatorID, wrID, amount - penalty, penalty);
}
Expand Down Expand Up @@ -817,12 +821,16 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
return rewards;
}

/// Burn FTM tokens.
/// Burn native tokens.
/// The tokens are sent to the zero address.
function _burnFTM(uint256 amount) internal {
function _burnNativeTokens(uint256 amount) internal {
if (amount != 0) {
if (amount > totalSupply) {
revert ValueTooLarge();
}
totalSupply -= amount;
payable(address(0)).transfer(amount);
emit BurntFTM(amount);
emit BurntNativeTokens(amount);
}
}

Expand Down
30 changes: 29 additions & 1 deletion test/SFC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { BlockchainNode, ValidatorMetrics } from './helpers/BlockchainNode';
describe('SFC', () => {
const fixture = async () => {
const [owner, user] = await ethers.getSigners();
const totalSupply = ethers.parseEther('100');
const sfc = await upgrades.deployProxy(await ethers.getContractFactory('UnitTestSFC'), {
kind: 'uups',
initializer: false,
Expand All @@ -24,7 +25,7 @@ describe('SFC', () => {
const evmWriter: IEVMWriter = await ethers.deployContract('StubEvmWriter');
const initializer: UnitTestNetworkInitializer = await ethers.deployContract('UnitTestNetworkInitializer');

await initializer.initializeAll(0, 0, sfc, nodeDriverAuth, nodeDriver, evmWriter, owner);
await initializer.initializeAll(0, totalSupply, sfc, nodeDriverAuth, nodeDriver, evmWriter, owner);
const constants: UnitTestConstantsManager = await ethers.getContractAt(
'UnitTestConstantsManager',
await sfc.constsAddress(),
Expand All @@ -39,6 +40,7 @@ describe('SFC', () => {
nodeDriver,
nodeDriverAuth,
constants,
totalSupply,
};
};

Expand All @@ -55,6 +57,32 @@ describe('SFC', () => {
).to.revertedWithCustomError(this.sfc, 'TransfersNotAllowed');
});

describe('Burn native tokens', () => {
it('Should revert when no amount sent', async function () {
await expect(this.sfc.connect(this.user).burnNativeTokens()).to.be.revertedWithCustomError(
this.sfc,
'ZeroAmount',
);
});

it('Should revert when amount greater than total supply', async function () {
await expect(
this.sfc.connect(this.user).burnNativeTokens({ value: this.totalSupply + 1n }),
).to.be.revertedWithCustomError(this.sfc, 'ValueTooLarge');
});

it('Should succeed and burn native tokens', async function () {
const amount = ethers.parseEther('1.5');
const totalSupply = await this.sfc.totalSupply();
const tx = await this.sfc.connect(this.user).burnNativeTokens({ value: amount });
await expect(tx).to.emit(this.sfc, 'BurntNativeTokens').withArgs(amount);
expect(await this.sfc.totalSupply()).to.equal(totalSupply - amount);
await expect(tx).to.changeEtherBalance(this.sfc, 0);
await expect(tx).to.changeEtherBalance(this.user, -amount);
await expect(tx).to.changeEtherBalance(ethers.ZeroAddress, amount);
});
});

describe('Genesis validator', () => {
beforeEach(async function () {
const validator = ethers.Wallet.createRandom();
Expand Down

0 comments on commit 6b738b0

Please sign in to comment.