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

Blank rasa contracts #1

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
branch = v4.8.3
11 changes: 11 additions & 0 deletions contracts/csr/ITurnstile.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// turnstile address: 0xEcf044C5B4b867CFda001101c617eCd347095B44
// turnstile ID: 22

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.10;

interface ITurnstile {
function assign(uint256) external returns (uint256);

function register(address) external returns (uint256);
}
42 changes: 42 additions & 0 deletions contracts/manifold/IRoyaltyEngineV1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @author: manifold.xyz

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
* @dev Lookup engine interface
*/
interface IRoyaltyEngineV1 is IERC165 {
/**
* Get the royalty for a given token (address, id) and value amount. Does not cache the bps/amounts. Caches the spec for a given token address
*
* @param tokenAddress - The address of the token
* @param tokenId - The id of the token
* @param value - The value you wish to get the royalty of
*
* returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get
*/
function getRoyalty(
address tokenAddress,
uint256 tokenId,
uint256 value
) external returns (address payable[] memory recipients, uint256[] memory amounts);

/**
* View only version of getRoyalty
*
* @param tokenAddress - The address of the token
* @param tokenId - The id of the token
* @param value - The value you wish to get the royalty of
*
* returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get
*/
function getRoyaltyView(
address tokenAddress,
uint256 tokenId,
uint256 value
) external view returns (address payable[] memory recipients, uint256[] memory amounts);
}
37 changes: 37 additions & 0 deletions contracts/manifold/IRoyaltyRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @author: manifold.xyz

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
* @dev Royalty registry interface
*/
interface IRoyaltyRegistry is IERC165 {
event RoyaltyOverride(address owner, address tokenAddress, address royaltyAddress);

/**
* Override the location of where to look up royalty information for a given token contract.
* Allows for backwards compatibility and implementation of royalty logic for contracts that did not previously support them.
*
* @param tokenAddress - The token address you wish to override
* @param royaltyAddress - The royalty override address
*/
function setRoyaltyLookupAddress(address tokenAddress, address royaltyAddress) external;

/**
* Returns royalty address location. Returns the tokenAddress by default, or the override if it exists
*
* @param tokenAddress - The token address you are looking up the royalty for
*/
function getRoyaltyLookupAddress(address tokenAddress) external view returns (address);

/**
* Whether or not the message sender can override the royalty address for the given token address
*
* @param tokenAddress - The token address you are looking up the royalty for
*/
function overrideAllowed(address tokenAddress) external view returns (bool);
}
201 changes: 201 additions & 0 deletions contracts/manifold/RoyaltyEngineV1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/// @author: manifold.xyz

import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

import "./libraries/SuperRareContracts.sol";

import "./specs/IManifold.sol";
import "./specs/IRarible.sol";
import "./specs/IFoundation.sol";
import "./specs/ISuperRare.sol";
import "./specs/IEIP2981.sol";
import "./specs/IZoraOverride.sol";
import "./specs/IArtBlocksOverride.sol";
import "./IRoyaltyEngineV1.sol";
import "./IRoyaltyRegistry.sol";

/**
* @dev Engine to lookup royalty configurations
*/
contract RoyaltyEngineV1 is ERC165, OwnableUpgradeable, IRoyaltyEngineV1 {
using AddressUpgradeable for address;

// Use int16 for specs to support future spec additions
// When we add a spec, we also decrement the NONE value
// Anything > NONE and <= NOT_CONFIGURED is considered not configured
int16 private constant NONE = -1;
int16 private constant NOT_CONFIGURED = 0;
int16 private constant EIP2981 = 1;
int16 private constant ZORA = 2;

mapping(address => int16) _specCache;

address public royaltyRegistry;

function initialize(address royaltyRegistry_) public initializer {
__Ownable_init_unchained();
require(ERC165Checker.supportsInterface(royaltyRegistry_, type(IRoyaltyRegistry).interfaceId));
royaltyRegistry = royaltyRegistry_;
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IRoyaltyEngineV1).interfaceId || super.supportsInterface(interfaceId);
}

/**
* @dev Invalidate the cached spec (useful for situations where tooken royalty implementation changes to a different spec)
*/
function invalidateCachedRoyaltySpec(address tokenAddress) public {
address royaltyAddress = IRoyaltyRegistry(royaltyRegistry).getRoyaltyLookupAddress(tokenAddress);
delete _specCache[royaltyAddress];
}

