-
Notifications
You must be signed in to change notification settings - Fork 252
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
feat(NFT): add events to standard #627
Conversation
207eeaf
to
a6e16e8
Compare
@austinabell @ChaoticTempest This is a rough start. I am a fan of this method since it seems to add a lot of code, so I would love some feedback. |
yeah, would be nice to have a common crate for all these types. Let me see if I can't get one up, but let me workshop around a name. |
@ChaoticTempest How about |
@ChaoticTempest any luck? |
@willemneal so was talking to @austinabell about this, but it seems like this would be better still living here since most of this is just the NFT related types. If anything, we'd surface |
Sounds good to me. I'll go ahead and update it. @frol @telezhnaya What are your thoughts for adding |
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 are your thoughts for adding
near-contract-standards
as a dep to the indexer so that we can share the types?
We would need to evaluate the dependencies tree before making this decision, but I think it should be fine. It is definitely not a priority at the moment, though. We will get back to it after FT events are implemented.
pub fn log_nft_mint(owner_id: String, token_ids: Vec<String>, memo: Option<String>) { | ||
NearEvent::nft_mint(vec![NftMintData { owner_id, token_ids, memo }]).log(); | ||
} | ||
pub fn log_nft_transfer( | ||
old_owner_id: String, | ||
new_owner_id: String, | ||
token_ids: Vec<String>, | ||
memo: Option<String>, | ||
authorized_id: Option<String>, | ||
) { | ||
NearEvent::nft_transfer(vec![NftTransferData { | ||
authorized_id, | ||
old_owner_id, | ||
new_owner_id, | ||
token_ids, | ||
memo, | ||
}]) | ||
.log(); | ||
} | ||
|
||
pub fn log_nft_burn( | ||
owner_id: String, | ||
authorized_id: Option<String>, | ||
token_ids: Vec<String>, | ||
memo: Option<String>, | ||
) { | ||
NearEvent::nft_burn(vec![NftBurnData { owner_id, authorized_id, token_ids, memo }]).log(); | ||
} |
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 API has a few problems:
-
The usage of these methods will be error-prone to use and hard to reason about:
NearEvent::log_nft_transfer("frol.near", "willem.near", vec!["dacha".to_string()], Some("qq".to_string()), Some("alex.near")) NearEvent::log_nft_burn("willem.near", Some("alex.near"), vec!["dacha".to_string()], Some("qq".to_string()))
(You already mixed up the order of
authorized_id
in transfer and burn methods) -
These methods promote non-batched events and thus we promote using more gas on events than necessary
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.
-
Yeah oops, this was from just following the ordering from the struct.
-
I agree, my inital thoughts were that they were the common case so it should be easy to use.
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 fixed 1
and added methods to log data vectors.
#[skip_serializing_none] | ||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct NftMintData { | ||
pub owner_id: String, | ||
pub token_ids: Vec<String>, | ||
pub memo: Option<String>, | ||
} | ||
|
||
#[skip_serializing_none] | ||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct NftTransferData { | ||
pub authorized_id: Option<String>, | ||
pub old_owner_id: String, | ||
pub new_owner_id: String, | ||
pub token_ids: Vec<String>, | ||
pub memo: Option<String>, | ||
} | ||
|
||
#[skip_serializing_none] | ||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct NftBurnData { | ||
pub authorized_id: Option<String>, | ||
pub owner_id: String, | ||
pub token_ids: Vec<String>, | ||
pub memo: Option<String>, | ||
} |
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.
We may consider using Cow<'a, str>
instead of Strings to avoid unnecessary clones when users would need to generate the events without giving the ownership over the strings. Yet, that might make the API harder to follow.
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.
Yeah again this is a copy/paste and I agree that we should try to minimize the cost of these logs.
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.
Still not sure how to fix this. It is annoying with to_string
s everywhere.
guys any luck with this PR? |
@danielwpz About to push up some changes! |
@ChaoticTempest @frol @austinabell @BenKurrek I moved everything up a level and added three new methods for logging batches of events. However, I'm still not a fan of |
Might be worth at least switching and seeing how it affects code size. Keep in mind, by default Cow will deserialize as an owned string and you don't get the performance of referencing the deserialized buffer so this just saves an allocation on initialization. As for this PR and the other, I think it might have been assumed this was stale as it didn't have the connection to standards, not sure. Hopefully, we can merge the efforts somehow to get the best of both :) |
What do you mean |
it isn't used in the NFT standard, this just adds the types, which is fine |
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'll leave it up to @austinabell to have the final say, but overall this PR looks good to me. The sim tests will have to be moved over to workspaces in the future, but for now we can leave that for a later PR. Think we need a CHANGELOG entry as well
near-contract-standards/src/event.rs
Outdated
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct NftMintData<'a> { | ||
#[serde(borrow)] | ||
pub owner_id: Cow<'a, str>, |
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.
Maybe worth putting in the comments somewhere in this file about why the optimization with Cow
's are needed, or linking back to this PR with the discussions could work too
Co-authored-by: Phuong Nguyen <ChaoticTempest@users.noreply.github.com>
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.
Sorry for long time to review, think there is a slight miscommunication about who owns standards
near-contract-standards/src/event.rs
Outdated
pub old_owner_id: Cow<'a, str>, | ||
#[serde(borrow)] | ||
pub new_owner_id: Cow<'a, str>, | ||
#[serde(borrow)] | ||
pub token_ids: Vec<Cow<'a, str>>, | ||
#[serde(borrow)] | ||
pub authorized_id: Option<Cow<'a, str>>, | ||
#[serde(borrow)] | ||
pub memo: Option<Cow<'a, str>>, |
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.
Is there a benefit to exposing all of these? Seems like we are just adding too much surface area to maintain
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 was from the original code from the indexer. So no real reason to expose them.
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.
@frol @telezhnaya Thoughts?
|
||
#[skip_serializing_none] | ||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct NftTransferData<'a> { |
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.
Would be nice if there were docs on some of these, but that can always be added in follow up PR
} | ||
|
||
pub(crate) fn to_json_string(&self) -> String { | ||
serde_json::to_string(self).unwrap() |
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 should never fail, so would be slightly more ideal to just panic through host function to avoid file-specific data being included. Fine to have this done in a following PR though.
near-contract-standards/src/non_fungible_token/core/core_impl.rs
Outdated
Show resolved
Hide resolved
@austinabell I addressed most of your concerns. I didn't change the visibility of the inner fields. I also improved the API so that AccountId's are used directly ensuring that only valid ones are written to the event ( unless they do Removing PTAL and let me know. |
Co-authored-by: Austin Abell <austinabell8@gmail.com>
@austinabell Could really use this in the wild! Also the FT events have been added to the standard to so I'll add that in a future PR. |
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.
Feel free to change the things I've commented on. Going to follow this to make some other changes wrt what of the API is exposed to make it easier to maintain anyway so nbd if not
pub old_owner_id: &'a str, | ||
#[serde(borrow)] | ||
pub new_owner_id: &'a str, |
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.
why not these as account ids?
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 AccountId references are used in the constructors. If I add them here I get:
the trait bound `&'a AccountId: Deserialize<'_>` is not satisfied
the following implementations were found:
<AccountId as Deserialize<'de>>
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.
yeah, the point before is that the deserialize isn't needed for anything. nbd can leave as is
@austinabell @ChaoticTempest Thanks for reviewing, but it seems I have lost my ability to hit the final merge. |
Because of the conflicts? Was just waiting for that |
Literally not an option to merge for me. I guess you have to be in the NEAR org to get that power. |
Nope, just needed to be merged manually. I couldn't have pulled it in either. Hope you don't mind me pushing to your branch to fix |
No issues just glad to see it wrapping up. |
@willemneal I am so happy to see how this turned out to be a nice API! I want to thank you for driving this! It is really tiresome work to get to perfection. I also apologize that I failed to provide the feedback in timely manner 🙏 @miraclx Could you maybe take a look into why |
No worries, the API was updated in dce4bd8 so there is no need for this. Deserializing into an AccountId reference is intended given our current |
This borrows the types for NFT event standard used by indexer. The only real change is that serializers are implemented for these types and
serde_with
is used to not serialize optional fields.Perhaps these types should live in a separate repo that is shared between the sdk and the indexer, but I thought I'd put them here for now.