Skip to content
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

Merged
merged 48 commits into from
Jan 25, 2022
Merged

Conversation

willemneal
Copy link
Contributor

@willemneal willemneal commented Nov 4, 2021

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.

@willemneal willemneal marked this pull request as ready for review November 8, 2021 20:52
@willemneal
Copy link
Contributor Author

@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.

@ChaoticTempest
Copy link
Member

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. near-primitives is already taken. near-commons could be one but might be confusing with near-primitives

@willemneal
Copy link
Contributor Author

@ChaoticTempest How about near-standards-primitives?

@willemneal
Copy link
Contributor Author

@ChaoticTempest any luck?

@ChaoticTempest
Copy link
Member

@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 NearEvent into lib.rs where we can potentially populate it with other events too like FT. What do you think?

@willemneal
Copy link
Contributor Author

Sounds good to me. I'll go ahead and update it. @frol @telezhnaya What are your thoughts for adding near-contract-standards as a dep to the indexer so that we can share the types?

Copy link
Collaborator

@frol frol left a 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.

near-contract-standards/src/non_fungible_token/event.rs Outdated Show resolved Hide resolved
Comment on lines 93 to 120
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();
}
Copy link
Collaborator

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:

  1. 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)

  2. These methods promote non-batched events and thus we promote using more gas on events than necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yeah oops, this was from just following the ordering from the struct.

  2. I agree, my inital thoughts were that they were the common case so it should be easy to use.

Copy link
Contributor Author

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.

near-contract-standards/src/non_fungible_token/event.rs Outdated Show resolved Hide resolved
Comment on lines 30 to 55
#[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>,
}
Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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_strings everywhere.

near-contract-standards/src/non_fungible_token/event.rs Outdated Show resolved Hide resolved
near-contract-standards/src/non_fungible_token/event.rs Outdated Show resolved Hide resolved
@danielwpz
Copy link
Contributor

guys any luck with this PR?

@willemneal
Copy link
Contributor Author

@danielwpz About to push up some changes!

@willemneal willemneal mentioned this pull request Dec 1, 2021
@willemneal
Copy link
Contributor Author

@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 String types everywhere. Do you think it's worth changing the API to Cow as @frol suggested?

@austinabell
Copy link
Contributor

@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 String types everywhere. Do you think it's worth changing the API to Cow as @frol suggested?

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 :)

@willemneal
Copy link
Contributor Author

What do you mean as it didn't have the connection to standards?

@austinabell
Copy link
Contributor

What do you mean as it didn't have the connection to standards?

it isn't used in the NFT standard, this just adds the types, which is fine

Copy link
Member

@ChaoticTempest ChaoticTempest left a 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 Show resolved Hide resolved
#[derive(Serialize, Deserialize, Debug)]
pub struct NftMintData<'a> {
#[serde(borrow)]
pub owner_id: Cow<'a, str>,
Copy link
Member

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

willemneal and others added 2 commits January 20, 2022 15:51
Co-authored-by: Phuong Nguyen <ChaoticTempest@users.noreply.github.com>
Copy link
Contributor

@austinabell austinabell left a 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 Show resolved Hide resolved
near-contract-standards/src/event.rs Outdated Show resolved Hide resolved
Comment on lines 80 to 88
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>>,
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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> {
Copy link
Contributor

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()
Copy link
Contributor

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/event.rs Outdated Show resolved Hide resolved
near-contract-standards/src/event.rs Outdated Show resolved Hide resolved
@willemneal
Copy link
Contributor Author

willemneal commented Jan 20, 2022

@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 new_unchecked).

Removing cow reduced the size of the final contract by around 3K, so not too much code bloat, but still an improvement.

PTAL and let me know.

@willemneal
Copy link
Contributor Author

@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.

Copy link
Contributor

@austinabell austinabell left a 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

near-contract-standards/src/event.rs Show resolved Hide resolved
Comment on lines +59 to +61
pub old_owner_id: &'a str,
#[serde(borrow)]
pub new_owner_id: &'a str,
Copy link
Contributor

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?

Copy link
Contributor Author

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>>

Copy link
Contributor

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

@willemneal
Copy link
Contributor Author

@austinabell @ChaoticTempest Thanks for reviewing, but it seems I have lost my ability to hit the final merge.

@austinabell
Copy link
Contributor

@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

@willemneal
Copy link
Contributor Author

Literally not an option to merge for me. I guess you have to be in the NEAR org to get that power.

@austinabell
Copy link
Contributor

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

@willemneal
Copy link
Contributor Author

No issues just glad to see it wrapping up.

@frol
Copy link
Collaborator

frol commented Feb 1, 2022

@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 the trait bound &'a AccountId: Deserialize<'_> is not satisfied: #627 (comment) ?

@austinabell
Copy link
Contributor

@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 the trait bound &'a AccountId: Deserialize<'_> is not satisfied: #627 (comment) ?

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 AccountId API, so no need for @miraclx to look into anything here I don't think

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants