Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.0.0 #14

Merged
merged 8 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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