Skip to content

Commit

Permalink
refactor: restrict the burning ability to just the token holders;
Browse files Browse the repository at this point in the history
refactor: change the signature of INativeTokens::burn();
refactor: change the type of sub id and token id to uint256;
refactor: remove the unused code;

chore: format the code in the repo;
chore: work around the forge fmt <-> bun solhint max-line conflict.
  • Loading branch information
IaroslavMazur committed Jul 1, 2024
1 parent a6d5454 commit 249a174
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 76 deletions.
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"compiler-version": ["error", ">=0.8.12"],
"func-name-mixedcase": "off",
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": ["error", 120],
"max-line-length": ["error", 123],
"named-parameters-mapping": "warn",
"no-console": "off",
"not-rely-on-time": "off",
Expand Down
58 changes: 29 additions & 29 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config

[profile.default]
auto_detect_solc = false
block_timestamp = 1717200000 # June 1, 2024 at 00:00 GMT
bytecode_hash = "none"
evm_version = "shanghai"
fuzz = { runs = 1_000 }
gas_reports = ["SRF20"]
optimizer = true
optimizer_runs = 10_000
out = "out"
script = "script"
solc = "0.8.26"
src = "src"
test = "test"
auto_detect_solc = false
block_timestamp = 1717200000 # June 1, 2024 at 00:00 GMT
bytecode_hash = "none"
evm_version = "shanghai"
fuzz = { runs = 1_000 }
gas_reports = ["SRF20"]
optimizer = true
optimizer_runs = 10_000
out = "out"
script = "script"
solc = "0.8.26"
src = "src"
test = "test"

[profile.ci]
fuzz = { runs = 10_000 }
verbosity = 4
fuzz = { runs = 10_000 }
verbosity = 4

# Speed up compilation and tests during development
[profile.lite]
optimizer = false
optimizer = false

[doc]
ignore = ["**/*.t.sol"]
out = "docs"
repository = "https://github.com/sablier-labs/stdlib"
ignore = ["**/*.t.sol"]
out = "docs"
repository = "https://github.com/sablier-labs/stdlib"

[fmt]
bracket_spacing = true
int_types = "long"
line_length = 120
multiline_func_header = "all"
number_underscore = "thousands"
quote_style = "double"
tab_width = 4
wrap_comments = true
bracket_spacing = true
int_types = "long"
line_length = 120
multiline_func_header = "all"
number_underscore = "thousands"
quote_style = "double"
tab_width = 4
wrap_comments = true

[rpc_endpoints]
localhost = "http://localhost:8545"
sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}"
localhost = "http://localhost:8545"
sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}"
4 changes: 1 addition & 3 deletions src/Constants.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.12;

// import { SubID } from "./Types.sol";

/*//////////////////////////////////////////////////////////////////////////
NATIVE TOKENS
//////////////////////////////////////////////////////////////////////////*/

bytes32 constant DEFAULT_SUB_ID = bytes32(0);
uint256 constant DEFAULT_SUB_ID = 0;

