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(wallet): support CoW 🐮 orders in Safe Sign #20203

Merged
merged 6 commits into from
Sep 25, 2023
Merged

Conversation

onyb
Copy link
Member

@onyb onyb commented Sep 18, 2023

Summary of changes:

  • Add support for parsing EIP-712 messages for CoW orders, and render the parsed fields in the Safe Sign UI previously designed for 0x swaps.
  • Add support for unknown tokens in Safe Sign UI.

Resolves brave/brave-browser#33093

Submitter Checklist:

  • I confirm that no security/privacy review is needed and no other type of reviews are needed, or that I have requested them
  • There is a ticket for my issue
  • Used Github auto-closing keywords in the PR description above
  • Wrote a good PR/commit description
  • Squashed any review feedback or "fixup" commits before merge, so that history is a record of what happened in the repo, not your PR
  • Added appropriate labels (QA/Yes or QA/No; release-notes/include or release-notes/exclude; OS/...) to the associated issue
  • Checked the PR locally:
    • npm run test -- brave_browser_tests, npm run test -- brave_unit_tests wiki
    • npm run lint, npm run presubmit wiki, npm run gn_check, npm run tslint
  • Ran git rebase master (if needed)

Reviewer Checklist:

  • A security review is not needed, or a link to one is included in the PR description
  • New files have MPL-2.0 license header
  • Adequate test coverage exists to prevent regressions
  • Major classes, functions and non-trivial code blocks are well-commented
  • Changes in component dependencies are properly reflected in gn
  • Code follows the style guide
  • Test plan is specified in PR before merging

After-merge Checklist:

Test Plan:

👉 Case A: CoW Swap trade

Before After

👉 Case B: CoW Swap trade with custom recipient

Before After

It's also possible to view the raw message by clicking on the Details button.

👉 Case C: CoW swap trade selling native asset (ETH on Ethereum, XDAI on Gnosis)

⚠️ These trades cost gas, since they are real transactions. Also, we do not have the ability to display custom recipients in this case, for the time being.

Before After

👉 Case D: 0x Swap involving unknown tokens

Before After

@onyb onyb requested a review from a team as a code owner September 18, 2023 15:12
@onyb onyb self-assigned this Sep 18, 2023
@onyb onyb requested review from a team as code owners September 18, 2023 15:12
@github-actions github-actions bot added CI/storybook-url Deploy storybook and provide a unique URL for each build feature/web3/wallet feature/web3/wallet/core labels Sep 18, 2023
Copy link
Collaborator

@supermassive supermassive left a comment

Choose a reason for hiding this comment

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

wallet core lgtm

Copy link
Collaborator

@mkarolin mkarolin left a comment

Choose a reason for hiding this comment

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

strings++

@onyb onyb force-pushed the f/wallet/cowswap branch 2 times, most recently from 2380d1c to 4fb5ec0 Compare September 20, 2023 09:37
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@kdenhartog
Copy link
Member

Just working on some dynamic testing on swap.cow.fi. I'm not seeing either of the before or after screens being presented when running this dev branch. It's still showing all the old UI for me. Is there a flag that needs to be enabled for this to work?

Screenshot 2023-09-21 at 11 45 04 AM

@kdenhartog
Copy link
Member

0x swaps are still working good for me though. Ignore the network fee not showing, I'm fairly certain that's because I don't have an API key I need enabled.

Screenshot 2023-09-21 at 11 51 04 AM

