Skip to content

Commit

Permalink
v3.0.0 (#14)
Browse files Browse the repository at this point in the history
Version 3.0.0 has a few breaking changes:
- drops support for older solidity versions and only uses 0.8.20 and
above
- uses OpenZeppelin Contract v5.0.1
- uses ERC-7201 namespaced storage layout for upgradeable contracts
instead of gaps

In addition, there are some non-breaking changes:
- follows TL code standards
- moves custom errors into contracts instead of outside of the contracts
- better code documentation
  • Loading branch information
mpeyfuss authored Dec 26, 2023
2 parents c72ea81 + 40b6df9 commit 82dddb5
Show file tree
Hide file tree
Showing 37 changed files with 740 additions and 664 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
on: [push]

name: Test

jobs:
check:
name: Transient Labs Sol Tools
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Run unit tests
run: make compiler_test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ out/

# Dotenv file
.env

# Docs
docs/
13 changes: 6 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ clean:

# Remove the modules
remove:
rm -rf .gitmodules && rm -rf .git/modules/* && rm -rf lib
rm -rf .gitmodules && rm -rf .git/modules/* && rm -rf lib && touch .gitmodules

# Install the modules
install:
forge install foundry-rs/forge-std --no-commit
forge install OpenZeppelin/openzeppelin-contracts@v4.8.3 --no-commit
forge install OpenZeppelin/openzeppelin-contracts-upgradeable@v4.8.3 --no-commit
forge install OpenZeppelin/openzeppelin-contracts@v5.0.1 --no-commit
forge install OpenZeppelin/openzeppelin-contracts-upgradeable@v5.0.1 --no-commit
forge install manifoldxyz/royalty-registry-solidity --no-commit

# Updatee the modules
Expand All @@ -26,13 +26,12 @@ build:

# Tests
compiler_test:
forge test --use 0.8.17
forge test --use 0.8.18
forge test --use 0.8.19
forge test --use 0.8.20
forge test --use 0.8.21
forge test --use 0.8.22

quick_test:
forge test --fuzz-runs 512
forge test

gas_test:
forge test --gas-report
Expand Down
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ You should have no trouble inheriting from this library if you install with foun

When cloning, you must use either `make remove && make install` or `make update` to install/update the required modules, such as `forge-std` or OpenZeppelin contracts.

We use OpenZeppelin contracts version 4.8.3 in this codebase.
We use OpenZeppelin contracts version 5.0.1 in this codebase.

## Testing
You should run the test suite with `make test_suite`.
You should run the test suites in the Makefile.

This loops through the following solidity versions:
- 0.8.17
- 0.8.18
- 0.8.19
- 0.8.20
- 0.8.21
- 0.8.22

## Disclaimer
This codebase is provided on an "as is" and "as available" basis.
Expand Down
6 changes: 4 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ optimizer = true
optimizer_runs = 20000
verbosity = 3
wrap_comments = true
gas_reports = ["OwnableAccessControl", "EIP2981TL", "OwnableAccessControlUpgradeable", "EIP2981TLUpgradeable", "TransferHelper", "RoyaltyPayoutHelper", "RoyaltyPayoutHelperUpgradeable"]
fs_permissions = [{ access = "read", path = "./"}]
fs_permissions = [{ access = "read", path = "./"}]

[fuzz]
runs = 1024
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts-upgradeable
10 changes: 4 additions & 6 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
@manifoldxyz/libraries-solidity/=lib/royalty-registry-solidity/lib/libraries-solidity/
@openzeppelin/contracts-upgradeable/=lib/royalty-registry-solidity/lib/openzeppelin-contracts-upgradeable/contracts/
@openzeppelin/contracts/=lib/royalty-registry-solidity/lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
create2-helpers/=lib/royalty-registry-solidity/lib/create2-helpers/
create2-scripts/=lib/royalty-registry-solidity/lib/create2-helpers/script/
ds-test/=lib/forge-std/lib/ds-test/src/
erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/
forge-std/=lib/forge-std/src/
libraries-solidity/=lib/royalty-registry-solidity/lib/libraries-solidity/contracts/
openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/
openzeppelin-contracts/=lib/openzeppelin-contracts/
openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
openzeppelin/=lib/openzeppelin-contracts/contracts/
royalty-registry-solidity/=lib/royalty-registry-solidity/contracts
tl-sol-tools/=src/
royalty-registry-solidity/=lib/royalty-registry-solidity/contracts/
90 changes: 43 additions & 47 deletions src/access/OwnableAccessControl.sol
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.20;

import {EnumerableSet} from "openzeppelin/utils/structs/EnumerableSet.sol";
import {Ownable} from "openzeppelin/access/Ownable.sol";

/*//////////////////////////////////////////////////////////////////////////
Custom Errors
//////////////////////////////////////////////////////////////////////////*/

/// @dev does not have specified role
error NotSpecifiedRole(bytes32 role);

/// @dev is not specified role or owner
error NotRoleOrOwner(bytes32 role);

/*//////////////////////////////////////////////////////////////////////////
OwnableAccessControl
//////////////////////////////////////////////////////////////////////////*/
import {EnumerableSet} from "openzeppelin/utils/structs/EnumerableSet.sol";

/// @title OwnableAccessControl.sol
/// @notice single owner, flexible access control mechanics
/// @dev can easily be extended by inheriting and applying additional roles
/// @dev by default, only the owner can grant roles but by inheriting, but you
/// @notice Single owner, flexible access control mechanics
/// @dev Can easily be extended by inheriting and applying additional roles
/// @dev By default, only the owner can grant roles but by inheriting, but you
/// may allow other roles to grant roles by using the internal helper.
/// @author transientlabs.xyz
/// @custom:last-updated 2.2.2
/// @custom:version 3.0.0
abstract contract OwnableAccessControl is Ownable {
/*//////////////////////////////////////////////////////////////////////////
State Variables
Expand All @@ -37,20 +23,30 @@ abstract contract OwnableAccessControl is Ownable {
mapping(uint256 => mapping(bytes32 => EnumerableSet.AddressSet)) private _roleMembers;

/*//////////////////////////////////////////////////////////////////////////
Events
Events
//////////////////////////////////////////////////////////////////////////*/

/// @param from - address that authorized the role change
/// @param user - the address who's role has been changed
/// @param approved - boolean indicating the user's status in role
/// @param role - the bytes32 role created in the inheriting contract
/// @param from Address that authorized the role change
/// @param user The address who's role has been changed
/// @param approved Boolean indicating the user's status in role
/// @param role The bytes32 role created in the inheriting contract
event RoleChange(address indexed from, address indexed user, bool indexed approved, bytes32 role);

/// @param from - address that authorized the revoke
event AllRolesRevoked(address indexed from);

/*//////////////////////////////////////////////////////////////////////////
Modifiers
Errors
//////////////////////////////////////////////////////////////////////////*/

/// @dev Does not have specified role
error NotSpecifiedRole(bytes32 role);

/// @dev Is not specified role or owner
error NotRoleOrOwner(bytes32 role);

/*//////////////////////////////////////////////////////////////////////////
Modifiers
//////////////////////////////////////////////////////////////////////////*/

modifier onlyRole(bytes32 role) {
Expand All @@ -71,34 +67,34 @@ abstract contract OwnableAccessControl is Ownable {
Constructor
//////////////////////////////////////////////////////////////////////////*/

constructor() Ownable() {}
constructor() Ownable(msg.sender) {}

/*//////////////////////////////////////////////////////////////////////////
External Role Functions
External Role Functions
//////////////////////////////////////////////////////////////////////////*/

/// @notice function to revoke all roles currently present
/// @dev increments the `_c` variables
/// @dev requires owner privileges
/// @notice Function to revoke all roles currently present
/// @dev Increments the `_c` variables
/// @dev Requires owner privileges
function revokeAllRoles() external onlyOwner {
_c++;
emit AllRolesRevoked(msg.sender);
}

/// @notice function to renounce role
/// @param role - bytes32 role created in inheriting contracts
/// @notice Function to renounce role
/// @param role Bytes32 role created in inheriting contracts
function renounceRole(bytes32 role) external {
address[] memory members = new address[](1);
members[0] = msg.sender;
_setRole(role, members, false);
}

/// @notice function to grant/revoke a role to an address
/// @dev requires owner to call this function but this may be further
/// @notice Function to grant/revoke a role to an address
/// @dev Requires owner to call this function but this may be further
/// extended using the internal helper function in inheriting contracts
/// @param role - bytes32 role created in inheriting contracts
/// @param roleMembers - list of addresses that should have roles attached to them based on `status`
/// @param status - bool whether to remove or add `roleMembers` to the `role`
/// @param role Bytes32 role created in inheriting contracts
/// @param roleMembers List of addresses that should have roles attached to them based on `status`
/// @param status Bool whether to remove or add `roleMembers` to the `role`
function setRole(bytes32 role, address[] memory roleMembers, bool status) external onlyOwner {
_setRole(role, roleMembers, status);
}
Expand All @@ -107,15 +103,15 @@ abstract contract OwnableAccessControl is Ownable {
External View Functions
//////////////////////////////////////////////////////////////////////////*/

/// @notice function to see if an address is the owner
/// @param role - bytes32 role created in inheriting contracts
/// @param potentialRoleMember - address to check for role membership
/// @notice Function to see if an address is the owner
/// @param role Bytes32 role created in inheriting contracts
/// @param potentialRoleMember Address to check for role membership
function hasRole(bytes32 role, address potentialRoleMember) public view returns (bool) {
return _roleStatus[_c][role][potentialRoleMember];
}

/// @notice function to get role members
/// @param role - bytes32 role created in inheriting contracts
/// @notice Function to get role members
/// @param role Bytes32 role created in inheriting contracts
function getRoleMembers(bytes32 role) public view returns (address[] memory) {
return _roleMembers[_c][role].values();
}
Expand All @@ -124,10 +120,10 @@ abstract contract OwnableAccessControl is Ownable {
Internal Helper Functions
//////////////////////////////////////////////////////////////////////////*/

/// @notice helper function to set addresses for a role
/// @param role - bytes32 role created in inheriting contracts
/// @param roleMembers - list of addresses that should have roles attached to them based on `status`
/// @param status - bool whether to remove or add `roleMembers` to the `role`
/// @notice Helper function to set addresses for a role
/// @param role Bytes32 role created in inheriting contracts
/// @param roleMembers List of addresses that should have roles attached to them based on `status`
/// @param status Bool whether to remove or add `roleMembers` to the `role`
function _setRole(bytes32 role, address[] memory roleMembers, bool status) internal {
for (uint256 i = 0; i < roleMembers.length; i++) {
_roleStatus[_c][role][roleMembers[i]] = status;
Expand Down
6 changes: 6 additions & 0 deletions src/payments/IChainalysisSanctionsOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IChainalysisSanctionsOracle {
function isSanctioned(address addr) external view returns (bool);
}
2 changes: 1 addition & 1 deletion src/payments/IWETH.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.20;

import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol";

Expand Down
18 changes: 8 additions & 10 deletions src/payments/RoyaltyPayoutHelper.sol
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.20;

import {TransferHelper} from "./TransferHelper.sol";
import {SanctionsCompliance} from "./SanctionsCompliance.sol";
import {IRoyaltyEngineV1} from "royalty-registry-solidity/IRoyaltyEngineV1.sol";

/*//////////////////////////////////////////////////////////////////////////
Royalty Payout Helper
//////////////////////////////////////////////////////////////////////////*/
import {SanctionsCompliance} from "src/payments/SanctionsCompliance.sol";
import {TransferHelper} from "src/payments/TransferHelper.sol";

/// @title Royalty Payout Helper
/// @notice Abstract contract to help payout royalties using the Royalty Registry
/// @dev Does not manage updating the sanctions oracle and expects the child contract to implement
/// @author transientlabs.xyz
/// @custom:last-updated 2.5.0
/// @custom:last-updated 3.0.0
abstract contract RoyaltyPayoutHelper is TransferHelper, SanctionsCompliance {
/*//////////////////////////////////////////////////////////////////////////
State Variables
Expand All @@ -29,7 +25,9 @@ abstract contract RoyaltyPayoutHelper is TransferHelper, SanctionsCompliance {
/// @param sanctionsOracle - the init sanctions oracle
/// @param wethAddress - the init weth address
/// @param royaltyEngineAddress - the init royalty engine address
constructor(address sanctionsOracle, address wethAddress, address royaltyEngineAddress) SanctionsCompliance(sanctionsOracle) {
constructor(address sanctionsOracle, address wethAddress, address royaltyEngineAddress)
SanctionsCompliance(sanctionsOracle)
{
weth = wethAddress;
royaltyEngine = IRoyaltyEngineV1(royaltyEngineAddress);
}
Expand Down Expand Up @@ -59,7 +57,7 @@ abstract contract RoyaltyPayoutHelper is TransferHelper, SanctionsCompliance {
/// @notice Function to payout royalties from the contract balance based on sale price
/// @dev if the call to the royalty engine reverts or if the return values are invalid, no payments are made
/// @dev if the sum of the royalty payouts is greater than the salePrice, the loop exits early for gas savings (this shouldn't happen in reality)
/// @dev if this is used in a call where tokens should be transferred from a sender, it is advisable to
/// @dev if this is used in a call where tokens should be transferred from a sender, it is advisable to
/// first transfer the required amount to the contract and then call this function, as it will save on gas
/// @param token The contract address for the token
/// @param tokenId The token id
Expand Down
Loading

0 comments on commit 82dddb5

Please sign in to comment.