Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- changed: WalletConnect Connect button pinned to the bottom of Confirm Connection
- fixed: A send whose funds are not spendable yet says so instead of reporting a network error
- fixed: A swap retried after a failure fetches a fresh quote instead of failing with a "closed proxy" error
- fixed: WalletConnect Bitcoin message signing returns a BIP-322 signature when the dapp requests `bip322`
- fixed: Auto-login starting two competing accounts when both `YOLO_PASSWORD` and `YOLO_PIN` are set, and attempting a login when either is set to an empty string.
- fixed: Auto-login never running on a device with no accounts, since the welcome carousel took priority over the login scene that owns it.
- fixed: USDC.e shown as USDC in the Optimism Tarot staking pools
Expand Down
13 changes: 9 additions & 4 deletions src/components/modals/WcSignMessageModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ interface Props {
dAppIcon: string
dAppName: string
message: string
/** The bip122 signing protocol the dapp asked for. */
protocol: 'ecdsa' | 'bip322'
/** The address the session advertised, which is the one the dapp verifies
* the signature against. */
publicAddress: string
Expand All @@ -47,6 +49,7 @@ export const WcSignMessageModal: React.FC<Props> = props => {
dAppIcon,
dAppName,
message,
protocol,
publicAddress,
requestId,
topic,
Expand All @@ -70,12 +73,14 @@ export const WcSignMessageModal: React.FC<Props> = props => {
try {
// `signMessage` signs the literal UTF-8 message, which is what the dapp
// verifies. `signBytes` would base64-re-encode first and sign the wrong
// data. BIP137 encodes the signing address' script type in the header
// byte, which SegWit verifiers require and which collapses to the legacy
// encoding for non-SegWit addresses.
// data. For `ecdsa`, BIP137 encodes the signing address' script type in
// the header byte, which SegWit verifiers require and which collapses to
// the legacy encoding for non-SegWit addresses. `bip322` is the BIP-322
// simple signature, a witness stack rather than a recoverable signature.
const signatureFormat = protocol === 'bip322' ? 'bip322' : 'bip137'
// eslint-disable-next-line @typescript-eslint/no-deprecated
const signatureBase64 = await wallet.signMessage(message, {
otherParams: { publicAddress, signatureFormat: 'bip137' }
otherParams: { publicAddress, signatureFormat }
})
await walletConnect.approveRequest(topic, requestId, {
address: publicAddress,
Expand Down
38 changes: 27 additions & 11 deletions src/components/services/WalletConnectService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import '@walletconnect/react-native-compat'
import { Core } from '@walletconnect/core'
import type { SessionTypes } from '@walletconnect/types'
import Web3Wallet, { type Web3WalletTypes } from '@walletconnect/web3wallet'
import { asNumber, asObject, asOptional, asString, asUnknown } from 'cleaners'
import {
asNumber,
asObject,
asOptional,
asString,
asUnknown,
asValue
} from 'cleaners'
import type { EdgeAccount, EdgeCurrencyWallet } from 'edge-core-js'
import * as React from 'react'

Expand All @@ -17,7 +24,7 @@ import {
walletConnectClient
} from '../../hooks/useWalletConnect'
import { globalKeys } from '../../keys'
import { asLegacyTokenId } from '../../types/types'
import { asEdgeTokenId } from '../../types/types'
import { snooze } from '../../util/utils'
import { readActiveSessionWallets } from '../../util/walletConnectSessionStore'
import { WcSignMessageModal } from '../modals/WcSignMessageModal'
Expand Down Expand Up @@ -69,16 +76,20 @@ export const WalletConnectService: React.FC<Props> = props => {
return
}
case 'signMessage': {
const { account: requestedAccount, message } =
asBip122SignMessageParams(payload.params)
const {
account: requestedAccount,
address: requestedAddress,
message,
protocol
} = asBip122SignMessageParams(payload.params)
// A dapp may name the account it wants signed for, as the bare address
// or as the CAIP-10 account the session gave it. Edge holds one
// address per session, so anything else is unservable.
if (
requestedAccount != null &&
requestedAccount !== publicAddress &&
requestedAccount !== sessionAccount
) {
const isServable = (requested: string | undefined): boolean =>
requested == null ||
requested === publicAddress ||
requested === sessionAccount
if (!isServable(requestedAccount) || !isServable(requestedAddress)) {
await walletConnect.rejectRequest(topic, requestId)
return
}
Expand All @@ -93,6 +104,7 @@ export const WalletConnectService: React.FC<Props> = props => {
dAppIcon={dAppIcon}
dAppName={session.peer.metadata.name}
message={message}
protocol={protocol}
publicAddress={publicAddress}
requestId={requestId}
topic={topic}
Expand Down Expand Up @@ -251,7 +263,8 @@ export const WalletConnectService: React.FC<Props> = props => {
const payloadAmounts = asObject({
nativeAmount: asString,
networkFee: asString,
tokenId: asLegacyTokenId
// Some chains' payload parsers omit tokenId for the native asset.
tokenId: asOptional(asEdgeTokenId, null)
})
const asSessionRequest = asObject({
id: asNumber,
Expand All @@ -267,5 +280,8 @@ const asBip122Payload = asObject({
})
const asBip122SignMessageParams = asObject({
message: asString,
account: asOptional(asString)
account: asOptional(asString),
address: asOptional(asString),
// The bip122 spec defaults to ECDSA when the dapp names no protocol.
protocol: asOptional(asValue<['ecdsa', 'bip322']>('ecdsa', 'bip322'), 'ecdsa')
})
Loading