Comment on lines 2971 to 2973
if (!decimals) {
throw new Error(errorMessage)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we check for the error message presence instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Comment on lines 3009 to 3011
if (!symbol) {
throw new Error(errorMessage)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldnt we just check if there is an error message?

Copy link
Member Author

Choose a reason for hiding this comment

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

// Hooks
import { useAccountOrb, useAddressOrb } from '../../../common/hooks/use-orb'

const makeUnknownToken = (
Copy link
Contributor

Choose a reason for hiding this comment

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

how about?

Suggested change
const makeUnknownToken = (
const UNKOWN_TOKEN = (

Copy link
Member Author

Choose a reason for hiding this comment

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

I think makeUnknownToken makes more sense since it is a function. I'd use UNKNOWN_TOKEN for a constant.

Comment on lines 185 to 196
const buyTokenResult = makeToken(
buyToken,
buyAssetNetwork,
buyTokenSymbol,
buyTokenDecimals
)
const sellTokenResult = makeToken(
sellToken,
sellAssetNetwork,
sellTokenSymbol,
sellTokenDecimals
)
Copy link
Contributor

Choose a reason for hiding this comment

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

memoize these objet to prevent re-renders of child components

Copy link
Member Author

Choose a reason for hiding this comment

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

@onyb
Copy link
Member Author

onyb commented Sep 21, 2023

@kdenhartog You need to wrap ETH into WETH in order to benefit from gasless swaps using EIP-712 messages. If you select ETH as your sell asset, you'll need to pay for gas fees - which is actually wrapping it into WETH behind the scenes.

@StephenHeaps also had the same feedback by the way. We should handle this case the same way we parse 0x calldata into the ETHSwap transaction type. I'm currently working with the CoW team to implement a calldata parser for this particular case.

Copy link

@anxolin anxolin left a comment

Choose a reason for hiding this comment

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

Amazing! this looks slick.

I just checked the PR. I wouldn't mind trying it out, do you think is easy for me to run this locally?

string buy_token;
string buy_amount;
string receiver;
string deadline;
Copy link

Choose a reason for hiding this comment

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

I would suggest adding the feeAmount and kind (that can be either sell or buy)
And maybe partiallyFillable

see:
https://github.com/cowprotocol/contracts/blob/5c25837f585d79dc5450fb80f66c41f596c3198d/src/ts/order.ts#L151

Copy link

Choose a reason for hiding this comment

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

Or this is just for the view that shows the basic params, and the rest are visible in the details?

Copy link
Member Author

Choose a reason for hiding this comment

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

Or this is just for the view that shows the basic params, and the rest are visible in the details?

That's right. I think we'll need to extend the current design to accommodate for those extra fields. Would be a good next step for us to make the signing screen even more informative.

}
]
}),
getEthTokenSymbol: query<
Copy link

Choose a reason for hiding this comment

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

I see you get decimals, symbol. You might want to consider fetching the name as well

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh I didn't know name was also part of the ERC20 interface. Good to know! We don't need the token name for this particular case (it doesn't get displayed), but I'll add it another PR.

Copy link

Choose a reason for hiding this comment

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

yep, it is, although is optional (although most contracts have them).

image

Not sure if your provider accounts for it, but there's some contracts that implement these methods but return bytes instead of the string. One that comes to mind is SAI, so I would try this out. They have different ABI for the same method, technically they don't respect the standard, but most dapps handle this case.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the info. Created an issue to track this: brave/brave-browser#33162


// set to true once Swap+Send is supported
expectRecipientAddress={false}
/>
Copy link

Choose a reason for hiding this comment

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

nice refactor! ❤️

senderLabel={senderLabel}
senderOrb={senderOrb}
recipientOrb={recipientOrb}
recipientLabel={recipientLabel}
Copy link

Choose a reason for hiding this comment

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

Probably out of scope for this PR, but, one thing that would help with the security is to show a warning if the receiver account and the signing account is not the same (or is not 0x0, since that in the smart contract refers to the owner of the funds).

Changing the receiver is a great CoW Swap feature, it allows you to SWAP and send in one operation. However, i think is nice to make the user aware the destination of the funds is different than the origin of them

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed that's a good point. The addresses should also link to the explorer. Will take inputs from the design team for a future iteration.

Copy link
Member

Choose a reason for hiding this comment

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

++ seems like a good follow up item

Adds support for parsing EIP-712 messages for CoW orders, and
renders the information in the Safe Sign UI previously designed
for 0x swaps.
@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

Copy link
Collaborator

@StephenHeaps StephenHeaps left a comment

Choose a reason for hiding this comment

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

iOS++.

iOS will get ETHSwap UI for free 🔥:

And I've opened brave/brave-ios#8114 for integrating the Safe Sign UI with this signature request on iOS.

@brave-builds
Copy link
Collaborator

A Storybook has been deployed to preview UI for the latest push

Copy link
Contributor

@josheleonard josheleonard left a comment

Choose a reason for hiding this comment

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

desktop frontend ++

Copy link
Member

@kdenhartog kdenhartog left a comment

Choose a reason for hiding this comment

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

Just one blocking question to confirm we aren't introducing a casting issue - rest seems like good follow up issues.

senderLabel={senderLabel}
senderOrb={senderOrb}
recipientOrb={recipientOrb}
recipientLabel={recipientLabel}
Copy link
Member

Choose a reason for hiding this comment

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

++ seems like a good follow up item

@@ -341,6 +342,55 @@ GetTransactionInfoFromData(const std::vector<uint8_t>& data) {
"uint128", // sell amount
"uint128"}, // buy amount
tx_args);
} else if (selector == kCowOrderSellEthSelector) {
Copy link
Member

Choose a reason for hiding this comment

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

This function could use a bit of refactoring. It's starting to get pretty complex for a parsing function that's handling untrusted data supplied by a page. Given that an error in this logic can easily lead to a rule of 2 violation we should split this up better.

Let's do a follow up issue for this.

Copy link
Member

@kdenhartog kdenhartog left a comment

Choose a reason for hiding this comment

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

LGTM for the one sec concern I had

@onyb onyb merged commit 617a068 into master Sep 25, 2023
15 checks passed
@onyb onyb deleted the f/wallet/cowswap branch September 25, 2023 11:17
@github-actions github-actions bot added this to the 1.60.x - Nightly milestone Sep 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI/storybook-url Deploy storybook and provide a unique URL for each build feature/web3/wallet/core feature/web3/wallet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Safe Sign support for CoW 🐮 orders
8 participants