-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added payment helpers. `TransferHelpers` - an abstract contract that safely transfers ETH and ERC-20 tokens `RoyaltyPayoutHelper` - an abstract contract that uses the royalty registry to get royalty recipients for a token sale and payout the royalties safely
- Loading branch information
Showing
29 changed files
with
1,099 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,12 @@ | ||
[profile.default] | ||
src = 'src' # the source directory | ||
test = 'test' # the test directory | ||
out = 'out' # the output directory (for artifacts) | ||
libs = ['lib'] # a list of library directories | ||
libraries = [] # a list of deployed libraries to link against | ||
cache = true # whether to cache builds or not | ||
force = false # whether to ignore the cache (clean build) | ||
evm_version = 'london' # the evm version (by hardfork name) | ||
#solc_version = '0.8.17' # override for the solc version (setting this ignores `auto_detect_solc`) | ||
auto_detect_solc = true # enable auto-detection of the appropriate solc version to use | ||
offline = false # disable downloading of missing solc version(s) | ||
optimizer = true # enable or disable the solc optimizer | ||
optimizer_runs = 2000 # the number of optimizer runs | ||
verbosity = 3 # the verbosity of tests | ||
ffi = false # whether to enable ffi or not | ||
gas_reports = ["*"] | ||
fs_permissions = [{ access = 'read', path = './test/file_utils'}] | ||
|
||
[fuzz] | ||
runs = 10000 | ||
src = 'src' | ||
test = 'test' | ||
out = 'out' | ||
libs = ['lib'] | ||
auto_detect_solc = true | ||
optimizer = true | ||
optimizer_runs = 20000 | ||
verbosity = 3 | ||
wrap_comments = true | ||
gas_reports = ["OwnableAccessControl", "EIP2981TL", "OwnableAccessControlUpgradeable", "EIP2981TLUpgradeable", "TransferHelper", "RoyaltyPayoutHelper", "RoyaltyPayoutHelperUpgradeable"] | ||
fs_permissions = [{ access = "read", path = "./"}] |
Submodule forge-std
updated
16 files
+48 −6 | .github/workflows/ci.yml | |
+1 −1 | package.json | |
+3 −2 | src/Script.sol | |
+0 −2 | src/StdChains.sol | |
+144 −15 | src/StdCheats.sol | |
+1 −1 | src/StdInvariant.sol | |
+4 −0 | src/StdStorage.sol | |
+2 −2 | src/StdStyle.sol | |
+1 −1 | src/StdUtils.sol | |
+4 −2 | src/Test.sol | |
+13 −1 | src/Vm.sol | |
+71 −16 | test/StdChains.t.sol | |
+124 −29 | test/StdCheats.t.sol | |
+17 −2 | test/StdMath.t.sol | |
+10 −0 | test/StdStorage.t.sol | |
+38 −8 | test/StdUtils.t.sol |
Submodule royalty-registry-solidity
added at
e5369f
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,14 @@ | ||
forge-std/=lib/forge-std/src | ||
@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/ | ||
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/ | ||
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/ | ||
openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/ | ||
royalty-registry-solidity/=lib/royalty-registry-solidity/contracts | ||
tl-sol-tools/=src/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
import {IERC20} from "openzeppelin/token/ERC20/IERC20.sol"; | ||
|
||
interface IWETH is IERC20 { | ||
function deposit() external payable; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
import {TransferHelper} from "./TransferHelper.sol"; | ||
import {IRoyaltyEngineV1} from "royalty-registry-solidity/IRoyaltyEngineV1.sol"; | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
Royalty Payout Helper | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @title Royalty Payout Helper | ||
/// @notice Abstract contract to help payout royalties using the Royalty Registry | ||
/// @author transientlabs.xyz | ||
/// @custom:last-updated 2.3.0 | ||
abstract contract RoyaltyPayoutHelper is TransferHelper { | ||
/*////////////////////////////////////////////////////////////////////////// | ||
State Variables | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
address public weth; | ||
IRoyaltyEngineV1 public royaltyEngine; | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
Constructor | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @param wethAddress - the init weth address | ||
/// @param royaltyEngineAddress - the init royalty engine address | ||
constructor(address wethAddress, address royaltyEngineAddress) { | ||
weth = wethAddress; | ||
royaltyEngine = IRoyaltyEngineV1(royaltyEngineAddress); | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
Internal State Functions | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @notice Function to update the WETH address | ||
/// @dev Care should be taken to ensure proper access control for this function | ||
/// @param wethAddress The new WETH token address | ||
function _setWethAddress(address wethAddress) internal { | ||
weth = wethAddress; | ||
} | ||
|
||
/// @notice Function to update the royalty engine address | ||
/// @dev Care should be taken to ensure proper access control for this function | ||
/// @param royaltyEngineAddress The new royalty engine address | ||
function _setRoyaltyEngineAddress(address royaltyEngineAddress) internal { | ||
royaltyEngine = IRoyaltyEngineV1(royaltyEngineAddress); | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
Royalty Payout Function | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @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 | ||
/// 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 | ||
/// @param currency The address of the currency to send to recipients (null address == ETH) | ||
/// @param salePrice The sale price for the token | ||
/// @return remainingSale The amount left over in the sale after paying out royalties | ||
function _payoutRoyalties(address token, uint256 tokenId, address currency, uint256 salePrice) | ||
internal | ||
returns (uint256 remainingSale) | ||
{ | ||
remainingSale = salePrice; | ||
try royaltyEngine.getRoyalty(token, tokenId, salePrice) returns ( | ||
address payable[] memory recipients, uint256[] memory amounts | ||
) { | ||
if (recipients.length != amounts.length) return remainingSale; | ||
|
||
for (uint256 i = 0; i < recipients.length; i++) { | ||
if (amounts[i] > remainingSale) break; | ||
remainingSale -= amounts[i]; | ||
if (currency == address(0)) { | ||
_safeTransferETH(recipients[i], amounts[i], weth); | ||
} else { | ||
_safeTransferERC20(recipients[i], currency, amounts[i]); | ||
} | ||
} | ||
|
||
return remainingSale; | ||
} catch { | ||
return remainingSale; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.17; | ||
|
||
import {SafeERC20} from "openzeppelin/token/ERC20/utils/SafeERC20.sol"; | ||
import {IWETH, IERC20} from "./IWETH.sol"; | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
Custom Errors | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @dev ETH transfer failed | ||
error ETHTransferFailed(); | ||
|
||
/// @dev Transferred too few ERC-20 tokens | ||
error InsufficentERC20Transfer(); | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
Transfer Helper | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @title Transfer Helper | ||
/// @notice Abstract contract that has helper function for sending ETH and ERC20's safely | ||
/// @author transientlabs.xyz | ||
/// @custom:last-updated 2.3.0 | ||
abstract contract TransferHelper { | ||
/*////////////////////////////////////////////////////////////////////////// | ||
State Variables | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
using SafeERC20 for IERC20; | ||
using SafeERC20 for IWETH; | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
ETH Functions | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @notice Function to force transfer ETH | ||
/// @dev On failure to send the ETH, the ETH is converted to WETH and sent | ||
/// @dev Care should be taken to always pass the proper WETH address that adheres to IWETH | ||
/// @param recipient The recipient of the ETH | ||
/// @param amount The amount of ETH to send | ||
/// @param weth The WETH token address | ||
function _safeTransferETH(address recipient, uint256 amount, address weth) internal { | ||
(bool success,) = recipient.call{value: amount}(""); | ||
if (!success) { | ||
IWETH token = IWETH(weth); | ||
token.deposit{value: amount}(); | ||
token.safeTransfer(recipient, amount); | ||
} | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
ERC-20 Functions | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @notice Function to safely transfer ERC-20 tokens from the contract, without checking for token tax | ||
/// @dev Does not check if the sender has enough balance as that is handled by the token contract | ||
/// @dev Does not check for token tax as that could lock up funds in the contract | ||
/// @dev Reverts on failure to transfer | ||
/// @param recipient The recipient of the ERC-20 token | ||
/// @param currency The address of the ERC-20 token | ||
/// @param amount The amount of ERC-20 to send | ||
function _safeTransferERC20(address recipient, address currency, uint256 amount) internal { | ||
IERC20(currency).safeTransfer(recipient, amount); | ||
} | ||
|
||
/// @notice Function to safely transfer ERC-20 tokens from another address to a recipient | ||
/// @dev Does not check if the sender has enough balance or allowance for this contract as that is handled by the token contract | ||
/// @dev Reverts on failure to transfer | ||
/// @dev Reverts if there is a token tax taken out | ||
/// @param sender The sender of the tokens | ||
/// @param recipient The recipient of the ERC-20 token | ||
/// @param currency The address of the ERC-20 token | ||
/// @param amount The amount of ERC-20 to send | ||
function _safeTransferFromERC20(address sender, address recipient, address currency, uint256 amount) internal { | ||
IERC20 token = IERC20(currency); | ||
uint256 intialBalance = token.balanceOf(recipient); | ||
token.safeTransferFrom(sender, recipient, amount); | ||
uint256 finalBalance = token.balanceOf(recipient); | ||
if (finalBalance - intialBalance < amount) revert InsufficentERC20Transfer(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.