Skip to content

Conversation

@peachbits
Copy link
Contributor

@peachbits peachbits commented Nov 24, 2025

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

EdgeApp/edge-core-js#688

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)

Note

Replaces currencyCode-based logic with tokenId across state, selectors, actions, UI, staking/loans/ramps/providers, and bumps edge-core-js; also restructures FIO state and recent wallet tracking.

  • Core/state:
    • Replace currencyCode with tokenId in actions, reducers, navigation params, and settings init; remove UI/WALLETS selected wallet/currency reducers; move fioWallets to ui.fio and add UPDATE_FIO_WALLETS.
    • Update recent wallets to store { id, tokenId }.
  • Selectors/utils:
    • Deprecate/remove getCurrencyCodeMultiplier and selectDisplayDenomByCurrencyCode; use getExchangeDenom everywhere.
    • Update CryptoAmount, currency helpers, and fiat/crypto conversions to use tokenId.
  • UI/components:
    • Convert props/flows to tokenId (AddressTile2, Tx rows, SwapDetailsCard upgrade, SendScene2, EdgeProviderComponent, WalletList, DevTestScene, staking/coins scenes).
    • Simplify custom token add flow (remove builtin override warning).
  • Staking/Loans:
    • Propagate tokenId through staking policies/adapters; enable tokens via enableTokens; add LOAN_TOKEN_IDS and use in loan scenes.
  • Fiat ramps/providers:
    • Update all providers (Banxa, Moonpay, Paybis, etc.) to compute amounts via getExchangeDenom and pass tokenId to CryptoAmount and spend flows.
  • Tests:
    • Adjust tests/snapshots to tokenId usage and FIO state path.
  • Dependencies:
    • Bump edge-core-js to 2.36.0 (local); update Podfile.lock.

Written by Cursor Bugbot for commit f442403. This will update automatically on new commits. Configure here.


plugin,
refundAddress
} = swapData
} = upgradeSwapData(wallet, swapData)
Copy link

Choose a reason for hiding this comment

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

Bug: Wrong wallet passed to upgradeSwapData function

The upgradeSwapData function is called with wallet (the source wallet) instead of destinationWallet (the payout wallet). This causes the function to look up payoutTokenId or payoutCurrencyCode in the wrong wallet's currency configuration, potentially returning incorrect token information for the swap destination asset.

Fix in Cursor Fix in Web

"detect-bundler": "^1.1.0",
"disklet": "^0.5.2",
"edge-core-js": "^2.35.0",
"edge-core-js": "file:../edge-core-js",
Copy link

Choose a reason for hiding this comment

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

Bug: Local file dependency in package.json

The edge-core-js dependency is changed to "file:../edge-core-js", which is a local file reference for development. This breaks the build for anyone without that specific directory structure and should not be committed to the repository. The dependency should reference a published version or a git URL instead.

Fix in Cursor Fix in Web

Copy link
Contributor

@swansontec swansontec left a comment

Choose a reason for hiding this comment

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

I notice that this PR doesn't update ESLint exceptions, so edited files might have leftover warnings. This is fine for a change of this magnitude, but it might cause problems in the merge-to-staging and merge-to-master, where we need to turn of the precommit thing as part of the merge. Just something to be aware of.

Comment on lines +1889 to +1895
const currencyCode = getCurrencyCode(
{
currencyConfig,
currencyInfo: currencyConfig.currencyInfo
} as unknown as EdgeCurrencyWallet,
tokenId
)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is fine. We need to fix getCurrencyCode to take EdgeCurrencyConfig instead of EdgeCurrencyWallet.

The need to fix getCurrencyCode becomes more urgent, but I think this is a good motivation / reminder to do this soon.

Comment on lines +1899 to +1900
const contractAddress = `0x${tokenId}`.toLocaleUpperCase()
return `${asset}-${contractAddress}`
Copy link
Contributor

Choose a reason for hiding this comment

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

This does not work in general, since different chains use different contract address mappings. We should add a comment that this is EVM-only (which is fine because Coreum is EVM).

Copy link
Contributor Author

@peachbits peachbits Dec 2, 2025

Choose a reason for hiding this comment

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

My understanding is that the only tokens supported on tcsavers were evm tokens, but regardless it's a dead staking plugin.

const tokenId =
contractAddress == null
? null
: contractAddress.toLowerCase().replace('0x', '')
Copy link
Contributor

Choose a reason for hiding this comment

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

Same deal here - this conversion is EVM only, so we need a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as the other tcsavers plugin. It's dead and should be pared down to tcy functionality only.