/*//////////////////////////////////////////////////////////////////////////
PRECOMPILES
Expand Down
2 changes: 2 additions & 0 deletions src/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
pragma solidity >=0.8.12;

error StdLib_UnknownError(string message);

error StdLib_UnauthorizedCaller(string message);
6 changes: 0 additions & 6 deletions src/Types.sol

This file was deleted.

12 changes: 6 additions & 6 deletions src/precompiles/native-tokens/INativeTokens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ pragma solidity >=0.8.12;
/// This interface is used by the library to ABI encode the precompile calls.
interface INativeTokens {
function balanceOf(uint256 tokenID, address account) external returns (uint256);
function burn(address holder, bytes32 subID, uint256 amount) external;
function mint(address recipient, bytes32 subID, uint256 amount) external;
function transfer(address from, address to, bytes32 tokenID, uint256 amount) external;
function burn(uint256 subID, address holder, uint256 amount) external;
function mint(address recipient, uint256 subID, uint256 amount) external;
function transfer(address from, address to, uint256 tokenID, uint256 amount) external;
function transferAndCall(
address from,
address to,
bytes32 tokenID,
uint256 tokenID,
uint256 amount,
address callee,
bytes calldata data
Expand All @@ -21,14 +21,14 @@ interface INativeTokens {
function transferMultiple(
address from,
address[] calldata to,
bytes32[] calldata tokenIDs,
uint256[] calldata tokenIDs,
uint256[] calldata amounts
)
external;
function transferMultipleAndCall(
address from,
address[] calldata to,
bytes32[] calldata tokenIDs,
uint256[] calldata tokenIDs,
uint256[] calldata amounts,
address callee,
bytes calldata data
Expand Down
50 changes: 26 additions & 24 deletions src/precompiles/native-tokens/NativeTokens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity >=0.8.12;

import { PRECOMPILE_NATIVE_TOKENS } from "../../Constants.sol";
import { StdLib_UnknownError } from "../../Errors.sol";
import { StdLib_UnauthorizedCaller, StdLib_UnknownError } from "../../Errors.sol";
import { INativeTokens } from "./INativeTokens.sol";

library NativeTokens {
Expand All @@ -14,12 +14,12 @@ library NativeTokens {
/// @param tokenID The ID of the native token to query the balance of.
/// @param account The address to query the balance of.
/// @return The balance of the `account` for the native token `tokenID`, denoted in 18 decimals.
function balanceOf(uint256 tokenID, address account) internal view returns (uint256) {
function balanceOf(uint256 tokenID, address account) external view returns (uint256) {
// ABI encode the input parameters.
bytes memory precompileData = abi.encodeCall(INativeTokens.balanceOf, (tokenID, account));
bytes memory callData = abi.encodeCall(INativeTokens.balanceOf, (tokenID, account));

// Call the precompile.
(bool success, bytes memory returnData) = PRECOMPILE_NATIVE_TOKENS.staticcall(precompileData);
(bool success, bytes memory returnData) = PRECOMPILE_NATIVE_TOKENS.staticcall(callData);

// This is an unexpected error since the VM should have panicked if the call failed.
if (!success) {
Expand All @@ -38,35 +38,37 @@ library NativeTokens {
/// @dev Generates a Burn receipt.
///
/// Requirements:
/// - The caller of this function must be a contract.
/// - The holder must have at least `amount` tokens.
///
/// @param holder The address to burn native tokens from.
/// @param subID The sub-identifier of the native token to burn.
/// @param amount The quantity of native tokens to burn.
function burn(address holder, bytes32 subID, uint256 amount) internal {
function burn(address holder, uint256 subID, uint256 amount) internal {
// ABI encode the input parameters.
bytes memory precompileData = abi.encodeCall(INativeTokens.burn, (holder, subID, amount));
bytes memory callData = abi.encodeCall(INativeTokens.burn, (holder, subID, amount));

// Call the precompile, ignoring the response since the VM will panic if there's an issue.
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(precompileData);
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(callData);
response;
}

/// @notice Mints `amount` tokens with sub-identifier `subID` to the provided `recipient`.
/// @dev Generates a Mint receipt.
///
/// Requirements:
/// - The caller of this function must be a contract.
/// - The `recipient`'s balance must not overflow.
///
/// @param recipient The address to mint native tokens to.
/// @param subID The sub-identifier of the native token to mint.
/// @param amount The quantity of native tokens to mint.
function mint(address recipient, bytes32 subID, uint256 amount) internal {
function mint(address recipient, uint256 subID, uint256 amount) internal {
// ABI encode the input parameters.
bytes memory precompileData = abi.encodeCall(INativeTokens.mint, (recipient, subID, amount));
bytes memory callData = abi.encodeCall(INativeTokens.mint, (recipient, subID, amount));

// Call the precompile, ignoring the response since the VM will panic if there's an issue.
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(precompileData);
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(callData);
response;
}

Expand All @@ -81,15 +83,15 @@ library NativeTokens {
/// @param to The address of the recipient.
/// @param tokenID The ID of the native token to transfer.
/// @param amount The quantity of native tokens to transfer.
function transfer(address to, bytes32 tokenID, uint256 amount) internal {
function transfer(address to, uint256 tokenID, uint256 amount) internal {
// The address in the calling contract.
address from = address(this);

// ABI encode the input parameters.
bytes memory precompileData = abi.encodeCall(INativeTokens.transfer, (from, to, tokenID, amount));
bytes memory callData = abi.encodeCall(INativeTokens.transfer, (from, to, tokenID, amount));

// Call the precompile, ignoring the response because the VM will panic if there's an issue.
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(precompileData);
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(callData);
response;
}

Expand All @@ -107,7 +109,7 @@ library NativeTokens {
/// @param data The call data to pass to the `callee`.
function transferAndCall(
address to,
bytes32 tokenID,
uint256 tokenID,
uint256 amount,
address callee,
bytes calldata data
Expand All @@ -118,11 +120,10 @@ library NativeTokens {
address from = address(this);

// ABI encode the input parameters.
bytes memory precompileData =
abi.encodeCall(INativeTokens.transferAndCall, (from, to, tokenID, amount, callee, data));
bytes memory callData = abi.encodeCall(INativeTokens.transferAndCall, (from, to, tokenID, amount, callee, data));

// Call the precompile, ignoring the response because the VM will panic if there's an issue.
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(precompileData);
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(callData);
response;
}

Expand All @@ -138,7 +139,7 @@ library NativeTokens {
/// @param amounts The quantities of native tokens to transfer.
function transferMultiple(
address[] calldata to,
bytes32[] calldata tokenIDs,
uint256[] calldata tokenIDs,
uint256[] calldata amounts
)
internal
Expand All @@ -147,14 +148,15 @@ library NativeTokens {
address from = address(this);

// ABI encode the input parameters.
bytes memory precompileData = abi.encodeCall(INativeTokens.transferMultiple, (from, to, tokenIDs, amounts));
bytes memory callData = abi.encodeCall(INativeTokens.transferMultiple, (from, to, tokenIDs, amounts));

// Call the precompile, ignoring the response because the VM will panic if there's an issue.
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(precompileData);
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(callData);
response;
}

/// @notice Performs multiple native token transfers from the calling contract to the recipients `to`, and calls the
/// @notice Performs multiple native token transfers from the calling contract to the recipients `to`, and calls
/// the
/// `callee` with the calldata `data`.
/// @dev Generates multiple Transfer receipts.
///
Expand All @@ -168,7 +170,7 @@ library NativeTokens {
/// @param data The call data to pass to the `callee`.
function transferMultipleAndCall(
address[] calldata to,
bytes32[] calldata tokenIDs,
uint256[] calldata tokenIDs,
uint256[] calldata amounts,
address callee,
bytes calldata data
Expand All @@ -179,11 +181,11 @@ library NativeTokens {
address from = address(this);

// ABI encode the input parameters.
bytes memory precompileData =
bytes memory callData =
abi.encodeCall(INativeTokens.transferMultipleAndCall, (from, to, tokenIDs, amounts, callee, data));

// Call the precompile, ignoring the response because the VM will panic if there's an issue.
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(precompileData);
(bool response,) = PRECOMPILE_NATIVE_TOKENS.delegatecall(callData);
response;
}
}
4 changes: 2 additions & 2 deletions src/standards/srf-20/SRF20Mock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { SRF20 } from "../../standards/srf-20/SRF20.sol";
contract SRF20Mock is SRF20 {
constructor(string memory name, string memory symbol) SRF20(name, symbol) { }

function burn(address holder, uint256 amount) external {
_burn(holder, amount);
function burn(uint256 amount) external {
_burn(msg.sender, amount);
}

function mint(address recipient, uint256 amount) external {
Expand Down
4 changes: 2 additions & 2 deletions test/Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ abstract contract Base_Test is Constants, Test {
return user;
}

/// @dev Derives the asset ID from the contract's address and the default sub ID.
function getAssetID(SRF20Mock tokenContract) internal view returns (uint256) {
/// @dev Derives the token ID from the contract's address and the default sub ID.
function getTokenID(SRF20Mock tokenContract) internal view returns (uint256) {
// Concatenate the contract's address and the default sub ID.
bytes memory concatenation = abi.encodePacked(address(tokenContract), defaults.SUB_ID());

Expand Down
3 changes: 2 additions & 1 deletion test/unit/concrete/srf-20/burn/burn.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ contract Burn_Unit_Concrete_Test is Base_Test {
function test_RevertWhen_TheHolderIsTheZeroAddress() external {
address holder = address(0);
vm.expectRevert(abi.encodeWithSelector(ISRF20.SRF20_InvalidHolder.selector, holder));
usdc.burn({ holder: holder, amount: 1 });
vm.prank(holder);
usdc.burn({ amount: 1 });
}

modifier whenHolderNotZeroAddress() {
Expand Down
2 changes: 1 addition & 1 deletion test/unit/concrete/srf-20/id.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Base_Test } from "../../../Base.t.sol";
contract ID_Unit_Concrete_Test is Base_Test {
function test_ID() external view {
uint256 actualID = usdc.ID();
uint256 expectedID = getAssetID(usdc);
uint256 expectedID = getTokenID(usdc);
assertEq(actualID, expectedID, "ID");
}
}
2 changes: 1 addition & 1 deletion test/utils/Defaults.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ contract Defaults is Constants {

uint256 public constant BURN_AMOUNT = 2500e18;
uint256 public constant MINT_AMOUNT = 10_000e18;
bytes32 public constant SUB_ID = bytes32(0);
uint256 public constant SUB_ID = 0;

ISRF20 private token;
Users private users;
Expand Down

0 comments on commit 249a174

Please sign in to comment.