-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
369 additions
and
0 deletions.
There are no files selected for viewing
17 changes: 17 additions & 0 deletions
17
packages/contracts/evm-contracts/contracts/token/IERC4906Agnostic.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: MIT | ||
// Forked from OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol) | ||
|
||
pragma solidity ^0.8.13; | ||
|
||
/// @title Agnostic Metadata Update Extension | ||
interface IERC4906Agnostic { | ||
/// @dev This event emits when the metadata of a token is changed. | ||
/// So that the third-party platforms such as NFT market could | ||
/// timely update the images and related attributes of the token. | ||
event MetadataUpdate(uint256 _tokenId); | ||
|
||
/// @dev This event emits when the metadata of a range of tokens is changed. | ||
/// So that the third-party platforms such as NFT market could | ||
/// timely update the images and related attributes of the tokens. | ||
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); | ||
} |
26 changes: 26 additions & 0 deletions
26
packages/contracts/evm-contracts/contracts/token/IInverseAppProjected1155.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.13; | ||
|
||
import {IInverseProjected1155} from "./IInverseProjected1155.sol"; | ||
|
||
/// @dev A Paima Inverse Projection ERC1155 token where initialization is handled by the app-layer. | ||
/// A standard ERC1155 that can be freely minted and stores an unique `<minter, userTokenId>` pair (used in `tokenURI`) when minted. | ||
interface IInverseAppProjected1155 is IInverseProjected1155 { | ||
/// @dev Emitted when `value` amount of globally-enforced `tokenId` in combination with an unique `<minter, userTokenId>` pair is minted. | ||
event Minted( | ||
uint256 indexed tokenId, | ||
address indexed minter, | ||
uint256 indexed userTokenId, | ||
uint256 value | ||
); | ||
|
||
/// @dev Emitted when supply of globally-enforced `tokenId` in combination with an unique `<minter, userTokenId>` pair goes to zero. | ||
event BurnedAll(uint256 indexed tokenId, address indexed minter, uint256 indexed userTokenId); | ||
|
||
/// @dev Mints `value` of a new token to the transaction sender. | ||
/// Increases the `currentTokenId`. | ||
/// Reverts if transaction sender is a smart contract that does not implement IERC1155Receiver-onERC1155Received. | ||
/// Emits the `Minted` event. | ||
/// Returns the id of the minted token. | ||
function mint(uint256 value, bytes memory data) external returns (uint256); | ||
} |
22 changes: 22 additions & 0 deletions
22
packages/contracts/evm-contracts/contracts/token/IInverseBaseProjected1155.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.13; | ||
|
||
import {IInverseProjected1155} from "./IInverseProjected1155.sol"; | ||
|
||
/// @dev A Paima Inverse Projection ERC1155 token where initialization is handled by the base-layer. | ||
/// A standard ERC1155 that accepts calldata in the mint function for any initialization data needed in a Paima dApp. | ||
interface IInverseBaseProjected1155 is IInverseProjected1155 { | ||
/// @dev Emitted when `value` amount of globally-enforced `tokenId` is minted, with `initialData` provided in the `mint` function parameters. | ||
event Minted(uint256 indexed tokenId, string initialData); | ||
|
||
/// @dev Mints `value` of a new token to transaction sender, passing `initialData` to be emitted in the event. | ||
/// Increases the `currentTokenId`. | ||
/// Reverts if transaction sender is a smart contract that does not implement IERC1155Receiver-onERC1155Received. | ||
/// Emits the `Minted` event. | ||
/// Returns the id of the minted token. | ||
function mint( | ||
uint256 value, | ||
bytes memory data, | ||
string calldata initialData | ||
) external returns (uint256); | ||
} |
30 changes: 30 additions & 0 deletions
30
packages/contracts/evm-contracts/contracts/token/IInverseProjected1155.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.13; | ||
|
||
import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; | ||
import {IERC4906Agnostic} from "./IERC4906Agnostic.sol"; | ||
|
||
/// @dev A standard ERC1155 that can be burned and has a special uri function accepting a custom base URI. | ||
interface IInverseProjected1155 is IERC1155MetadataURI, IERC4906Agnostic { | ||
/// @dev Emitted when `baseExtension` is updated from `oldBaseExtension` to `newBaseExtension`. | ||
event SetBaseExtension(string oldBaseExtension, string newBaseExtension); | ||
|
||
/// @dev Emitted when `baseUri` is updated from `oldUri` to `newUri`. | ||
event SetBaseURI(string oldUri, string newUri); | ||
|
||
/// @dev Burns `value` amount of token of ID `id` from transaction sender. | ||
/// Reverts if transaction sender's balance of `id` is less than `value`. | ||
function burn(uint256 id, uint256 value) external; | ||
|
||
/// @dev Sets `_URI` as the `baseURI`. | ||
/// Callable only by the contract owner. | ||
/// Emits the `SetBaseURI` event. | ||
function setBaseURI(string memory _URI) external; | ||
|
||
/// @dev Sets `_newBaseExtension` as the `baseExtension`. | ||
/// Callable only by the contract owner. | ||
function setBaseExtension(string memory _newBaseExtension) external; | ||
|
||
/// @dev Returns the token URI of specified `id` using a custom base URI. | ||
function uri(uint256 id, string memory customBaseUri) external view returns (string memory); | ||
} |
150 changes: 150 additions & 0 deletions
150
packages/contracts/evm-contracts/contracts/token/InverseAppProjected1155.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.13; | ||
|
||
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; | ||
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; | ||
import {ERC1155Supply} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; | ||
import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; | ||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; | ||
import {IERC4906} from "@openzeppelin/contracts/interfaces/IERC4906.sol"; | ||
import {IInverseProjected1155} from "./IInverseProjected1155.sol"; | ||
import {IInverseAppProjected1155} from "./IInverseAppProjected1155.sol"; | ||
import {IERC4906Agnostic} from "./IERC4906Agnostic.sol"; | ||
|
||
struct MintEntry { | ||
address minter; | ||
uint256 userTokenId; | ||
} | ||
|
||
/// @dev A Paima Inverse Projection ERC1155 token where initialization is handled by the app-layer. | ||
/// A standard ERC1155 that can be freely minted and stores an unique `<minter, userTokenId>` pair (used in `tokenURI`) when minted. | ||
contract InverseAppProjected1155 is IInverseAppProjected1155, ERC1155Supply, Ownable { | ||
using Strings for uint256; | ||
|
||
string public name; | ||
string public symbol; | ||
|
||
mapping(uint256 id => MintEntry) public tokenToMint; | ||
mapping(address minter => uint256) public mintCount; | ||
mapping(uint256 id => uint256) private _initialSupply; | ||
|
||
/// @dev The token ID that will be minted when calling the `mint` function. | ||
uint256 public currentTokenId; | ||
/// @dev Base URI that is used in the `uri` function to form the start of the token URI. | ||
string public baseURI; | ||
/// @dev Base extension that is used in the `uri` function to form the end of the token URI. | ||
string public baseExtension; | ||
|
||
/// @dev Sets the token's `_name`, `_symbol`, and transfers ownership to `_owner`. | ||
/// Also sets `currentTokenId` to 1. | ||
constructor( | ||
string memory _name, | ||
string memory _symbol, | ||
address _owner | ||
) ERC1155("") Ownable(_owner) { | ||
name = _name; | ||
symbol = _symbol; | ||
currentTokenId = 1; | ||
} | ||
|
||
/// @dev Returns true if this contract implements the interface defined by `interfaceId`. See EIP165. | ||
function supportsInterface( | ||
bytes4 interfaceId | ||
) public view virtual override(IERC165, ERC1155) returns (bool) { | ||
return | ||
interfaceId == type(IInverseProjected1155).interfaceId || | ||
interfaceId == type(IInverseAppProjected1155).interfaceId || | ||
super.supportsInterface(interfaceId); | ||
} | ||
|
||
/// @dev Returns the amount of token with ID `id` that had been initially minted. | ||
function initialSupply(uint256 id) public view virtual returns (uint256) { | ||
return _initialSupply[id]; | ||
} | ||
|
||
/// @dev Mints `value` of a new token to transaction sender. | ||
/// Increases the `currentTokenId`. | ||
/// Reverts if transaction sender is a smart contract that does not implement IERC1155Receiver-onERC1155Received. | ||
/// Emits the `Minted` event. | ||
/// Returns the id of the minted token. | ||
function mint(uint256 value, bytes memory data) external virtual returns (uint256) { | ||
uint256 tokenId = currentTokenId; | ||
_mint(msg.sender, tokenId, value, data); | ||
mintCount[msg.sender] += 1; | ||
uint256 userTokenId = mintCount[msg.sender]; | ||
tokenToMint[tokenId] = MintEntry(msg.sender, userTokenId); | ||
_initialSupply[tokenId] = value; | ||
|
||
currentTokenId++; | ||
|
||
emit Minted(tokenId, msg.sender, userTokenId, value); | ||
return tokenId; | ||
} | ||
|
||
/// @dev Burns `value` amount of token of ID `id` from transaction sender. | ||
/// Reverts if transaction sender's balance of `id` is less than `value`. | ||
function burn(uint256 id, uint256 value) external virtual { | ||
_burn(msg.sender, id, value); | ||
if (totalSupply(id) == 0) { | ||
MintEntry memory entry = tokenToMint[id]; | ||
emit BurnedAll(id, entry.minter, entry.userTokenId); | ||
} | ||
} | ||
|
||
/// @dev Returns the token URI of specified `id` using the default set base URI. | ||
function uri( | ||
uint256 id | ||
) public view virtual override(ERC1155, IERC1155MetadataURI) returns (string memory) { | ||
return uri(id, baseURI); | ||
} | ||
|
||
/// @dev Returns the token URI of specified `id` using a custom base URI. | ||
function uri( | ||
uint256 id, | ||
string memory customBaseUri | ||
) public view virtual returns (string memory) { | ||
require(exists(id), "InverseAppProjected1155: URI query for nonexistent token"); | ||
MintEntry memory entry = tokenToMint[id]; | ||
string memory URI = bytes(customBaseUri).length > 0 | ||
? string.concat( | ||
customBaseUri, | ||
Strings.toHexString(uint160(entry.minter), 20), | ||
"/", | ||
entry.userTokenId.toString(), | ||
"/", | ||
initialSupply(id).toString() | ||
) | ||
: ""; | ||
return string(abi.encodePacked(URI, baseExtension)); | ||
} | ||
|
||
/// @dev Sets `_URI` as the `baseURI` of the NFT. | ||
/// Callable only by the contract owner. | ||
/// Emits the `SetBaseURI` event. | ||
function setBaseURI(string memory _URI) external virtual onlyOwner { | ||
string memory oldURI = baseURI; | ||
baseURI = _URI; | ||
emit SetBaseURI(oldURI, _URI); | ||
} | ||
|
||
/// @dev Sets `_newBaseExtension` as the `baseExtension` of the NFT. | ||
/// Callable only by the contract owner. | ||
function setBaseExtension(string memory _newBaseExtension) public virtual onlyOwner { | ||
string memory oldBaseExtension = baseExtension; | ||
baseExtension = _newBaseExtension; | ||
emit SetBaseURI(oldBaseExtension, _newBaseExtension); | ||
} | ||
|
||
/// @dev Function that emits an event to notify third-parties (e.g. NFT marketplaces) about | ||
/// an update to consecutive range of tokens. Can be overriden in inheriting contract. | ||
function updateMetadataBatch(uint256 _fromTokenId, uint256 _toTokenId) public virtual { | ||
emit BatchMetadataUpdate(_fromTokenId, _toTokenId); | ||
} | ||
|
||
/// @dev Function that emits an event to notify third-parties (e.g. NFT marketplaces) about | ||
/// an update to a single token. Can be overriden in inheriting contract. | ||
function updateMetadata(uint256 _tokenId) public virtual { | ||
emit MetadataUpdate(_tokenId); | ||
} | ||
} |
124 changes: 124 additions & 0 deletions
124
packages/contracts/evm-contracts/contracts/token/InverseBaseProjected1155.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.13; | ||
|
||
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; | ||
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; | ||
import {ERC1155Supply} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; | ||
import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; | ||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; | ||
import {IERC4906} from "@openzeppelin/contracts/interfaces/IERC4906.sol"; | ||
import {IInverseProjected1155} from "./IInverseProjected1155.sol"; | ||
import {IInverseBaseProjected1155} from "./IInverseBaseProjected1155.sol"; | ||
import {IERC4906Agnostic} from "./IERC4906Agnostic.sol"; | ||
|
||
/// @dev A Paima Inverse Projection ERC1155 token where initialization is handled by the base-layer. | ||
/// A standard ERC1155 that accepts calldata in the mint function for any initialization data needed in a Paima dApp. | ||
contract InverseBaseProjected1155 is IInverseBaseProjected1155, ERC1155Supply, Ownable { | ||
using Strings for uint256; | ||
|
||
string public name; | ||
string public symbol; | ||
|
||
/// @dev The token ID that will be minted when calling the `mint` function. | ||
uint256 public currentTokenId; | ||
/// @dev Base URI that is used in the `uri` function to form the start of the token URI. | ||
string public baseURI; | ||
/// @dev Base extension that is used in the `uri` function to form the end of the token URI. | ||
string public baseExtension; | ||
|
||
/// @dev Sets the NFT's `name`, `symbol`, and transfers ownership to `owner`. | ||
/// Also sets `currentTokenId` to 1. | ||
constructor( | ||
string memory _name, | ||
string memory _symbol, | ||
address _owner | ||
) ERC1155("") Ownable(_owner) { | ||
name = _name; | ||
symbol = _symbol; | ||
currentTokenId = 1; | ||
} | ||
|
||
/// @dev Returns true if this contract implements the interface defined by `interfaceId`. See EIP165. | ||
function supportsInterface( | ||
bytes4 interfaceId | ||
) public view virtual override(IERC165, ERC1155) returns (bool) { | ||
return | ||
interfaceId == type(IInverseProjected1155).interfaceId || | ||
interfaceId == type(IInverseBaseProjected1155).interfaceId || | ||
super.supportsInterface(interfaceId); | ||
} | ||
|
||
/// @dev Mints `value` of a new token to transaction sender, passing `initialData` to be emitted in the event. | ||
/// Increases the `currentTokenId`. | ||
/// Reverts if transaction sender is a smart contract that does not implement IERC1155Receiver-onERC1155Received. | ||
/// Emits the `Minted` event. | ||
/// Returns the id of the minted token. | ||
function mint( | ||
uint256 value, | ||
bytes memory data, | ||
string calldata initialData | ||
) external virtual returns (uint256) { | ||
uint256 tokenId = currentTokenId; | ||
_mint(msg.sender, tokenId, value, data); | ||
|
||
currentTokenId++; | ||
|
||
emit Minted(tokenId, initialData); | ||
return tokenId; | ||
} | ||
|
||
/// @dev Burns `value` amount of token of ID `id` from transaction sender. | ||
/// Reverts if transaction sender's balance of `id` is less than `value`. | ||
function burn(uint256 id, uint256 value) external virtual { | ||
_burn(msg.sender, id, value); | ||
} | ||
|
||
/// @dev Returns the token URI of specified `id` using the default set base URI. | ||
function uri( | ||
uint256 id | ||
) public view virtual override(ERC1155, IERC1155MetadataURI) returns (string memory) { | ||
return uri(id, baseURI); | ||
} | ||
|
||
/// @dev Returns the token URI of specified `id` using a custom base URI. | ||
function uri( | ||
uint256 id, | ||
string memory customBaseUri | ||
) public view virtual returns (string memory) { | ||
require(exists(id), "InverseBaseProjected1155: URI query for nonexistent token"); | ||
string memory URI = bytes(customBaseUri).length > 0 | ||
? string.concat(customBaseUri, id.toString()) | ||
: ""; | ||
return string(abi.encodePacked(URI, baseExtension)); | ||
} | ||
|
||
/// @dev Sets `_URI` as the `baseURI` of the NFT. | ||
/// Callable only by the contract owner. | ||
/// Emits the `SetBaseURI` event. | ||
function setBaseURI(string memory _URI) external virtual onlyOwner { | ||
string memory oldURI = baseURI; | ||
baseURI = _URI; | ||
emit SetBaseURI(oldURI, _URI); | ||
} | ||
|
||
/// @dev Sets `_newBaseExtension` as the `baseExtension` of the NFT. | ||
/// Callable only by the contract owner. | ||
function setBaseExtension(string memory _newBaseExtension) public virtual onlyOwner { | ||
string memory oldBaseExtension = baseExtension; | ||
baseExtension = _newBaseExtension; | ||
emit SetBaseURI(oldBaseExtension, _newBaseExtension); | ||
} | ||
|
||
/// @dev Function that emits an event to notify third-parties (e.g. NFT marketplaces) about | ||
/// an update to consecutive range of tokens. Can be overriden in inheriting contract. | ||
function updateMetadataBatch(uint256 _fromTokenId, uint256 _toTokenId) public virtual { | ||
emit BatchMetadataUpdate(_fromTokenId, _toTokenId); | ||
} | ||
|
||
/// @dev Function that emits an event to notify third-parties (e.g. NFT marketplaces) about | ||
/// an update to a single token. Can be overriden in inheriting contract. | ||
function updateMetadata(uint256 _tokenId) public virtual { | ||
emit MetadataUpdate(_tokenId); | ||
} | ||
} |