return `${asset}-${contractAddress.toLocaleUpperCase()}`
if (tokenId != null) {
const contractAddress = `0x${tokenId}`.toLocaleUpperCase()
Copy link
Contributor

Choose a reason for hiding this comment

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

Also needs a comment about being EVM only.

const { multiplier } = getExchangeDenom(
coreWallet.currencyConfig,
displayCurrencyCode
)
Copy link

Choose a reason for hiding this comment

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

Bug: Passing currencyCode instead of tokenId to getExchangeDenom

The getExchangeDenom function expects an EdgeTokenId (contract address string or null) but is being passed displayCurrencyCode (a currency code like "BTC" or "USDT"). This type mismatch causes the function to fail to find the token in allTokens and return emptyEdgeDenomination with multiplier "1", resulting in incorrect native amount calculations for token transactions.

Additional Locations (2)

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we need to pass the tokenId here.

const tokenId = selectedWallet?.tokenId ?? null
const { id: walletId, tokenId } = useSelector(
state => state.ui.settings.mostRecentWallets[0]
)
Copy link

Choose a reason for hiding this comment

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

Bug: Potential crash accessing empty mostRecentWallets array

The code destructures state.ui.settings.mostRecentWallets[0] directly without checking if the array is empty. When a new user has no recent wallets, accessing index [0] returns undefined, and destructuring { id: walletId, tokenId } from undefined will throw a runtime error. This scene will crash for users with no recent wallet history.

Fix in Cursor Fix in Web

Copy link
Contributor

Choose a reason for hiding this comment

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

If the most recent wallets array is empty, the selector will definitely crash. Adding a simple ?? { walletId: '', tokenId: null } to the selector would solve this.

}
onAmountsChanged={() => {}}
onMaxSet={handleMaxButtonPress(currencyCode)}
onMaxSet={handleMaxButtonPress(tokenId, currencyCode)}
Copy link

Choose a reason for hiding this comment

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

Bug: Missing tokenId when updating changeQuoteRequest in StakeModifyScene

When updating changeQuoteRequest after the user enters an amount via FlipInputModal, only currencyCode and nativeAmount are set, but tokenId is not included despite being available in the closure scope. Similarly, the useEffect that initializes the request for claim/liquidStaking/mustMaxUnstake cases sets currencyCode and nativeAmount but omits tokenId from stakePolicy.rewardAssets[0].tokenId. This causes changeQuoteRequest.tokenId to remain at its initial value of null, leading to incorrect behavior when staking tokens rather than native assets.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link
Contributor

@swansontec swansontec left a comment

Choose a reason for hiding this comment

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

One more round of fixes needed, but we are getting close!

const { multiplier } = getExchangeDenom(
coreWallet.currencyConfig,
displayCurrencyCode
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we need to pass the tokenId here.


const { multiplier } = getExchangeDenom(
coreWallet.currencyConfig,
displayCurrencyCode
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to pass the tokenId here too.

)
const { multiplier } = getExchangeDenom(
coreWallet.currencyConfig,
displayCurrencyCode
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 be a tokenId.

export const asMostRecentWallet = asObject({
id: asString,
currencyCode: asString
tokenId: asEdgeTokenId
Copy link
Contributor

@swansontec swansontec Dec 3, 2025

Choose a reason for hiding this comment

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

We can't really change this without blowing away user settings - no good! We are kinda stuck with the way the data is.

Idea: Keep the data as-is, lookup the wallet by its walletId, and then search through enabled tokens to find a matching currency code. Then store the walletId + tokenId in memory. This keeps the data the same on disk, and even if the app has multiple tokens of the same name, it won't be a problem unless the user has them both enabled.

Once we have this migration code, we can optionally write the data back to disk as walletId + tokenId, and the migration will be complete. Or just leave it as-is and rely on the enabledTokenId search - it's fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We'd only be losing the mostRecentWallets as it's guarded by asMaybe. I think that is ok?

const tokenId = selectedWallet?.tokenId ?? null
const { id: walletId, tokenId } = useSelector(
state => state.ui.settings.mostRecentWallets[0]
)
Copy link
Contributor

Choose a reason for hiding this comment

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

If the most recent wallets array is empty, the selector will definitely crash. Adding a simple ?? { walletId: '', tokenId: null } to the selector would solve this.

>()
const paymentCurrencyCode =
activationPaymentInfo?.tokenId !== undefined
? getCurrencyCode(existingWallet, activationPaymentInfo?.tokenId)
Copy link

Choose a reason for hiding this comment

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

Bug: Wrong wallet used for payment currency lookup

The getCurrencyCode and getExchangeDenom calls use existingWallet (the wallet being activated) instead of the payment wallet to look up the payment currency. The tokenId in activationPaymentInfo refers to the payment currency (e.g., BTC), but looking it up on the existing wallet (e.g., EOS) would return the wrong currency code and denomination. For example, if activating an EOS wallet by paying with BTC, this would display "EOS" instead of "BTC" for the payment currency.

Additional Locations (1)

Fix in Cursor Fix in Web

@peachbits peachbits force-pushed the matthew/sans-currency-code branch from d8be217 to f442403 Compare December 4, 2025 22:19
}

return swapData
}
Copy link

Choose a reason for hiding this comment

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

Bug: upgradeSwapData mutates props causing React anti-pattern

The upgradeSwapData function directly mutates the swapData object passed as a prop (swapData.payoutTokenId = ...). This is a React anti-pattern that can cause unexpected behavior, as props should be treated as immutable. The function should create a new object with the updated property instead of modifying the input object directly.

Fix in Cursor Fix in Web

export const asMostRecentWallet = asObject({
id: asString,
currencyCode: asString
tokenId: asEdgeTokenId
Copy link

Choose a reason for hiding this comment

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

Bug: mostRecentWallets data migration causes user data loss

The asMostRecentWallet cleaner was changed from expecting { id, currencyCode } to { id, tokenId }. Existing user data stored with currencyCode will fail to parse when loaded, causing asMaybe to fall back to an empty array. This silently erases the user's most recent wallets list when they upgrade. The PR discussion shows the reviewer suggested a migration approach to preserve the data, but this cleaner change does not include migration logic.

Fix in Cursor Fix in Web

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