-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a97ad78
commit 0138776
Showing
5 changed files
with
396 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.19; | ||
|
||
interface IPaymentCombinerFunctions { | ||
/** | ||
* Get the address of the PaymentSplitter implementation. | ||
* @return implementationAddr The address of the PaymentSplitter implementation. | ||
*/ | ||
function implementationAddress() external view returns (address implementationAddr); | ||
|
||
/** | ||
* Creates a PaymentSplitter proxy. | ||
* @param payees The addresses of the payees | ||
* @param shares The number of shares each payee has | ||
* @return proxyAddr The address of the deployed proxy | ||
*/ | ||
function deploy(address[] calldata payees, uint256[] calldata shares) external returns (address proxyAddr); | ||
|
||
/** | ||
* Computes the address of a proxy instance. | ||
* @param payees The addresses of the payees | ||
* @param shares The number of shares each payee has | ||
* @return proxyAddr The address of the proxy | ||
*/ | ||
function determineAddress(address[] calldata payees, uint256[] calldata shares) external returns (address proxyAddr); | ||
|
||
/** | ||
* Get the list of Payment Splitters this payee is associated with. | ||
* @param payee The address of the payee | ||
* @return splitterAddrs The list of payments splitters | ||
*/ | ||
function listPayeeSplitters(address payee) external view returns (address[] memory splitterAddrs); | ||
|
||
/** | ||
* Get the list of pending shares for a payee. | ||
* @param payee The address of the payee | ||
* @param tokenAddr The address of the ERC-20 token. If the token address is 0x0, then the native token is used. | ||
* @return splitterAddrs The list of payments splitters with pending shares | ||
* @return pendingShares The list of pending shares | ||
* @dev The list includes zero balances. These should be removed before releasing shares. | ||
*/ | ||
function listReleasable(address payee, address tokenAddr) | ||
external | ||
view | ||
returns (address[] memory splitterAddrs, uint256[] memory pendingShares); | ||
|
||
/** | ||
* Release the pending shares for a payee. | ||
* @param payee The address of the payee | ||
* @param tokenAddr The address of the ERC-20 token. If the token address is 0x0, then the native token is used. | ||
* @param splitterAddrs The list of payments splitters to release shares from | ||
* @dev Use the listReleasableSplitters function to get the list of splitters and pending shares | ||
*/ | ||
function release(address payable payee, address tokenAddr, address[] calldata splitterAddrs) external; | ||
} | ||
|
||
interface IPaymentCombinerSignals { | ||
/** | ||
* Event emitted when a new proxy contract is deployed. | ||
* @param proxyAddr The address of the deployed proxy. | ||
*/ | ||
event PaymentSplitterDeployed(address proxyAddr); | ||
} | ||
|
||
interface IPaymentCombiner is IPaymentCombinerFunctions, IPaymentCombinerSignals {} |
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,124 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.19; | ||
|
||
import {PaymentSplitter, IERC20Upgradeable} from "@0xsequence/contracts-library/payments/PaymentSplitter.sol"; | ||
import { | ||
IPaymentCombiner, IPaymentCombinerFunctions | ||
} from "@0xsequence/contracts-library/payments/IPaymentCombiner.sol"; | ||
import {IERC165} from "@0xsequence/erc-1155/contracts/interfaces/IERC165.sol"; | ||
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; | ||
|
||
/** | ||
* Deployer of Payment Splitter proxies. | ||
* @dev Unlike other factories in this library, payment splitters are unowned and not upgradeable. | ||
*/ | ||
contract PaymentCombiner is IPaymentCombiner, IERC165 { | ||
using Clones for address; | ||
|
||
address private immutable _IMPLEMENTATION; | ||
|
||
mapping(address => address[]) private _payeeSplitters; | ||
|
||
/** | ||
* Creates a Payment Splitter Factory. | ||
*/ | ||
constructor() { | ||
_IMPLEMENTATION = address(new PaymentSplitter()); | ||
} | ||
|
||
/// @inheritdoc IPaymentCombinerFunctions | ||
function implementationAddress() external view returns (address) { | ||
return _IMPLEMENTATION; | ||
} | ||
|
||
/// @inheritdoc IPaymentCombinerFunctions | ||
function deploy(address[] calldata payees, uint256[] calldata shares) external returns (address proxyAddr) { | ||
bytes32 salt = _determineSalt(payees, shares); | ||
proxyAddr = _IMPLEMENTATION.cloneDeterministic(salt); | ||
PaymentSplitter(payable(proxyAddr)).initialize(payees, shares); | ||
emit PaymentSplitterDeployed(proxyAddr); | ||
|
||
// Add the payees to the list of payee splitters | ||
for (uint256 i = 0; i < payees.length; i++) { | ||
_payeeSplitters[payees[i]].push(proxyAddr); | ||
} | ||
|
||
return proxyAddr; | ||
} | ||
|
||
/// @inheritdoc IPaymentCombinerFunctions | ||
function determineAddress(address[] calldata payees, uint256[] calldata shares) | ||
external | ||
view | ||
returns (address proxyAddr) | ||
{ | ||
bytes32 salt = _determineSalt(payees, shares); | ||
return _IMPLEMENTATION.predictDeterministicAddress(salt); | ||
} | ||
|
||
/// @dev Computes the deployment salt for a Payment Splitter. | ||
function _determineSalt(address[] calldata payees, uint256[] calldata shares) internal pure returns (bytes32) { | ||
return keccak256(abi.encode(payees, shares)); | ||
} | ||
|
||
/// @inheritdoc IPaymentCombinerFunctions | ||
function listPayeeSplitters(address payee) external view returns (address[] memory splitterAddrs) { | ||
return _payeeSplitters[payee]; | ||
} | ||
|
||
/// @inheritdoc IPaymentCombinerFunctions | ||
function listReleasable(address payee, address tokenAddr) | ||
external | ||
view | ||
returns (address[] memory splitterAddrs, uint256[] memory pendingShares) | ||
{ | ||
address[] memory payeeSplitters = _payeeSplitters[payee]; | ||
uint256 len = payeeSplitters.length; | ||
uint256[] memory payeePendingShares = new uint256[](len); | ||
|
||
if (tokenAddr == address(0)) { | ||
for (uint256 i = 0; i < len;) { | ||
payeePendingShares[i] = PaymentSplitter(payable(payeeSplitters[i])).releasable(payee); | ||
unchecked { | ||
i++; | ||
} | ||
} | ||
} else { | ||
for (uint256 i = 0; i < len;) { | ||
payeePendingShares[i] = | ||
PaymentSplitter(payable(payeeSplitters[i])).releasable(IERC20Upgradeable(tokenAddr), payee); | ||
unchecked { | ||
i++; | ||
} | ||
} | ||
} | ||
|
||
return (payeeSplitters, payeePendingShares); | ||
} | ||
|
||
/// @inheritdoc IPaymentCombinerFunctions | ||
function release(address payable payee, address tokenAddr, address[] calldata splitterAddrs) external { | ||
uint256 len = splitterAddrs.length; | ||
if (tokenAddr == address(0)) { | ||
for (uint256 i = 0; i < len;) { | ||
PaymentSplitter(payable(splitterAddrs[i])).release(payee); | ||
unchecked { | ||
i++; | ||
} | ||
} | ||
} else { | ||
for (uint256 i = 0; i < len;) { | ||
PaymentSplitter(payable(splitterAddrs[i])).release(IERC20Upgradeable(tokenAddr), payee); | ||
unchecked { | ||
i++; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// @inheritdoc IERC165 | ||
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { | ||
return type(IPaymentCombiner).interfaceId == interfaceId | ||
|| type(IPaymentCombinerFunctions).interfaceId == interfaceId || type(IERC165).interfaceId == interfaceId; | ||
} | ||
} |
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,19 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
pragma solidity ^0.8.19; | ||
|
||
import { | ||
PaymentSplitterUpgradeable, | ||
IERC20Upgradeable | ||
} from "@openzeppelin-upgradeable/contracts/finance/PaymentSplitterUpgradeable.sol"; | ||
|
||
contract PaymentSplitter is PaymentSplitterUpgradeable { | ||
/** | ||
* Initialize the PaymentSplitter contract. | ||
* @param payees The addresses of the payees | ||
* @param shares The number of shares each payee has | ||
* @dev This function should be called only once immediately after the contract is deployed. | ||
*/ | ||
function initialize(address[] memory payees, uint256[] memory shares) public initializer { | ||
__PaymentSplitter_init(payees, shares); | ||
} | ||
} |
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.