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

migrate: swaps #468

Merged
merged 2 commits into from
Dec 13, 2024
Merged

migrate: swaps #468

merged 2 commits into from
Dec 13, 2024

Conversation

sentientforest
Copy link
Contributor

Migrate Token Swap features from assets-chaincode to public sdk

From the beginning, at least the start of my time on November 1, 2021, GalaChain has planned to support and included an implementation of peer-to-peer token
swapping.

This feature has been migrated, updated, and
refined through many refactorings and
changes in chaincode architecture. Many hands
contributed to this feature. It is only
now getting migrated to the public sdk for
wider use, due to various competing demands
throughout 2024. Finally, with
this commit, the remainder of the swap
implementation will be provided with the developer sdk.

Migrate Token Swap features from assets-chaincode to public sdk

From the beginning, at least the start of my time on
November 1, 2021, GalaChain has planned to support and
included an implementation of peer-to-peer token
swapping.

This feature has been migrated, updated, and
refined through many refactorings and
changes in chaincode architecture. Many hands
contributed to this feature. It is only
now getting migrated to the public sdk for
wider use, due to various competing demands
throughout 2024. Finally, with
this commit, the remainder of the swap
implementation will be provided with the developer sdk.
@sentientforest
Copy link
Contributor Author

Related to #443, item 8)

@sentientforest sentientforest merged commit ae61f58 into GalaChain:main Dec 13, 2024
13 checks passed
): Promise<TokenSwapFill[]> {
const params = dto.swapDtos.map((d) => ({
swapRequestId: d.swapRequestId,
filledBy: asValidUserAlias(d.filledBy ?? ctx.callingUser),
Copy link
Collaborator

Choose a reason for hiding this comment

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

we should use await resolveUserAlias(ctx, d.filledBy). The case is resolveUserAlias searcher in chain state if a given user is registered. This way you can provide valid user ref as filledBy, and it will find proper alias (like it will find client|abc for some provided eth address)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also I think it's worth checking if the following pattern applies to swap features:

  • For DTOs use UserRef
  • Do the resolveUserAlias in contract methods
  • For swap functions params use UserAlias (unambiguous)

For instance a few lines below there is:

return fetchTokenSwapsOfferedByUser(ctx, { ...dto, user: dto.user ?? ctx.callingUser });

Which suggests that dto.user is UserAlias, and it could be UserRef, and the function call could be something like:

return fetchTokenSwapsOfferedByUser(ctx, { ...dto, user: dto.user ? await resolveUserAlias(ctx, dto.user) : ctx.callingUser });

Comment on lines +33 to +40
function acceptNotFoundError(e: Error) {
const chainError = ChainError.from(e);
if (chainError.matches(ErrorCode.NOT_FOUND)) {
return null;
} else {
throw chainError;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

We have a built it function for that and the call:

acceptNotFoundError(e)

can be replaced with:

ChainError.ignore(e, ErrorCode.NOT_FOUND)`

Comment on lines +48 to +49
let noOp = true;
const writes: ChainObject[] = [];
Copy link
Collaborator

Choose a reason for hiding this comment

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

isn't noOp an equivalent of !writes.length?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Technically yes, it appears that way.

However I'm not sure if GalaSwap/Connect or other consumers are relying on this boolean being present in the response, so I would be hesitant to change it without looking into that.

The scope of the initial task was just to migrate code as-is, so I've left this as I found it.

Comment on lines +24 to +32
let tokenSwap: TokenSwapRequest;

try {
tokenSwap = await getObjectByKey(ctx, TokenSwapRequest, swapRequestId);
} catch (error) {
throw new Error(`Token swap with swapRequestId ${swapRequestId} not found.`);
}

return tokenSwap;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
let tokenSwap: TokenSwapRequest;
try {
tokenSwap = await getObjectByKey(ctx, TokenSwapRequest, swapRequestId);
} catch (error) {
throw new Error(`Token swap with swapRequestId ${swapRequestId} not found.`);
}
return tokenSwap;
return await getObjectByKey(ctx, TokenSwapRequest, swapRequestId);

why:

  1. The error thrown indicates "not found" even if the underlying error in getObjectByKey is different
  2. Error misses some useful properties that ChainError (thrown from getObjectByKey) has, like mapping to http 404.

I also don't think we need a custom error type for that function

Comment on lines +67 to +72
const swapRequestIds = Array.from(
new Set(
instancesOffered.results.map((instanceOffered) => {
return instanceOffered.swapRequestId;
})
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const swapRequestIds = Array.from(
new Set(
instancesOffered.results.map((instanceOffered) => {
return instanceOffered.swapRequestId;
})
)
const swapRequestIds = Array.from(new Set(instancesOffered.results.map((i) => i.swapRequestId));

Comment on lines +250 to +252
// todo: unsure why verifyAndUseAllowances() requires *both* the tokenInstanceKey and tokenInstance be supplied -
// its code appears to just need the string properties not the actual TokenInstance off chain
// that might be worth reworking in the future
Copy link
Collaborator

Choose a reason for hiding this comment

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

could you gather all of those problematic TODOs, and create a new issue for them? I believe it's a good way of enforcing more thorough review (by doing) of the business logic behind swaps

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree, I have written up a new issue here:

#470

It summarizes both high level goals of a review/refactor given new features introduced in the SDK since it was originally written, and it summarizes your comments on this pull request into a bulleted list.

Comment on lines +103 to +105
// 2023-11-16: added txid as new chain key because timestamp alone may not be precise enough to ensure uniqueness
// todo: determine if it would be straightforward to remove created as a ChainKey() from the TokenSwapRequest object
// i.e. if this feature has never been used in production, it could be easy
Copy link
Collaborator

Choose a reason for hiding this comment

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

probably this comment needs some update

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.

3 participants