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: render non-vbank NFTs in offers #125

Merged
merged 1 commit into from
Sep 21, 2023
Merged

feat: render non-vbank NFTs in offers #125

merged 1 commit into from
Sep 21, 2023

Conversation

samsiegart
Copy link
Contributor

@samsiegart samsiegart commented Sep 14, 2023

Closes #116

Screenshot 2023-09-15 at 12 15 06 PM

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Sep 14, 2023

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7ff97c0
Status: ✅  Deploy successful!
Preview URL: https://b826a1c5.wallet-app.pages.dev
Branch Preview URL: https://nft-wallet-app.wallet-app.pages.dev

View logs

@samsiegart samsiegart force-pushed the nft-wallet-app branch 2 times, most recently from 41b024f to ea7eb7b Compare September 15, 2023 04:51
@iomekam iomekam force-pushed the nft-wallet-app branch 2 times, most recently from d37cc23 to 0471b92 Compare September 15, 2023 16:59
wallet/src/components/Proposal.tsx Outdated Show resolved Hide resolved
wallet/src/components/SmartWalletConnection.tsx Outdated Show resolved Hide resolved
wallet/src/service/Offers.ts Outdated Show resolved Hide resolved
wallet/src/service/Offers.ts Outdated Show resolved Hide resolved
wallet/src/service/Offers.ts Outdated Show resolved Hide resolved
wallet/src/service/Offers.ts Outdated Show resolved Hide resolved
wallet/src/service/Offers.ts Outdated Show resolved Hide resolved
const value = String(entry.value);
return [kw, { pursePetname, value }];
}),
await Promise.all(
Copy link
Member

Choose a reason for hiding this comment

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

this looks like an opportunity to simplify with objectMap and deeplyFulfilledObject. I think with that you would need no await

Copy link
Contributor

Choose a reason for hiding this comment

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

I tried playing around with this but couldn't get it working. If we have time, I'd love to pair on this

Copy link
Member

Choose a reason for hiding this comment

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

check out 04ae1c6

Copy link
Member

Choose a reason for hiding this comment

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

I think that refactoring makes sense to apply here too, but not a blocker

wallet/src/service/Offers.ts Show resolved Hide resolved
@@ -402,7 +403,13 @@ export const makeWalletBridgeFromFollowers = (
// If we ever add non 'set' amount purses that aren't in the vbank, it's
// not currently possible to read their decimalPlaces, so this code
// will need updating.
if (!Array.isArray(purse.balance.value)) {

const isCopyBag = Object.prototype.hasOwnProperty.call(
Copy link
Member

Choose a reason for hiding this comment

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

we must have something already in Endo to check this. if not, please file an issue.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

I tried using isCopySet, but it kept returning false. Maybe I'm not passing in the correct data. I looked at how the method was used in other projects and couldn't discern what object shape is expects to be passed in

Copy link
Member

Choose a reason for hiding this comment

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

@iomekam iomekam requested a review from turadg September 19, 2023 16:49
Comment on lines 17 to 18
import { M } from '@agoric/vat-data';
import { mustMatch } from '@agoric/store';
Copy link
Member

Choose a reason for hiding this comment

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

available in Endo now

Suggested change
import { M } from '@agoric/vat-data';
import { mustMatch } from '@agoric/store';
import { M, mustMatch } from '@endo/patterns';

@@ -41,6 +44,41 @@ type GiveOrWantEntries = {
};
};

const CapDataShape = harden({ body: M.string(), slots: M.array() });
Copy link
Member

Choose a reason for hiding this comment

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

This looks right but is a concern of Endo. If it's not available in Endo please file an issue for Endo to provide it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@@ -41,6 +44,41 @@ type GiveOrWantEntries = {
};
};

const CapDataShape = harden({ body: M.string(), slots: M.array() });

const theOne = <T>(array: Array<T> | undefined) => {
Copy link
Member

Choose a reason for hiding this comment

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

consider putting this in a utils module. eventually we might want it in @agoric/internal but it's pretty lightweight to copy around

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 don't think this abstraction is appropriate for this use-case, explained in my comment below. Is this motivated rather by some other code in the sdk?

Copy link
Member

Choose a reason for hiding this comment

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

You're right. I misread the error conditions for #125 (comment)

There are other cases where an array length other than 1 is an error, and the utility is useful for those, but this spot want undefined in that case.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll file an issue in agoric-sdk to have this added to @agoric/internal

Copy link
Contributor

Choose a reason for hiding this comment

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

const theOne = <T>(array: Array<T> | undefined) => {
assert(array?.length === 1);

const first = array.at(0);
Copy link
Member

Choose a reason for hiding this comment

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

surprising to see at

Suggested change
const first = array.at(0);
const first = array[0];

but actually, the first element could very well be undefined. so,

Suggested change
const first = array.at(0);
return array[0];

@@ -402,7 +403,13 @@ export const makeWalletBridgeFromFollowers = (
// If we ever add non 'set' amount purses that aren't in the vbank, it's
// not currently possible to read their decimalPlaces, so this code
// will need updating.
if (!Array.isArray(purse.balance.value)) {

const isCopyBag = Object.prototype.hasOwnProperty.call(
Copy link
Member

Choose a reason for hiding this comment

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

const value = String(entry.value);
return [kw, { pursePetname, value }];
}),
await Promise.all(
Copy link
Member

Choose a reason for hiding this comment

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

check out 04ae1c6

),
]);

const brandPetname = theOne(brands.find(([_, brand]) => brand === brand));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did you test this before pushing? brands is an array of tuples of [petname, brand], so assert(array?.length === 1); above would always throw since the length is 2. I think it's better to leave the ?.at(0) and leave the brandPetname undefined if missing, then show an error in the component that renders the offer so that the user doesn't have to open the console to know something went wrong. Additionally, I think throwing will break the loop that watches pending offers, preventing it from rendering other offers.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for pointing this out. Turns out the purse was created, so I was no longer executing this code path

@@ -41,6 +44,41 @@ type GiveOrWantEntries = {
};
};

const CapDataShape = harden({ body: M.string(), slots: M.array() });

const theOne = <T>(array: Array<T> | undefined) => {
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 don't think this abstraction is appropriate for this use-case, explained in my comment below. Is this motivated rather by some other code in the sdk?

@iomekam iomekam requested a review from turadg September 20, 2023 16:38
@@ -191,7 +192,7 @@ const PurseValue = ({ value, displayInfo, brandPetname }) => {
const isSet = displayInfo?.assetKind === AssetKind.SET;
const isCopyBag = displayInfo?.assetKind === AssetKind.COPY_BAG;

if (isCopyBag && Object.prototype.hasOwnProperty.call(value, 'payload')) {
if (isCopyBag && endoIsCopyBag(value)) {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder why one would be true and not the other. Is that exceptional?

Copy link
Contributor

Choose a reason for hiding this comment

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

I wasn't sure if there was some legacy situation where we could have a copyBag, but it didn't have the correct payload. @samsiegart, do you think this is a safe change?

);
const purse = brandToPurse.get(amount.brand);

// if (purse) {
Copy link
Member

Choose a reason for hiding this comment

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

remove disabled code

await getBrandPetNameAndDisplayInfoWithoutPurse(
watcher,
amount.brand,
);
);
console.log("GYT")
Copy link
Member

Choose a reason for hiding this comment

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

remove

@@ -402,7 +404,10 @@ export const makeWalletBridgeFromFollowers = (
// If we ever add non 'set' amount purses that aren't in the vbank, it's
// not currently possible to read their decimalPlaces, so this code
// will need updating.
if (!Array.isArray(purse.balance.value)) {

const isCopyBag = endoIsCopyBag(purse.balance.value);
Copy link
Member

Choose a reason for hiding this comment

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

that it comes from Endo isn't semantically meaningful. please omit from the name.

I think the bar should be high for renaming an import so I'd suggest keeping the imported name and using a different name for the boolean.

otherwise import the function as something meaningful like isCopyBagValue.

watcher: ChainStorageWatcher,
brand: Brand,
) => {
const brandsP = watcher.queryOnce<[string, unknown][]>([
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 used to be in the top-level of offer service so it's queried one time, but now it's queried for every proposal entry. Consider moving it back so it can be memoized.


const [brands, boardAux] = await Promise.all([
brandsP,
watcher.queryBoardAux<{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similarly here, consider memoizing the boardAux for each brand.

@@ -109,26 +141,34 @@ export const getOfferService = (
return Object.fromEntries(entries);
};

const readDisplayInfo = async (entry: PurseDisplayInfo) => {
mustMatch(harden(entry.amount), CapDataShape, 'amount');
Copy link
Member

Choose a reason for hiding this comment

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

Why enforce the shape here instead of deferring to the marshaller what it will accept?

@iomekam iomekam requested a review from turadg September 20, 2023 20:08
Copy link
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

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

No blockers. I trust you'll use "squash" to merge.

const value = String(entry.value);
return [kw, { pursePetname, value }];
}),
await Promise.all(
Copy link
Member

Choose a reason for hiding this comment

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

I think that refactoring makes sense to apply here too, but not a blocker

@iomekam iomekam merged commit fcf2b73 into main Sep 21, 2023
@iomekam iomekam deleted the nft-wallet-app branch September 21, 2023 02:41
iomekam added a commit that referenced this pull request Sep 21, 2023
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.

Non-fungible ERTP assets displayed incorrectly in incoming offers
5 participants