/**
* @dev View function to get the cached spec of a token
*/
function getCachedRoyaltySpec(address tokenAddress) public view returns (int16) {
address royaltyAddress = IRoyaltyRegistry(royaltyRegistry).getRoyaltyLookupAddress(tokenAddress);
return _specCache[royaltyAddress];
}

/**
* @dev See {IRoyaltyEngineV1-getRoyalty}
*/
function getRoyalty(
address tokenAddress,
uint256 tokenId,
uint256 value
) public override returns (address payable[] memory recipients, uint256[] memory amounts) {
// External call to limit gas
try this._getRoyaltyAndSpec{gas: 50000}(tokenAddress, tokenId, value) returns (
address payable[] memory _recipients,
uint256[] memory _amounts,
int16 spec,
address royaltyAddress,
bool addToCache
) {
if (addToCache) _specCache[royaltyAddress] = spec;
return (_recipients, _amounts);
} catch {
revert("Invalid royalty amount");
}
}

/**
* @dev See {IRoyaltyEngineV1-getRoyaltyView}.
*/
function getRoyaltyView(
address tokenAddress,
uint256 tokenId,
uint256 value
) public view override returns (address payable[] memory recipients, uint256[] memory amounts) {
// External call to limit gas
try this._getRoyaltyAndSpec{gas: 100000}(tokenAddress, tokenId, value) returns (
address payable[] memory _recipients,
uint256[] memory _amounts,
int16,
address,
bool
) {
return (_recipients, _amounts);
} catch {
revert("Invalid royalty amount");
}
}

/**
* @dev Get the royalty and royalty spec for a given token
*
* returns recipieints array, amounts array, royalty spec, royalty address, whether or not to add to cache
*/
function _getRoyaltyAndSpec(
address tokenAddress,
uint256 tokenId,
uint256 value
)
external
view
returns (
address payable[] memory recipients,
uint256[] memory amounts,
int16 spec,
address royaltyAddress,
bool addToCache
)
{
require(msg.sender == address(this), "Only Engine");

royaltyAddress = IRoyaltyRegistry(royaltyRegistry).getRoyaltyLookupAddress(tokenAddress);
spec = _specCache[royaltyAddress];

if (spec <= NOT_CONFIGURED && spec > NONE) {
// No spec configured yet, so we need to detect the spec
addToCache = true;

try IEIP2981(royaltyAddress).royaltyInfo(tokenId, value) returns (address recipient, uint256 amount) {
// Supports EIP2981. Return amounts
require(amount < value, "Invalid royalty amount");
recipients = new address payable[](1);
amounts = new uint256[](1);
recipients[0] = payable(recipient);
amounts[0] = amount;
return (recipients, amounts, EIP2981, royaltyAddress, addToCache);
} catch {}
try IZoraOverride(royaltyAddress).convertBidShares(tokenAddress, tokenId) returns (
address payable[] memory recipients_,
uint256[] memory bps
) {
// Support Zora override
require(recipients_.length == bps.length);
return (recipients_, _computeAmounts(value, bps), ZORA, royaltyAddress, addToCache);
} catch {}
// No supported royalties configured
return (recipients, amounts, NONE, royaltyAddress, addToCache);
} else {
// Spec exists, just execute the appropriate one
addToCache = false;
if (spec == NONE) {
return (recipients, amounts, spec, royaltyAddress, addToCache);
} else if (spec == EIP2981) {
// EIP2981 spec
(address recipient, uint256 amount) = IEIP2981(royaltyAddress).royaltyInfo(tokenId, value);
require(amount < value, "Invalid royalty amount");
recipients = new address payable[](1);
amounts = new uint256[](1);
recipients[0] = payable(recipient);
amounts[0] = amount;
return (recipients, amounts, spec, royaltyAddress, addToCache);
} else if (spec == ZORA) {
// Zora spec
uint256[] memory bps;
(recipients, bps) = IZoraOverride(royaltyAddress).convertBidShares(tokenAddress, tokenId);
require(recipients.length == bps.length);
return (recipients, _computeAmounts(value, bps), spec, royaltyAddress, addToCache);
}
}
}

/**
* Compute royalty amounts
*/
function _computeAmounts(uint256 value, uint256[] memory bps) private pure returns (uint256[] memory amounts) {
amounts = new uint256[](bps.length);
uint256 totalAmount;
for (uint256 i = 0; i < bps.length; i++) {
amounts[i] = (value * bps[i]) / 10000;
totalAmount += amounts[i];
}
require(totalAmount < value, "Invalid royalty amount");
return amounts;
}
}
Loading