Skip to content

Instantly share code, notes, and snippets.

@cliffhall
Last active March 9, 2022 06:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cliffhall/94aec29237b3045295eb204e25189176 to your computer and use it in GitHub Desktop.
Save cliffhall/94aec29237b3045295eb204e25189176 to your computer and use it in GitHub Desktop.
A factory/registry for deploying cheap, minimal clones of royalty funds handler logic and retrieving those clones by token address and id
pragma solidity 0.8.4;
import "@openzeppelin/contracts/proxy/Clones.sol";
import "./IFundsHandler.sol"; // Multiple funds receiver/splitter logic implementations can exist
contract FundsHandlerRegistry {
// Available IFundsHandler implementations
mapping(string => address) handlers;
// For any token address, all tokens can have their own minimal proxy to an IFundsHandler implementation
mapping(address => mapping(uint256 => address)) proxies;
// When a new IFundsHandler implementation is added to the registry
event FundsHandlerAdded (string name, address handler);
// When an IFundsHandler implementation is cloned with a minimal proxy
event FundsHandlerCloned (
address proxy,
address tokenAddress,
uint256 tokenId,
string handlerName,
address[] recipients,
uint256[] shares
);
function addHandler(string memory _name, address _handler) public
{
// Store the handler address by name
handlers[_name] = _handler;
// Emit event
emit HandlerAdded(_name, _handler);
}
// Clones a funds handler implementation as a minimal proxy,
// associating the specific NFT with the proxy, and initializing
// it with the given arrays of recipients and shares
function cloneFundsHandler (
address tokenAddress,
uint256 _tokenId,
string memory _handlerName,
address[] calldata _recipients,
uint256[] calldata _shares
)
public
payable
returns (address proxy)
{
// Get the specified funds handler
address handler = handlers[_handlerName];
// Clone funds handler as Minimal Proxy
proxy = Clones.clone(handler);
// Initialize proxy
IFundsHandler(proxy).init(_recipients, _shares);
// Verify that it was initialized properly
require(IFundsHandler(proxy).totalRecipients() == _recipients.length);
// Store address of proxy by token address and id
proxies[_tokenAddress][_tokenId] = proxy;
// Emit event
emit FundsHandlerCloned(proxy, _tokenAddress, _tokenId, _handlerName, _recipients, _shares);
}
function getRoyaltyFundsHandler (
address _tokenAddress,
uint256 _tokenId
)
public
view
returns (address receiver)
{
receiver = proxies[_tokenAddress][_tokenId];
require(receiver != address(0));
}
}
pragma solidity 0.8.4;
interface IFundsHandler {
function init(address[] calldata _recipients, uint256[] calldata _shares) external;
function totalRecipients() external view returns (uint256);
function recipientShareAtIndex(uint256 index) external view returns (address _recipient, uint256 _share);
}
@chrishol
Copy link

Hey @cliffhall - do you have a version of this deployed anywhere that could be used by others (i.e. me)?

We have several different NFT collabs and I am trying to cheaply create several iterations of a standard PaymentSplitter without deploying a full new copy every time which seems to be exactly what you are doing here.

@cliffhall
Copy link
Author

HI @chrishol I do not have one deployed, but I wouldn't be averse to working with you to get something going. This notional one is loosely based on a tech spike I did for KnownOrigin, not their eventual production code.

DM me on the Twitters if you like and we can chat about it a little further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment