Feature Tip: Add private address tag to any address under My Name Tag !
ERC-1155
Overview
Max Total Supply
0
Holders
134
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Minimal Proxy Contract for 0x65af690c8233af8fdb639de2f0e400de1c9cf978
Contract Name:
Rae
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.13; /// @title ClonesWithImmutableArgs /// @author wighawag, zefram.eth /// @notice Enables creating clone contracts with immutable args library ClonesWithImmutableArgs { error CreateFail(); /// @notice Creates a clone proxy of the implementation contract, with immutable args /// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length /// @param implementation The implementation contract to clone /// @param data Encoded immutable args /// @return instance The address of the created clone function clone(address implementation, bytes memory data) internal returns (address payable instance) { // unrealistic for memory ptr or data length to exceed 256 bits unchecked { uint256 extraLength = data.length + 2; // +2 bytes for telling how much data there is appended to the call uint256 creationSize = 0x41 + extraLength; uint256 runSize = creationSize - 10; uint256 dataPtr; uint256 ptr; // solhint-disable-next-line no-inline-assembly assembly { ptr := mload(0x40) // ------------------------------------------------------------------------------------------------------------- // CREATION (10 bytes) // ------------------------------------------------------------------------------------------------------------- // 61 runtime | PUSH2 runtime (r) | r | – mstore( ptr, 0x6100000000000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x01), shl(240, runSize)) // size of the contract running bytecode (16 bits) // creation size = 0a // 3d | RETURNDATASIZE | 0 r | – // 81 | DUP2 | r 0 r | – // 60 creation | PUSH1 creation (c) | c r 0 r | – // 3d | RETURNDATASIZE | 0 c r 0 r | – // 39 | CODECOPY | 0 r | [0-runSize): runtime code // f3 | RETURN | | [0-runSize): runtime code // ------------------------------------------------------------------------------------------------------------- // RUNTIME (55 bytes + extraLength) // ------------------------------------------------------------------------------------------------------------- // 3d | RETURNDATASIZE | 0 | – // 3d | RETURNDATASIZE | 0 0 | – // 3d | RETURNDATASIZE | 0 0 0 | – // 3d | RETURNDATASIZE | 0 0 0 0 | – // 36 | CALLDATASIZE | cds 0 0 0 0 | – // 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | – // 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | – // 37 | CALLDATACOPY | 0 0 0 0 | [0, cds) = calldata // 61 | PUSH2 extra | extra 0 0 0 0 | [0, cds) = calldata mstore( add(ptr, 0x03), 0x3d81600a3d39f33d3d3d3d363d3d376100000000000000000000000000000000 ) mstore(add(ptr, 0x13), shl(240, extraLength)) // 60 0x37 | PUSH1 0x37 | 0x37 extra 0 0 0 0 | [0, cds) = calldata // 0x37 (55) is runtime size - data // 36 | CALLDATASIZE | cds 0x37 extra 0 0 0 0 | [0, cds) = calldata // 39 | CODECOPY | 0 0 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // 36 | CALLDATASIZE | cds 0 0 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // 61 extra | PUSH2 extra | extra cds 0 0 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData mstore( add(ptr, 0x15), 0x6037363936610000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x1b), shl(240, extraLength)) // 01 | ADD | cds+extra 0 0 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // 73 addr | PUSH20 0x123… | addr 0 cds 0 0 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData mstore( add(ptr, 0x1d), 0x013d730000000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x20), shl(0x60, implementation)) // 5a | GAS | gas addr 0 cds 0 0 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // f4 | DELEGATECALL | success 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // 3d | RETURNDATASIZE | rds success 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // 3d | RETURNDATASIZE | rds rds success 0 0 | [0, cds) = calldata, [cds, cds+0x37) = extraData // 93 | SWAP4 | 0 rds success 0 rds | [0, cds) = calldata, [cds, cds+0x37) = extraData // 80 | DUP1 | 0 0 rds success 0 rds | [0, cds) = calldata, [cds, cds+0x37) = extraData // 3e | RETURNDATACOPY | success 0 rds | [0, rds) = return data (there might be some irrelevant leftovers in memory [rds, cds+0x37) when rds < cds+0x37) // 60 0x35 | PUSH1 0x35 | 0x35 sucess 0 rds | [0, rds) = return data // 57 | JUMPI | 0 rds | [0, rds) = return data // fd | REVERT | – | [0, rds) = return data // 5b | JUMPDEST | 0 rds | [0, rds) = return data // f3 | RETURN | – | [0, rds) = return data mstore( add(ptr, 0x34), 0x5af43d3d93803e603557fd5bf300000000000000000000000000000000000000 ) } // ------------------------------------------------------------------------------------------------------------- // APPENDED DATA (Accessible from extcodecopy) // (but also send as appended data to the delegatecall) // ------------------------------------------------------------------------------------------------------------- extraLength -= 2; uint256 counter = extraLength; uint256 copyPtr = ptr + 0x41; // solhint-disable-next-line no-inline-assembly assembly { dataPtr := add(data, 32) } for (; counter >= 32; counter -= 32) { // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, mload(dataPtr)) } copyPtr += 32; dataPtr += 32; } uint256 mask = ~(256**(32 - counter) - 1); // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, and(mload(dataPtr), mask)) } copyPtr += counter; // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, shl(240, extraLength)) } // solhint-disable-next-line no-inline-assembly assembly { instance := create(0, ptr, creationSize) } if (instance == address(0)) { revert CreateFail(); } } } } /// @title Clone /// @author zefram.eth /// @notice Provides helper functions for reading immutable args from calldata contract Clone { /// @notice Reads an immutable arg with type address /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgAddress(uint256 argOffset) internal pure returns (address arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0x60, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint256 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint256(uint256 argOffset) internal pure returns (uint256 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := calldataload(add(offset, argOffset)) } } /// @notice Reads an immutable arg with type bytes32 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgBytes32(uint256 argOffset) internal pure returns (bytes32 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := calldataload(add(offset, argOffset)) } } /// @notice Reads a uint256 array stored in the immutable args. /// @param argOffset The offset of the arg in the packed data /// @param arrLen Number of elements in the array /// @return arr The array function _getArgUint256Array(uint256 argOffset, uint64 arrLen) internal pure returns (uint256[] memory arr) { uint256 offset = _getImmutableArgsOffset(); uint256 el; arr = new uint256[](arrLen); for (uint64 i = 0; i < arrLen; i++) { assembly { // solhint-disable-next-line no-inline-assembly el := calldataload(add(add(offset, argOffset), mul(i, 32))) } arr[i] = el; } return arr; } /// @notice Reads a uint256 array stored in the immutable args. /// @param argOffset The offset of the arg in the packed data /// @param arrLen Number of elements in the array /// @return arr The array function _getArgBytes32Array(uint256 argOffset, uint64 arrLen) internal pure returns (bytes32[] memory arr) { uint256 offset = _getImmutableArgsOffset(); bytes32 el; arr = new bytes32[](arrLen); for (uint64 i = 0; i < arrLen; i++) { assembly { // solhint-disable-next-line no-inline-assembly el := calldataload(add(add(offset, argOffset), mul(i, 32))) } arr[i] = el; } return arr; } /// @notice Reads an immutable arg with type uint64 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint64(uint256 argOffset) internal pure returns (uint64 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0xc0, calldataload(add(offset, argOffset))) } } /// @notice Reads an immutable arg with type uint8 /// @param argOffset The offset of the arg in the packed data /// @return arg The arg value function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) { uint256 offset = _getImmutableArgsOffset(); // solhint-disable-next-line no-inline-assembly assembly { arg := shr(0xf8, calldataload(add(offset, argOffset))) } } /// @return offset The offset of the packed immutable args in calldata function _getImmutableArgsOffset() internal pure returns (uint256 offset) { // solhint-disable-next-line no-inline-assembly assembly { offset := sub( calldatasize(), add(shr(240, calldataload(sub(calldatasize(), 2))), 2) ) } } } // OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol) // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) // OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol) /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } } /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } } /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } } /// @notice Minimalist and gas efficient standard ERC1155 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) abstract contract ERC1155 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event TransferSingle( address indexed operator, address indexed from, address indexed to, uint256 id, uint256 amount ); event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] amounts ); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); event URI(string value, uint256 indexed id); /*////////////////////////////////////////////////////////////// ERC1155 STORAGE //////////////////////////////////////////////////////////////*/ mapping(address => mapping(uint256 => uint256)) public balanceOf; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// METADATA LOGIC //////////////////////////////////////////////////////////////*/ function uri(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC1155 LOGIC //////////////////////////////////////////////////////////////*/ function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) public virtual { require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); balanceOf[from][id] -= amount; balanceOf[to][id] += amount; emit TransferSingle(msg.sender, from, to, id, amount); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) == ERC1155TokenReceiver.onERC1155Received.selector, "UNSAFE_RECIPIENT" ); } function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) public virtual { require(ids.length == amounts.length, "LENGTH_MISMATCH"); require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); // Storing these outside the loop saves ~15 gas per iteration. uint256 id; uint256 amount; for (uint256 i = 0; i < ids.length; ) { id = ids[i]; amount = amounts[i]; balanceOf[from][id] -= amount; balanceOf[to][id] += amount; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, from, to, ids, amounts); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) == ERC1155TokenReceiver.onERC1155BatchReceived.selector, "UNSAFE_RECIPIENT" ); } function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) public view virtual returns (uint256[] memory balances) { require(owners.length == ids.length, "LENGTH_MISMATCH"); balances = new uint256[](owners.length); // Unchecked because the only math done is incrementing // the array index counter which cannot possibly overflow. unchecked { for (uint256 i = 0; i < owners.length; ++i) { balances[i] = balanceOf[owners[i]][ids[i]]; } } } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155 interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint( address to, uint256 id, uint256 amount, bytes memory data ) internal virtual { balanceOf[to][id] += amount; emit TransferSingle(msg.sender, address(0), to, id, amount); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) == ERC1155TokenReceiver.onERC1155Received.selector, "UNSAFE_RECIPIENT" ); } function _batchMint( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { uint256 idsLength = ids.length; // Saves MLOADs. require(idsLength == amounts.length, "LENGTH_MISMATCH"); for (uint256 i = 0; i < idsLength; ) { balanceOf[to][ids[i]] += amounts[i]; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, address(0), to, ids, amounts); require( to.code.length == 0 ? to != address(0) : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) == ERC1155TokenReceiver.onERC1155BatchReceived.selector, "UNSAFE_RECIPIENT" ); } function _batchBurn( address from, uint256[] memory ids, uint256[] memory amounts ) internal virtual { uint256 idsLength = ids.length; // Saves MLOADs. require(idsLength == amounts.length, "LENGTH_MISMATCH"); for (uint256 i = 0; i < idsLength; ) { balanceOf[from][ids[i]] -= amounts[i]; // An array can't have a total length // larger than the max uint256 value. unchecked { ++i; } } emit TransferBatch(msg.sender, from, address(0), ids, amounts); } function _burn( address from, uint256 id, uint256 amount ) internal virtual { balanceOf[from][id] -= amount; emit TransferSingle(msg.sender, from, address(0), id, amount); } } /// @notice A generic interface for a contract which properly accepts ERC1155 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) abstract contract ERC1155TokenReceiver { function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC1155TokenReceiver.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external virtual returns (bytes4) { return ERC1155TokenReceiver.onERC1155BatchReceived.selector; } } /// @dev Name of the Rae token contract string constant NAME = "Rae"; /// @dev Version number of the Rae token contract string constant VERSION = "1"; /// @dev The EIP-712 typehash for the contract's domain bytes32 constant DOMAIN_TYPEHASH = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); /// @dev The EIP-712 typehash for the permit struct used by the contract bytes32 constant PERMIT_TYPEHASH = keccak256( "Permit(address owner,address operator,uint256 tokenId,bool approved,uint256 nonce,uint256 deadline)" ); /// @dev The EIP-712 typehash for the permit all struct used by the contract bytes32 constant PERMIT_ALL_TYPEHASH = keccak256( "PermitAll(address owner,address operator,bool approved,uint256 nonce,uint256 deadline)" ); /// @title PermitBase /// @author Tessera /// @notice Utility contract for computing permit signature approvals for Rae tokens abstract contract PermitBase { /// @notice Mapping of token owner to nonce value mapping(address => uint256) public nonces; /// @dev Computes hash of permit struct /// @param _owner Address of the owner of the token type /// @param _operator Address of the spender of the token type /// @param _id ID of the token type /// @param _approved Approval status for the token type /// @param _deadline Expiration of the signature function _computePermitStructHash( address _owner, address _operator, uint256 _id, bool _approved, uint256 _deadline ) internal returns (bytes32) { return keccak256( abi.encode( PERMIT_TYPEHASH, _owner, _operator, _id, _approved, nonces[_owner]++, _deadline ) ); } /// @dev Computes hash of permit all struct /// @param _owner Address of the owner of the token type /// @param _operator Address of the spender of the token type /// @param _approved Approval status for the token type /// @param _deadline Expiration of the signature function _computePermitAllStructHash( address _owner, address _operator, bool _approved, uint256 _deadline ) internal returns (bytes32) { return keccak256( abi.encode( PERMIT_ALL_TYPEHASH, _owner, _operator, _approved, nonces[_owner]++, _deadline ) ); } /// @dev Computes domain separator to prevent signature collisions /// @return Hash of the contract-specific fields function _computeDomainSeparator() internal view returns (bytes32) { return keccak256( abi.encode( DOMAIN_TYPEHASH, keccak256(bytes(NAME)), keccak256(bytes(VERSION)), block.chainid, address(this) ) ); } /// @dev Computes digest of domain separator and struct hash /// @param _domainSeparator Hash of contract-specific fields /// @param _structHash Hash of signature fields struct /// @return Hash of the signature digest function _computeDigest(bytes32 _domainSeparator, bytes32 _structHash) internal pure returns (bytes32) { return keccak256(abi.encode("\x19\x01", _domainSeparator, _structHash)); } } /// @dev Interface of ERC-1155 token contract for raes interface IRae { /// @dev Emitted when caller is not required address error InvalidSender(address _required, address _provided); /// @dev Emitted when owner signature is invalid error InvalidSignature(address _signer, address _owner); /// @dev Emitted when deadline for signature has passed error SignatureExpired(uint256 _timestamp, uint256 _deadline); /// @dev Emitted when royalty is set to value greater than 100% error InvalidRoyalty(uint256 _percentage); /// @dev Emitted when new controller is zero address error ZeroAddress(); /// @dev Event log for updating the Controller of the token contract /// @param _newController Address of the controller event ControllerTransferred(address indexed _newController); /// @dev Event log for updating the metadata contract for a token type /// @param _metadata Address of the metadata contract that URI data is stored on /// @param _id ID of the token type event SetMetadata(address indexed _metadata, uint256 _id); /// @dev Event log for updating the royalty of a token type /// @param _receiver Address of the receiver of secondary sale royalties /// @param _id ID of the token type /// @param _percentage Royalty percent on secondary sales event SetRoyalty(address indexed _receiver, uint256 indexed _id, uint256 _percentage); /// @dev Event log for approving a spender of a token type /// @param _owner Address of the owner of the token type /// @param _operator Address of the spender of the token type /// @param _id ID of the token type /// @param _approved Approval status for the token type event SingleApproval( address indexed _owner, address indexed _operator, uint256 indexed _id, bool _approved ); /// @notice Event log for Minting Raes of ID to account _to /// @param _to Address to mint rae tokens to /// @param _id Token ID to mint /// @param _amount Number of tokens to mint event MintRaes(address indexed _to, uint256 indexed _id, uint256 _amount); /// @notice Event log for Burning raes of ID from account _from /// @param _from Address to burn rae tokens from /// @param _id Token ID to burn /// @param _amount Number of tokens to burn event BurnRaes(address indexed _from, uint256 indexed _id, uint256 _amount); function INITIAL_CONTROLLER() external pure returns (address); function VAULT_REGISTRY() external pure returns (address); function burn( address _from, uint256 _id, uint256 _amount ) external; function contractURI() external view returns (string memory); function controller() external view returns (address controllerAddress); function isApproved( address, address, uint256 ) external view returns (bool); function metadataDelegate() external view returns (address); function mint( address _to, uint256 _id, uint256 _amount, bytes memory _data ) external; function permit( address _owner, address _operator, uint256 _id, bool _approved, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external; function permitAll( address _owner, address _operator, bool _approved, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external; function royaltyInfo(uint256 _id, uint256 _salePrice) external view returns (address receiver, uint256 royaltyAmount); function safeTransferFrom( address _from, address _to, uint256 _id, uint256 _amount, bytes memory _data ) external; function setApprovalFor( address _operator, uint256 _id, bool _approved ) external; function setMetadataDelegate(address _metadata) external; function setRoyalties( uint256 _id, address _receiver, uint256 _percentage ) external; function totalSupply(uint256) external view returns (uint256); function transferController(address _newController) external; function uri(uint256 _id) external view returns (string memory); } /// @dev Interface for NFT Receiver contract interface INFTReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external returns (bytes4); function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external returns (bytes4); function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external returns (bytes4); } interface IMetadataDelegate { function tokenURI(uint256 tokenId) external view returns (string memory); function contractURI() external view returns (string memory); } /// @title Rae /// @author Tessera /// @notice An ERC-1155 implementation for Raes contract Rae is Clone, ERC1155, IRae, PermitBase { /// @notice Address of interface identifier for royalty standard bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a; /// @notice Address that can deploy new vaults and manage metadata for this collection address internal _controller; /// @notice contract address for the metadata delegate address public metadataDelegate; /// @notice Mapping of token owner to token operator to token ID type to approval status mapping(address => mapping(address => mapping(uint256 => bool))) public isApproved; /// @notice Mapping of token ID type to total supply of tokens mapping(uint256 => uint256) public totalSupply; /// @notice Mapping of token ID type to royalty beneficiary mapping(uint256 => address) private royaltyAddress; /// @notice Mapping of token ID type to royalty percentage mapping(uint256 => uint256) private royaltyPercent; /// @notice Modifier for restricting function calls to the controller account modifier onlyController() { address controller_ = controller(); if (msg.sender != controller_) revert InvalidSender(controller_, msg.sender); _; } /// @notice Modifier for restricting function calls to the VaultRegistry modifier onlyRegistry() { address vaultRegistry = VAULT_REGISTRY(); if (msg.sender != vaultRegistry) revert InvalidSender(vaultRegistry, msg.sender); _; } /// @notice Burns raes for an ID /// @param _from Address to burn rae tokens from /// @param _id Token ID to burn /// @param _amount Number of tokens to burn function burn( address _from, uint256 _id, uint256 _amount ) external onlyRegistry { totalSupply[_id] -= _amount; _burn(_from, _id, _amount); emit BurnRaes(_from, _id, _amount); } /// @notice Mints new raes for an ID /// @param _to Address to mint rae tokens to /// @param _id Token ID to mint /// @param _amount Number of tokens to mint /// @param _data Extra calldata to include in the mint function mint( address _to, uint256 _id, uint256 _amount, bytes memory _data ) external onlyRegistry { totalSupply[_id] += _amount; emit MintRaes(_to, _id, _amount); _mint(_to, _id, _amount, _data); } /// @notice Permit function that approves an operator for token type with a valid signature /// @param _owner Address of the owner of the token type /// @param _operator Address of the spender of the token type /// @param _id ID of the token type /// @param _approved Approval status for the token type /// @param _deadline Expiration of the signature /// @param _v The recovery ID (129th byte and chain ID) of the signature used to recover the signer /// @param _r The first 64 bytes of the signature /// @param _s Bytes 64-128 of the signature function permit( address _owner, address _operator, uint256 _id, bool _approved, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external { if (block.timestamp > _deadline) revert SignatureExpired(block.timestamp, _deadline); // cannot realistically overflow on human timescales unchecked { bytes32 structHash = _computePermitStructHash( _owner, _operator, _id, _approved, _deadline ); bytes32 digest = _computeDigest(_computeDomainSeparator(), structHash); address signer = ECDSA.recover(digest, _v, _r, _s); if (signer == address(0) || signer != _owner) revert InvalidSignature(signer, _owner); } isApproved[_owner][_operator][_id] = _approved; emit SingleApproval(_owner, _operator, _id, _approved); } /// @notice Permit function that approves an operator for all token types with a valid signature /// @param _owner Address of the owner of the token type /// @param _operator Address of the spender of the token type /// @param _approved Approval status for the token type /// @param _deadline Expiration of the signature /// @param _v The recovery ID (129th byte and chain ID) of the signature used to recover the signer /// @param _r The first 64 bytes of the signature /// @param _s Bytes 64-128 of the signature function permitAll( address _owner, address _operator, bool _approved, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external { if (block.timestamp > _deadline) revert SignatureExpired(block.timestamp, _deadline); // cannot realistically overflow on human timescales unchecked { bytes32 structHash = _computePermitAllStructHash( _owner, _operator, _approved, _deadline ); bytes32 digest = _computeDigest(_computeDomainSeparator(), structHash); address signer = ECDSA.recover(digest, _v, _r, _s); if (signer == address(0) || signer != _owner) revert InvalidSignature(signer, _owner); } isApprovedForAll[_owner][_operator] = _approved; emit ApprovalForAll(_owner, _operator, _approved); } /// @notice Scoped approvals allow us to eliminate some of the risks associated with setting the approval for an entire collection /// @param _operator Address of spender account /// @param _id ID of the token type /// @param _approved Approval status for operator(spender) account function setApprovalFor( address _operator, uint256 _id, bool _approved ) external { isApproved[msg.sender][_operator][_id] = _approved; emit SingleApproval(msg.sender, _operator, _id, _approved); } /// @notice Sets the token metadata contract /// @param _metadata Address for metadata contract function setMetadataDelegate(address _metadata) external onlyController { metadataDelegate = _metadata; } /// @notice Sets the token royalties /// @param _id Token ID royalties are being updated for /// @param _receiver Address to receive royalties /// @param _percentage Percentage of royalties on secondary sales (2 decimals of precision) function setRoyalties( uint256 _id, address _receiver, uint256 _percentage ) external onlyController { if (_percentage > 10000) revert InvalidRoyalty(_percentage); royaltyAddress[_id] = _receiver; royaltyPercent[_id] = _percentage; emit SetRoyalty(_receiver, _id, _percentage); } /// @notice Updates the controller address for the Rae token contract /// @param _newController Address of new controlling entity function transferController(address _newController) external onlyController { if (_newController == address(0)) revert ZeroAddress(); _controller = _newController; emit ControllerTransferred(_newController); } function contractURI() external view returns (string memory) { return IMetadataDelegate(metadataDelegate).contractURI(); } /// @notice Sets the token royalties /// @param _id Token ID royalties are being updated for /// @param _salePrice Sale price to calculate the royalty for function royaltyInfo(uint256 _id, uint256 _salePrice) external view returns (address receiver, uint256 royaltyAmount) { receiver = royaltyAddress[_id]; royaltyAmount = (_salePrice * royaltyPercent[_id]) / 10000; } /// @notice ERC165 implementation /// @param interfaceId ERC165 Interface ID function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return interfaceId == _INTERFACE_ID_ERC2981 || super.supportsInterface(interfaceId); // ERC165 Interface ID for ERC2981 } /// @notice Transfer an amount of a token type between two accounts /// @param _from Source address for an amount of tokens /// @param _to Destination address for an amount of tokens /// @param _id ID of the token type /// @param _amount The amount of tokens being transferred /// @param _data Additional calldata function safeTransferFrom( address _from, address _to, uint256 _id, uint256 _amount, bytes memory _data ) public override(ERC1155, IRae) { require( msg.sender == _from || isApprovedForAll[_from][msg.sender] || isApproved[_from][msg.sender][_id], "NOT_AUTHORIZED" ); balanceOf[_from][_id] -= _amount; balanceOf[_to][_id] += _amount; emit TransferSingle(msg.sender, _from, _to, _id, _amount); require( _to.code.length == 0 ? _to != address(0) : INFTReceiver(_to).onERC1155Received(msg.sender, _from, _id, _amount, _data) == INFTReceiver.onERC1155Received.selector, "UNSAFE_RECIPIENT" ); } /// @notice Getter for URI of a token type /// @param _id ID of the token type function uri(uint256 _id) public view override(ERC1155, IRae) returns (string memory) { return IMetadataDelegate(metadataDelegate).tokenURI(_id); } /// @notice Getter for controller account function controller() public view returns (address controllerAddress) { _controller == address(0) ? controllerAddress = INITIAL_CONTROLLER() : controllerAddress = _controller; } /// @notice Getter for initial controller account immutable argument stored in calldata function INITIAL_CONTROLLER() public pure returns (address) { return _getArgAddress(0); } /// @notice VaultRegistry address that is allowed to call mint() and burn() function VAULT_REGISTRY() public pure returns (address) { return _getArgAddress(20); } } /// @dev Initialization call information struct InitInfo { // Address of target contract address target; // Initialization data bytes data; // Merkle proof for call bytes32[] proof; } /// @dev Interface for Vault proxy contract interface IVault { /// @dev Emitted when execution reverted with no reason error ExecutionReverted(); /// @dev Emitted when the caller is not the owner error NotAuthorized(address _caller, address _target, bytes4 _selector); /// @dev Emitted when the caller is not the owner error NotOwner(address _owner, address _caller); /// @dev Emitted when the caller is not the factory error NotFactory(address _factory, address _caller); /// @dev Emitted when passing an EOA or an undeployed contract as the target error TargetInvalid(address _target); /// @dev Event log for executing transactions /// @param _target Address of target contract /// @param _data Transaction data being executed /// @param _response Return data of delegatecall event Execute(address indexed _target, bytes _data, bytes _response); function execute( address _target, bytes memory _data, bytes32[] memory _proof ) external payable returns (bool success, bytes memory response); function MERKLE_ROOT() external view returns (bytes32); function OWNER() external view returns (address); function FACTORY() external view returns (address); } /// @dev Vault permissions struct Permission { // Address of module contract address module; // Address of target contract address target; // Function selector from target contract bytes4 selector; } /// @dev Vault information struct VaultInfo { // Address of Rae token contract address token; // ID of the token type uint256 id; } /// @dev Interface for VaultRegistry contract interface IVaultRegistry { /// @dev Emitted when the caller is not the controller error InvalidController(address _controller, address _sender); /// @dev Emitted when the caller is not a registered vault error UnregisteredVault(address _sender); /// @dev Event log for deploying vault /// @param _vault Address of the vault /// @param _token Address of the token /// @param _id Id of the token event VaultDeployed(address indexed _vault, address indexed _token, uint256 indexed _id); function createFor( bytes32 _merkleRoot, address _owner, InitInfo[] calldata _calls ) external returns (address vault); function createFor(bytes32 _merkleRoot, address _owner) external returns (address vault); function create(bytes32 _merkleRoot, InitInfo[] calldata _calls) external returns (address vault); function create(bytes32 _merkleRoot) external returns (address vault); function createCollectionFor( bytes32 _merkleRoot, address _controller, InitInfo[] calldata _calls ) external returns (address vault, address token); function createCollection(bytes32 _merkleRoot, InitInfo[] calldata _calls) external returns (address vault, address token); function createInCollection( bytes32 _merkleRoot, address _token, InitInfo[] calldata _calls ) external returns (address vault); function factory() external view returns (address); function rae() external view returns (address); function raeImplementation() external view returns (address); function burn(address _from, uint256 _value) external; function mint(address _to, uint256 _value) external; function nextId(address) external view returns (uint256); function totalSupply(address _vault) external view returns (uint256); function uri(address _vault) external view returns (string memory); function vaultToToken(address) external view returns (address token, uint256 id); } /// @title ClonesWithImmutableArgs /// @author wighawag, zefram.eth /// @notice Enables creating clone contracts with immutable args library Create2ClonesWithImmutableArgs { error CreateFail(); function cloneCreationCode(address implementation, bytes memory data) internal pure returns (uint256 ptr, uint256 creationSize) { // unchecked is safe because it is unrealistic for memory ptr or data length to exceed 256 bits unchecked { uint256 extraLength = data.length + 2; // +2 bytes for telling how much data there is appended to the call creationSize = 0x43 + extraLength; uint256 runSize = creationSize - 11; uint256 dataPtr; // solhint-disable-next-line no-inline-assembly assembly { ptr := mload(0x40) // ------------------------------------------------------------------------------------------------------------- // CREATION (11 bytes) // ------------------------------------------------------------------------------------------------------------- // 3d | RETURNDATASIZE | 0 | – // 61 runtime | PUSH2 runtime (r) | r 0 | – mstore( ptr, 0x3d61000000000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x02), shl(240, runSize)) // size of the contract running bytecode (16 bits) // creation size = 0b // 80 | DUP1 | r r 0 | – // 60 creation | PUSH1 creation (c) | c r r 0 | – // 3d | RETURNDATASIZE | 0 c r r 0 | – // 39 | CODECOPY | r 0 | [0-2d]: runtime code // 81 | DUP2 | 0 c 0 | [0-2d]: runtime code // f3 | RETURN | 0 | [0-2d]: runtime code mstore( add(ptr, 0x04), 0x80600b3d3981f300000000000000000000000000000000000000000000000000 ) // ------------------------------------------------------------------------------------------------------------- // RUNTIME // ------------------------------------------------------------------------------------------------------------- // 36 | CALLDATASIZE | cds | – // 3d | RETURNDATASIZE | 0 cds | – // 3d | RETURNDATASIZE | 0 0 cds | – // 37 | CALLDATACOPY | – | [0, cds] = calldata // 61 | PUSH2 extra | extra | [0, cds] = calldata mstore( add(ptr, 0x0b), 0x363d3d3761000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x10), shl(240, extraLength)) // 60 0x38 | PUSH1 0x38 | 0x38 extra | [0, cds] = calldata // 0x38 (56) is runtime size - data // 36 | CALLDATASIZE | cds 0x38 extra | [0, cds] = calldata // 39 | CODECOPY | _ | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 0 0 | [0, cds] = calldata // 36 | CALLDATASIZE | cds 0 0 0 | [0, cds] = calldata // 61 extra | PUSH2 extra | extra cds 0 0 0 | [0, cds] = calldata mstore( add(ptr, 0x12), 0x603836393d3d3d36610000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x1b), shl(240, extraLength)) // 01 | ADD | cds+extra 0 0 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | 0 cds 0 0 0 | [0, cds] = calldata // 73 addr | PUSH20 0x123… | addr 0 cds 0 0 0 | [0, cds] = calldata mstore( add(ptr, 0x1d), 0x013d730000000000000000000000000000000000000000000000000000000000 ) mstore(add(ptr, 0x20), shl(0x60, implementation)) // 5a | GAS | gas addr 0 cds 0 0 0 | [0, cds] = calldata // f4 | DELEGATECALL | success 0 | [0, cds] = calldata // 3d | RETURNDATASIZE | rds success 0 | [0, cds] = calldata // 82 | DUP3 | 0 rds success 0 | [0, cds] = calldata // 80 | DUP1 | 0 0 rds success 0 | [0, cds] = calldata // 3e | RETURNDATACOPY | success 0 | [0, rds] = return data (there might be some irrelevant leftovers in memory [rds, cds] when rds < cds) // 90 | SWAP1 | 0 success | [0, rds] = return data // 3d | RETURNDATASIZE | rds 0 success | [0, rds] = return data // 91 | SWAP2 | success 0 rds | [0, rds] = return data // 60 0x36 | PUSH1 0x36 | 0x36 sucess 0 rds | [0, rds] = return data // 57 | JUMPI | 0 rds | [0, rds] = return data // fd | REVERT | – | [0, rds] = return data // 5b | JUMPDEST | 0 rds | [0, rds] = return data // f3 | RETURN | – | [0, rds] = return data mstore( add(ptr, 0x34), 0x5af43d82803e903d91603657fd5bf30000000000000000000000000000000000 ) } // ------------------------------------------------------------------------------------------------------------- // APPENDED DATA (Accessible from extcodecopy) // (but also send as appended data to the delegatecall) // ------------------------------------------------------------------------------------------------------------- extraLength -= 2; uint256 counter = extraLength; uint256 copyPtr; assembly { copyPtr := add(ptr, 0x43) } // solhint-disable-next-line no-inline-assembly assembly { dataPtr := add(data, 32) } for (; counter >= 32; counter -= 32) { // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, mload(dataPtr)) } copyPtr += 32; dataPtr += 32; } uint256 mask = ~(256**(32 - counter) - 1); // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, and(mload(dataPtr), mask)) } copyPtr += counter; // solhint-disable-next-line no-inline-assembly assembly { mstore(copyPtr, shl(240, extraLength)) } } } /// @notice Creates a clone proxy of the implementation contract, with immutable args /// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length /// @param implementation The implementation contract to clone /// @param data Encoded immutable args /// @return instance The address of the created clone function clone( address implementation, bytes32 salt, bytes memory data ) internal returns (address payable instance) { (uint256 creationPtr, uint256 creationSize) = cloneCreationCode( implementation, data ); // solhint-disable-next-line no-inline-assembly assembly { instance := create2(0, creationPtr, creationSize, salt) } // if the create failed, the instance address won't be set if (instance == address(0)) { revert CreateFail(); } } } /// @dev Interface for VaultFactory contract interface IVaultFactory { /// @dev Event log for deploying vault /// @param _origin Address of transaction origin /// @param _deployer Address of sender /// @param _owner Address of vault owner /// @param _seed Value of seed /// @param _salt Value of salt /// @param _vault Address of deployed vault event DeployVault( address indexed _origin, address indexed _deployer, address indexed _owner, bytes32 _seed, bytes32 _salt, address _vault, bytes32 _root ); function deploy(bytes32 _merkleRoot) external returns (address payable vault); function deployFor(bytes32 _merkleRoot, address _owner) external returns (address payable vault); function getNextAddress( address _origin, address _owner, bytes32 _merkleRoot ) external view returns (address vault); function getNextSeed(address _deployer) external view returns (bytes32); function implementation() external view returns (address); } // OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol) /** * @dev These functions deal with verification of Merkle Tree proofs. * * The proofs can be generated using the JavaScript library * https://github.com/miguelmota/merkletreejs[merkletreejs]. * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. * * See `test/utils/cryptography/MerkleProof.test.js` for some examples. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } } /// @notice Modern, minimalist, and gas efficient ERC-721 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 indexed id); event Approval(address indexed owner, address indexed spender, uint256 indexed id); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /*////////////////////////////////////////////////////////////// METADATA STORAGE/LOGIC //////////////////////////////////////////////////////////////*/ string public name; string public symbol; function tokenURI(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) internal _ownerOf; mapping(address => uint256) internal _balanceOf; function ownerOf(uint256 id) public view virtual returns (address owner) { require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); } function balanceOf(address owner) public view virtual returns (uint256) { require(owner != address(0), "ZERO_ADDRESS"); return _balanceOf[owner]; } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) public getApproved; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 id) public virtual { address owner = _ownerOf[id]; require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); getApproved[id] = spender; emit Approval(owner, spender, id); } function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function transferFrom( address from, address to, uint256 id ) public virtual { require(from == _ownerOf[id], "WRONG_FROM"); require(to != address(0), "INVALID_RECIPIENT"); require( msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], "NOT_AUTHORIZED" ); // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. unchecked { _balanceOf[from]--; _balanceOf[to]++; } _ownerOf[id] = to; delete getApproved[id]; emit Transfer(from, to, id); } function safeTransferFrom( address from, address to, uint256 id ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function safeTransferFrom( address from, address to, uint256 id, bytes calldata data ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 id) internal virtual { require(to != address(0), "INVALID_RECIPIENT"); require(_ownerOf[id] == address(0), "ALREADY_MINTED"); // Counter overflow is incredibly unrealistic. unchecked { _balanceOf[to]++; } _ownerOf[id] = to; emit Transfer(address(0), to, id); } function _burn(uint256 id) internal virtual { address owner = _ownerOf[id]; require(owner != address(0), "NOT_MINTED"); // Ownership check above ensures no underflow. unchecked { _balanceOf[owner]--; } delete _ownerOf[id]; delete getApproved[id]; emit Transfer(owner, address(0), id); } /*////////////////////////////////////////////////////////////// INTERNAL SAFE MINT LOGIC //////////////////////////////////////////////////////////////*/ function _safeMint(address to, uint256 id) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function _safeMint( address to, uint256 id, bytes memory data ) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } } /// @notice A generic interface for a contract which properly accepts ERC721 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } } /// @title NFT Receiver /// @author Tessera /// @notice Plugin contract for handling receipts of non-fungible tokens contract NFTReceiver is ERC721TokenReceiver, ERC1155TokenReceiver { /// @notice Handles the receipt of a single ERC721 token function onERC721Received( address, address, uint256, bytes calldata ) external virtual override returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } /// @notice Handles the receipt of a single ERC1155 token type function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external virtual override returns (bytes4) { return ERC1155TokenReceiver.onERC1155Received.selector; } /// @notice Handles the receipt of multiple ERC1155 token types function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external virtual override returns (bytes4) { return ERC1155TokenReceiver.onERC1155BatchReceived.selector; } } /// @title Vault /// @author Tessera /// @notice Proxy contract for storing Assets contract Vault is Clone, IVault, NFTReceiver { address public immutable original; /// @dev Minimum reserve of gas units uint256 private constant MIN_GAS_RESERVE = 5_000; uint256 private constant MERKLE_ROOT_POSITION = 0; uint256 private constant OWNER_POSITION = 32; uint256 private constant FACTORY_POSITION = 52; constructor() { original = address(this); } /// @dev Callback for receiving Ether when the calldata is empty receive() external payable {} /// @dev Executed if none of the other functions match the function identifier fallback() external payable {} /// @notice Executes vault transactions through delegatecall /// @param _target Target address /// @param _data Transaction data /// @param _proof Merkle proof of permission hash /// @return success Result status of delegatecall /// @return response Return data of delegatecall function execute( address _target, bytes calldata _data, bytes32[] calldata _proof ) external payable returns (bool success, bytes memory response) { bytes4 selector; assembly { selector := calldataload(_data.offset) } // Generate leaf node by hashing module, target and function selector. bytes32 leaf = keccak256(abi.encode(msg.sender, _target, selector)); // Check that the caller is either a module with permission to call or the owner. if (!MerkleProof.verify(_proof, MERKLE_ROOT(), leaf)) { if (msg.sender != FACTORY() && msg.sender != OWNER()) revert NotAuthorized(msg.sender, _target, selector); } (success, response) = _execute(_target, _data); } /// @notice Getter for merkle root stored as an immutable argument function MERKLE_ROOT() public pure returns (bytes32) { return _getArgBytes32(MERKLE_ROOT_POSITION); } /// @notice Getter for owner of vault function OWNER() public pure returns (address) { return _getArgAddress(OWNER_POSITION); } /// @notice Getter for factory of vault function FACTORY() public pure returns (address) { return _getArgAddress(FACTORY_POSITION); } /// @notice Executes plugin transactions through delegatecall /// @param _target Target address /// @param _data Transaction data /// @return success Result status of delegatecall /// @return response Return data of delegatecall function _execute(address _target, bytes calldata _data) internal returns (bool success, bytes memory response) { require(original != address(this), "only delegate call"); if (_target.code.length == 0) revert TargetInvalid(_target); // Reserve some gas to ensure that the function has enough to finish the execution uint256 stipend = gasleft() - MIN_GAS_RESERVE; // Delegate call to the target contract (success, response) = _target.delegatecall{gas: stipend}(_data); // Revert if execution was unsuccessful if (!success) { if (response.length == 0) revert ExecutionReverted(); _revertedWithReason(response); } } /// @notice Reverts transaction with reason /// @param _response Unsucessful return response of the delegate call function _revertedWithReason(bytes memory _response) internal pure { assembly { let returndata_size := mload(_response) revert(add(32, _response), returndata_size) } } } /// @title Vault Factory /// @author Tessera /// @notice Factory contract for deploying Tessera vaults contract VaultFactory is IVaultFactory { /// @dev Use clones library for address types using Create2ClonesWithImmutableArgs for address; /// @notice Address of Vault proxy contract address public implementation; /// @dev Internal mapping to track the next seed to be used by an EOA mapping(address => bytes32) internal nextSeeds; /// @notice Initializes implementation contract constructor() { implementation = address(new Vault()); } /// @notice Deploys new vault for sender /// @param _merkleRoot Merkle root of deployed vault /// @return vault Address of deployed vault function deploy(bytes32 _merkleRoot) external returns (address payable vault) { vault = deployFor(_merkleRoot, msg.sender); } /// @notice Gets pre-computed address of vault deployed by given account /// @param _origin Address of vault originating account /// @param _owner Address of vault deployer /// @param _merkleRoot Merkle root of deployed vault /// @return vault Address of next vault function getNextAddress( address _origin, address _owner, bytes32 _merkleRoot ) external view returns (address vault) { bytes32 salt = keccak256(abi.encode(_origin, nextSeeds[_origin])); (uint256 creationPtr, uint256 creationSize) = implementation.cloneCreationCode( abi.encodePacked(_merkleRoot, _owner, address(this)) ); bytes32 creationHash; // solhint-disable-next-line no-inline-assembly assembly { creationHash := keccak256(creationPtr, creationSize) } bytes32 data = keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, creationHash)); vault = address(uint160(uint256(data))); } /// @notice Gets next seed value of given account /// @param _deployer Address of vault deployer /// @return Value of next seed function getNextSeed(address _deployer) external view returns (bytes32) { return nextSeeds[_deployer]; } /// @notice Deploys new vault for given address /// @param _merkleRoot Merkle root of deployed vault /// @param _owner Address of vault owner /// @return vault Address of deployed vault function deployFor(bytes32 _merkleRoot, address _owner) public returns (address payable vault) { vault = _computeSalt(_merkleRoot, _owner); } /// @notice Deploys new vault for given address and executes calls /// @param _merkleRoot Merkle root of deployed vault /// @param _owner Address of vault owner /// @param _calls List of calls to execute upon deployment /// @return vault Address of deployed vault function deployFor( bytes32 _merkleRoot, address _owner, InitInfo[] calldata _calls ) public returns (address payable vault) { vault = _computeSalt(_merkleRoot, _owner); unchecked { for (uint256 i; i < _calls.length; ++i) { Vault(vault).execute(_calls[i].target, _calls[i].data, _calls[i].proof); } } } function _computeSalt(bytes32 _merkleRoot, address _owner) internal returns (address payable vault) { bytes32 seed = nextSeeds[tx.origin]; // Prevent front-running the salt by hashing the concatenation of tx.origin and the user-provided seed. bytes32 salt = keccak256(abi.encode(tx.origin, seed)); vault = _cloneVault(_merkleRoot, _owner, seed, salt); } function _cloneVault( bytes32 _merkleRoot, address _owner, bytes32 _seed, bytes32 _salt ) internal returns (address payable vault) { bytes memory data = abi.encodePacked(_merkleRoot, _owner, address(this)); vault = implementation.clone(_salt, data); // Increment the seed. unchecked { nextSeeds[tx.origin] = bytes32(uint256(_seed) + 1); } /// Log the vault via en event. emit DeployVault(tx.origin, msg.sender, _owner, _seed, _salt, vault, _merkleRoot); } } /// @title Vault Registry /// @author Tessera /// @notice Registry contract for tracking all Rae vaults contract VaultRegistry is IVaultRegistry { /// @dev Use clones library with address types using ClonesWithImmutableArgs for address; /// @notice Address of VaultFactory contract address public immutable factory; /// @notice Address of Rae token contract address public immutable rae; /// @notice Address of Implementation for Rae token contract address public immutable raeImplementation; /// @notice Mapping of collection address to next token ID type mapping(address => uint256) public nextId; /// @notice Mapping of vault address to vault information mapping(address => VaultInfo) public vaultToToken; /// @notice Initializes factory, implementation, and token contracts constructor() { factory = address(new VaultFactory()); raeImplementation = address(new Rae()); rae = raeImplementation.clone(abi.encodePacked(msg.sender, address(this))); } /// @notice Creates a new vault with permissions and initialization calls, and transfers ownership to a given owner /// @dev This should only be done in limited cases i.e. if you're okay with a trusted individual(s) /// having control over the vault. Ideally, execution would be locked behind a Multisig wallet. /// @param _merkleRoot Hash of merkle root for vault permissions /// @param _owner Address of the vault owner /// @param _calls List of initialization calls /// @return vault Address of Proxy contract function createFor( bytes32 _merkleRoot, address _owner, InitInfo[] calldata _calls ) public returns (address vault) { vault = _deployVault(_merkleRoot, _owner, rae, _calls); } /// @notice Creates a new vault with permissions /// @param _merkleRoot Hash of merkle root for vault permissions /// @return vault Address of Proxy contract function createFor(bytes32 _merkleRoot, address _owner) public returns (address vault) { vault = _deployVault(_merkleRoot, _owner, rae); } /// @notice Creates a new vault with permissions and initialization calls /// @param _merkleRoot Hash of merkle root for vault permissions /// @param _calls List of initialization calls /// @return vault Address of Proxy contract function create(bytes32 _merkleRoot, InitInfo[] calldata _calls) external returns (address vault) { vault = createFor(_merkleRoot, address(this), _calls); } /// @notice Creates a new vault with permissions and initialization calls /// @param _merkleRoot Hash of merkle root for vault permissions /// @return vault Address of Proxy contract function create(bytes32 _merkleRoot) external returns (address vault) { vault = createFor(_merkleRoot, address(this)); } /// @notice Creates a new vault with permissions and initialization calls for a given controller /// @param _merkleRoot Hash of merkle root for vault permissions /// @param _controller Address of token controller /// @param _calls List of initialization calls /// @return vault Address of Proxy contract /// @return token Address of Rae contract function createCollectionFor( bytes32 _merkleRoot, address _controller, InitInfo[] calldata _calls ) public returns (address vault, address token) { token = raeImplementation.clone(abi.encodePacked(_controller, address(this))); vault = _deployVault(_merkleRoot, address(this), token, _calls); } /// @notice Creates a new vault with permissions and intialization calls for the message sender /// @param _merkleRoot Hash of merkle root for vault permissions /// @param _calls List of initialization calls /// @return vault Address of Proxy contract /// @return token Address of Rae contract function createCollection(bytes32 _merkleRoot, InitInfo[] calldata _calls) external returns (address vault, address token) { (vault, token) = createCollectionFor(_merkleRoot, msg.sender, _calls); } /// @notice Creates a new vault with permissions and initialization calls for an existing collection /// @param _merkleRoot Hash of merkle root for vault permissions /// @param _token Address of Rae contract /// @param _calls List of initialization calls /// @return vault Address of Proxy contract function createInCollection( bytes32 _merkleRoot, address _token, InitInfo[] calldata _calls ) external returns (address vault) { address controller = Rae(_token).controller(); if (controller != msg.sender) revert InvalidController(controller, msg.sender); vault = _deployVault(_merkleRoot, address(this), _token, _calls); } /// @notice Burns vault tokens /// @param _from Source address /// @param _value Amount of tokens function burn(address _from, uint256 _value) external { VaultInfo memory info = vaultToToken[msg.sender]; uint256 id = info.id; if (id == 0) revert UnregisteredVault(msg.sender); Rae(info.token).burn(_from, id, _value); } /// @notice Mints vault tokens /// @param _to Target address /// @param _value Amount of tokens function mint(address _to, uint256 _value) external { VaultInfo memory info = vaultToToken[msg.sender]; uint256 id = info.id; if (id == 0) revert UnregisteredVault(msg.sender); Rae(info.token).mint(_to, id, _value, ""); } /// @notice Gets the total supply for a token and ID associated with a vault /// @param _vault Address of the vault /// @return Total supply function totalSupply(address _vault) external view returns (uint256) { VaultInfo memory info = vaultToToken[_vault]; return Rae(info.token).totalSupply(info.id); } /// @notice Gets the uri for a given token and ID associated with a vault /// @param _vault Address of the vault /// @return URI of token function uri(address _vault) external view returns (string memory) { VaultInfo memory info = vaultToToken[_vault]; return Rae(info.token).uri(info.id); } /// @dev Deploys new vault for specified token and sets the merkle root /// @param _merkleRoot Hash of merkle root for vault permissions /// @param _token Address of Rae contract /// @return vault Address of Proxy contract function _deployVault( bytes32 _merkleRoot, address _owner, address _token ) internal returns (address vault) { vault = VaultFactory(factory).deployFor(_merkleRoot, _owner); vaultToToken[vault] = VaultInfo(_token, ++nextId[_token]); emit VaultDeployed(vault, _token, nextId[_token]); } /// @dev Deploys new vault for specified token and sets the merkle root /// @param _merkleRoot Hash of merkle root for vault permissions /// @param _token Address of Rae contract /// @param _calls List of initialization calls /// @return vault Address of Proxy contract function _deployVault( bytes32 _merkleRoot, address _owner, address _token, InitInfo[] calldata _calls ) internal returns (address vault) { // pre-compute the next vault's address in order to register it before initialization calls vault = VaultFactory(factory).getNextAddress(tx.origin, _owner, _merkleRoot); vaultToToken[vault] = VaultInfo(_token, ++nextId[_token]); VaultFactory(factory).deployFor(_merkleRoot, _owner, _calls); emit VaultDeployed(vault, _token, nextId[_token]); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
[{"inputs":[{"internalType":"uint256","name":"_percentage","type":"uint256"}],"name":"InvalidRoyalty","type":"error"},{"inputs":[{"internalType":"address","name":"_required","type":"address"},{"internalType":"address","name":"_provided","type":"address"}],"name":"InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"InvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"BurnRaes","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_newController","type":"address"}],"name":"ControllerTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"MintRaes","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_metadata","type":"address"},{"indexed":false,"internalType":"uint256","name":"_id","type":"uint256"}],"name":"SetMetadata","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_percentage","type":"uint256"}],"name":"SetRoyalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_approved","type":"bool"}],"name":"SingleApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"INITIAL_CONTROLLER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"VAULT_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"address","name":"controllerAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"isApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"bool","name":"_approved","type":"bool"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"}],"name":"permitAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_metadata","type":"address"}],"name":"setMetadataDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_percentage","type":"uint256"}],"name":"setRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newController","type":"address"}],"name":"transferController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.