This is a work-in-progress implementation of ERC-1155 based on the discussions in the EIP-1155 issue thread.
Requirements:
- Solidity 0.5
Run npm install
in the root directory.
Run npm test
to run the unit tests.
ERC-1155: Smart Contract Sample Implementation
License: Apache License 2.0
This is a work-in-progress implementation of ERC-1155 based on the discussions in the EIP-1155 issue thread.
Requirements:
Run npm install
in the root directory.
Run npm test
to run the unit tests.
Why do ERC1155MixedFungibleMintable needs store the type of both fungible and non-fundgible in the upper 128 bits? For non-fungible it makes sense since the lower 128 bits are ID, but for fungible, why do we need to store the type in upper 128 bits as well
// Store the type in the upper 128 bits
_type = (++nonce << 128); <---- this one
// Set a flag if this is an NFI.
if (_isNF)
_type = _type | TYPE_NF_BIT;
// This will allow restricted access to creators.
creators[_type] = msg.sender;
_type = (++nonce << 128);
in the condition if (_isNF)
instead ?git clone https://github.com/enjin/erc-1155.git
cd .\erc-1155
npm install
truffle test
truffle test
Using network 'development'.
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
/Users/vitalihurski/Projects/tests/erc-1155/test/ERC1155Mintable.js:5
import expectThrow from './helpers/expectThrow';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at wrapSafe (internal/modules/cjs/loader.js:983:16)
at Module._compile (internal/modules/cjs/loader.js:1033:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1103:10)
at Module.load (internal/modules/cjs/loader.js:914:32)
at Function.Module._load (internal/modules/cjs/loader.js:822:14)
at Module.require (internal/modules/cjs/loader.js:956:19)
at require (internal/modules/cjs/helpers.js:74:18)
at /usr/local/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:250:27
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/usr/local/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:247:14)
at Mocha.run (/usr/local/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:576:10)
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/test.js:134:1
at new Promise (<anonymous>)
at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/test.js:133:1)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
Truffle v5.1.0 (core: 5.1.0)
Node v13.1.0
Steps to repoduce:
master
at ab7141d
npm install -g solc
git clone [email protected]:enjin/erc-1155.git
cd erc-1155
❯❯❯ npm install
npm ERR! Cannot read property 'match' of undefined
npm ERR! A complete log of this run can be found in:
npm ERR! ~/.npm/_logs/2019-09-10T15_11_17_200Z-debug.log
Workaround:
rm -f package-lock.json
Resulting package-lock.json
: https://gist.github.com/michaeljklein/49c4f7412b9cb0cc3cece4454129d29c
According to https://eips.ethereum.org/EIPS/eip-1155, you have to implement a uri
function for contract supports ERC1155Metadata_URI extension.
But in the ERC1155Mintable.sol
it registers 0x0e89341c
for erc165 but doesn't have a implementation of uri
.
Preface
In practice, achieving an index value greater than 2 ** 127 + 1 is infeasible by minting in unit increments, so deployment of this contract as is should be safe. The suggestion below is mostly for logical soundness, however users who make modifications to the prototype by replacing the base type incrementer with custom id's should be made aware, and perhaps guards should be put in place.
Expected Behavior
In contract {ERC1155MixedFungibleMintable}, all _type
values in the range supported by its integer type uint256
can be created and accessed without clashes and access control insecurity.
Actual Behavior
The current demonstration code runs the risk of calls reduced to the same base _type
for the index
range between 2**127
and 2**256 - 1
, where in a simplified 8-bit demonstration of left-shifted index
values masked by the TYPE_NF_MASK
:
0001 0001 << 4 | 1000 0000
and 0000 0001 << 4 | 1000 0000
result in the sender address being overwritten in the create()
call on L137 of ERC1155MixedFungibleMintable
In addition, any nonce
value where the lower half order of bits falls between xxxx 1000
and xxxx 1111
will clash with values ranging in xxxx 0000
and xxxx 0111
.
As such, regarding these two attack vectors, the nonce value should not exceed 2 ** (256/2 - 1) - 1
.
Similarly, maxIndex
should not exceed 2 ** (128) - 1
.
Suggestion
Limit _type
to a supported uint
type less than 2 ** 127, i.e. uint120
where compiler ^0.8
can handle overflow checks, or add validation logic to revert index values greater than that safe value, or utilize recent feature of User-Defined Types. A more expensive and unnecessarily complicated construction would be to create and manipulate 2 word custom integers, e.g., a Uint512Lib
custom library.
We're attempting to implement our first 1155 token using Vyper rather than Solidity. Noticed that your example code has some inline assembly in it. See https://github.com/enjin/erc-1155/blob/master/contracts/ERC1155.sol#L206
I'm not entirely certain what the operation is supposed to be doing here or what, if any, Vyper function would provide the equivalent functionality. Inline assembly is not allowed in Vyper. I expect we definitely want to support Vyper in 1155.
constructor(){
_mint(address(this),ProjectA,1,"0x0");
}
buyTKN(){
safeTransferFrom(address(this), msg.sender, ProjectA, 1, "");
}
How do I let add users buy these tokens?
I can't get the difference between the 'create' function and 'mint' function in ERC1155Mintable.sol.
When you use 'create' function with initalSupply=100, and the balanceOf the owner is now 100. If so, it should be similar to 'mint' function, right?
This implementation is using EIP-1538 for its upgrades. Specifically EIP-1538 is implemented in the contracts in the ProxyReceiver folder.
EIP-1538 has been abandoned and replaced by EIP-2535, the Diamond Standard.
EIP-2535, or the Diamond Standard, is an improvement over EIP-1538.
I suggest replacing the implementation of EIP-1538 in this repository with an implementation of EIP-2535. I suggest using the reference implementation of EIP-2535 to do this.
Some information about the Diamond Standard:
Here's a couple articles about EIP-2535:
Understanding Diamonds on Ethereum
Ethereum's Maximum Contract Size Limit is Solved with the Diamond Standard
One of the authors (Ronan Sandford) of ERC-1155 is currently building tooling for EIP-2535. Here is a link to his announcement: https://twitter.com/wighawag/status/1280992800545349644
I am the author of the Diamond Standard so if you have any questions or need help then let me know.
Hi, I have a question about the function create()
and mint()
in the file--ERC1155Mintable.sol.
In the function create()
, balances[_id][msg.sender] = _initialSupply;
sets the value of balances[_id][msg.sender]
to _initialSupply
.But in the function mint()
, balances[_id][to] = quantity.add(balances[_id][to]);
shows that balances[_id][to]
is be added, but balances[_id][msg.sender]
is not be subtracted.
And in emit TransferSingle(msg.sender, address(0x0), to, _id, quantity);
, why the _from address is "0x0"?
The syntax in the expectThrow file returns an error with unexpected token
The syntax can be changed to:
async function expectThrow() {
// ...
try {
await promise;
} catch (error) {
// TODO: Check jump destination to destinguish between a throw
// and an actual invalid jump.
const invalidOpcode = error.message.search('invalid opcode') >= 0;
// TODO: When we contract A calls contract B, and B throws, instead
// of an 'invalid jump', we get an 'out of gas' error. How do
// we distinguish this from an actual out of gas event? (The
// testrpc log actually show an 'invalid jump' event.)
const outOfGas = error.message.search('out of gas') >= 0;
const revert = error.message.search('revert') >= 0;
assert(
invalidOpcode || outOfGas || revert,
'Expected throw, got \'' + error + '\' instead',
);
return;
}
assert.fail('Expected throw not received');
}
// doStuff is defined inside the module so we can call it wherever we want
// Export it to make it available outside
module.exports.expectThrow = expectThrow;
and the first line in ERC115Mintable.js can be changed to :
const expectThrow = require('./helpers/expectThrow');
instead of an import...
Hi there,
I came across these contracts while researching NFT standards and wanted to ask or at least firm up my understanding of a few things regarding the differences/capabilities of the standard and these contracts in general.
I'm really sorry if this isn't the best place to do this, I have found it incredibly hard on discord or other forums to get straight answers to a few of these and if the answers can add value elsewhere to future users I would love to collate them into some kind of tutorial/wiki that goes beyond the naive implementations we see out in the wild.
As we see generally minting a token in an ERC1155 will give you back an id. (0x01) lets say. So this is ID of one type of contract and a qty of 1.
In this case I can have multiples minted of ID=0x01 and these can be assigned to multiple addresses?
How then to only have one ID=0x01 NFT issues? These are preminted with a total of 1?
I have seen some NFT examples where they place some constants in the contract to describe the ID types (card types for example, special, legendary etc). This would be good if all those cards were idempotent/similar stats/details so the ID resolves to a common JSON metadata file they all share.
In this I mean, perhaps you generate a class of card (special card10) and then you have some element of random stats given to that card (XP boosts etc). At this point I think you are going to have to create a unique ID for each and every card in your universe?
Now the ID space is a 64 bit hex number so there are plenty in there so I think that would fine.
Would any issues come using such large numbers when packing and sending them onto other addresses or is the O(1) lookup and searching happening in the code here? There is no time costs to larger and larger IDs?
In the case of stats on chain, how best to store that? Say you wanted to store 4-6 values on the NFT on chain for some use in a smart contract in such a way the JSON metadata is not a possibility? Would you store that in the same NFT as an array to ID mapping or would you embed it in the ID using some kind of bitwise shift? (Top 3/4 of the ID are the monotonically incrementing ID counter and the bottom 1/4 is the array of stats in 4byte blocks or something).
I hope these questions make sense, I'm trying to understand how the universe of NFTs can be generated and stored, any performance considerations along side using them.
And also, some on-chain data storage for pertinent data that we would like to have on-chain attached to an NFT, how best would that be achieved in a clear and concise manner that isn't too costly.
Thanks again for your time and building this amazing EIP.
git clone https://github.com/enjin/erc-1155.git
cd .\erc-1155
npm install
λ truffle test
Could not find suitable configuration file.
Truffle v5.0.30 (core: 5.0.30)
Node v10.16.0
Are you missing the the truffle-config.js file?
It's not safe, might overwrite an existing token?
Hello everyone,
I came across this line in the ERC-1155 contract
erc-1155/contracts/ERC1155.sol
Line 33 in 1e6ddc8
Minting functionality is not standardized in ERC-1155.
Source: https://eips.ethereum.org/EIPS/eip-1155
Code for minting is included in this repository as a demonstration (that's good) and it will be helpful to people studying this code as a reference implementation (also good). Currently this code is included in a file named ERC1155Mintable.sol (that's bad).
Because the minting functionality is not standardized, I recommend that any interfaces (interface
) or implementations (contract
) which implement minting should be in files that are not named including "1155". At current, somebody referencing this repository may mistakingly assume that the provided minting interface is standardized.
I recommend that these example extensions should be renamed as a "mock" or "example" or other. A reference for best practice in this aspect is the file organization presented at
https://github.com/0xcert/ethereum-erc721/tree/master/src/contracts/tokens
Similarly, this issue also applies to other non-standard implementations provided in this project.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.