-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add cw1155 specification #247
Conversation
Design decisions: - Fungible tokens and non-fungible tokens are treated equally, non-fungible tokens just have one max supply. - Approval is set or unset to some operator over entire set of tokens. (More nuanced control is defined in [ERC1761](https://eips.ethereum.org/EIPS/eip-1761), do we want to merge them together?) - Metadata and token enumeration should be done by indexing events off-chain. - Mint and burn are mixed with transfer/send messages, otherwise, we'll have much more message types, e.g. `Mint`/`MintToContract`/`BatchMint`/`BatchMintToContract`, etc. In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they must not both be `None` at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice and clean implementation and I really like some of the ideas. Especially events, but also merging eg. Send/SendFrom into one message type (avoids lots of duplication).
Most of the comments are minor suggestions to polish off the spec. The only real issue is combining send/burn/mint into one message. I would like a 2nd (or 3rd) opinion here. This is really about API design not coding.
Also, what do you think in general of extending the Ethereum spec to match our framework a bit I mean, you use Uint128 rather than Uint256 (128 bit is plenty large enough, and they just have 256 cuz everything is 256bit in Ethereum). It is a chance to take these same ideas and enhance them with some of the capabilities of CosmWasm (especially cheap iteration over parts of a set)
packages/cw1155/README.md
Outdated
|
||
- Mint and burn are mixed with transfer/send messages, otherwise, we'll have much more message types, e.g. `Mint`/`MintToContract`/`BatchMint`/`BatchMintToContract`, etc. | ||
|
||
In transfer/send messges, `from`/`to` are optional, a `None` `from` means minting, a `None` `to` means burning, they must not both be `None` at the same time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems dangerous to me, as the input is JSON, and extra fields are ignored. So changing from
to form
turns a transfer to a mint (likely to fail anyway), but using too
vs to
will make you burn your tokens, rather than have the tx rejected by the chain.
@willclarktech and @maurolacy I think we discussed the issue of nullable fields changing functionality to be dangerous. Will especially in the context of CosmJS, some case when we said omitting a field from "ChangeOwner" would make it "ClearOwner" (making no one owner) could be an expensive mistake with a typo.
Can you please comment on this design here (or better look at the corresponding type definitions) and say if you approve or suggest ways to improve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about minting/burning if the null address is provided, like Ethereum's 0x0000000000000000000000000000000000000000
? Then at least you have to specify it. Otherwise I'd suggest mint
/burn
boolean options to be explicit.
packages/cw1155/README.md
Outdated
|
||
`TransferFrom{from, to, token_id, value}` - This transfers some amount of tokens between two accounts. The operator should have approval from the source account. | ||
|
||
`SendFrom{from, to, token_id, value, msg}` - This transfers some amount of tokens between two accounts. `to` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that you combine Send
and SendFrom
is nice (just provide your own address as from to make it a normal send). Just not sure to throw in Mint/MintFrom/Burn/BurnFrom here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, mint/burn messages are separated.
} | ||
|
||
impl Event for TransferEvent { | ||
fn write_attributes(&self, attributes: &mut Vec<Attribute>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Response object now has an add_attribute
method. Maybe this could make use of it?
fn write_attributes(&self, resp: &mut Response) {
resp.add_attributute("action", "transfer");
resp.add_attributute("token_id", self.token_id);
// ...
}
Not that it does anything different, but seems a bit cleaner to read and sets a nice pattern for other devs. (And I would like your feedback on the method name add_attribute
, we are still in beta, when it can be changed)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not very good at picking english names though ;D
add_attribute
sounds good to me, I changed the method name in Event
trait to add_attribututes
too.
packages/cw1155/src/msg.rs
Outdated
msg: Option<Binary>, | ||
}, | ||
/// Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. | ||
SetApprovalForAll { operator: HumanAddr, approved: bool }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In cw721 we took a few liberties to "improve" the Ethereum design, even with the "all or nothing" approval. How about adding an optional expiration date?
Adding approvals on token by token basis would be nice as well, even if it is full control of the balance on that token_id. Are you concerned about performance? Or prefer the API this way? Especially iteration is MUCH more efficient in CosmWasm/Cosmos SDK than Ethereum and it is nice to embrace it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the only trade-off is use cases vs simplicity and on-chain resource usage.
For the example cw721 contract to support approval by token, it needs to store a Vec<Approval>
in TokenInfo
, and need to do O(n)
search when checking permission.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. This does add more runtime complexity. We can leave it as is.
Thanks for review, new modifications:
Open issues: |
Thanks for the updates, looking very nice.
I don't know if this use case will be used much or at all and it does indeed add runtime overhead to every check. I am fine to leave it off.
This is my only outstanding concern, and I would like the comment of another developer with CosmWasm experience here. Otherwise, it looks good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good minus the discussion on separating Transfer/Mint/Burn.
If you wish to reduce types, another thought would be to combine TransferFrom and SendFrom.
eg.
/// This handles contract call or user account
SendFrom {
from: HumanAddr, // either env.sender self or another account sender is approved on
to: HumanAddr, // an external account or contract
token_id: TokenId,
value: Uint128,
// if msg is None, just transfer the tokens.
// if msg is Some(m), then call a Cw1155 receiver on a contract with the `to` address (after moving the token)
msg: Option<Binary>,
}
And then add other types for minting and burning (or at least burning).
This would allow you to reduce the number of types and address my concern about possibly mixing burning and send.
If you want to still keep from: None
to mean mint
I have less issues than with burn. In the end maybe you can end up with the followng types:
SendFrom
- mints or transfers from my account or transfers from other account. If there is a message, it will assume the target is a contract and invoke the cw1155 receiver on it.BatchSendFrom
- like SendFrom but with a list of tokensBurnFrom
- burns one token either from my account or an account i was authorized onApproveAll
RevokeAll
packages/cw1155/README.md
Outdated
|
||
`SendFrom{from, to, token_id, value, msg}` - This transfers some amount of tokens between two accounts. `to` | ||
must be an address controlled by a smart contract, which implements | ||
the `CW1155Receiver` interface. The operator should have approval from the source account. The `msg` will be passed to the recipient contract, along with the other fields. | ||
the `CW1155Receiver` interface. The operator should eitherbe the `from` account or have approval from it. The `msg` will be passed to the recipient contract, along with the other fields. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either be (missing space)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
packages/cw1155/README.md
Outdated
`ApprovedForAll{owner, include_expired, start_after, limit}` - List all operators that can | ||
access all of the owner's tokens. Return type is `ApprovedForAllResponse`. | ||
If `include_expired` is set, show expired owners in the results, otherwise, | ||
ignore them. If query for some specific operator, set `start_after` to the operator, and set limit to 1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually interesting point - start_after does not include that value itself. It is great for pagination, but not good for finding one in particular. Maybe you do want the other query as well to just get one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added ApprovedForAllItem
(please feel free to suggest a name for this ;).
I think it needs to be
I guess we probably also want |
There is no real use case when we send a message to a contract with data |
But the receiver msg contains |
You are right. I designed the cw20 receiver interface before implementing any contracts. It would be good to remove Option there. |
|
- Seperate Mint/Burn/BatchMint/BatchBurn - Merge TransferFrom and SendFrom
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the changes
@@ -54,10 +54,10 @@ Any contract wish to receive CW1155 tokens must implement `Cw1155ReceiveMsg` and | |||
|
|||
`from`/`to` are optional, no `from` attribute means minting, no `to` attribute means burning. | |||
|
|||
- `metadata(url, token_id)` | |||
- `token_info(url, token_id)` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In event.rs i only see MetadataEvent, not found token_info.
And i dont see any api using this event.
I just want add uri for token, but dont find any api do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
metadata modification is not part of the standard API, different contracts can implement their own APIs to do that I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean base on ERC1155Metadata?
Do you think it can fulfill what's missing?
retry of #245
fixes #246
Design decisions:
Mint
/MintToContract
/BatchMint
/BatchMintToContract
, etc.In transfer/send messges,
from
/to
are optional, aNone
from
means minting, aNone
to
means burning, they must not both beNone
at the same time.