Repository navigation
chore(root): publish modules - #9956
Closed
davidkaplanbitgo wants to merge 58 commits into
Closed
davidkaplanbitgo wants to merge 58 commits into
davidkaplanbitgo wants to merge 58 commits into
Conversation
Adds an optional, failure-isolated progressCallback to changePassword() so callers (e.g. bitgo-retail's account-password dialog) can surface truthful indeterminate progress through v1/v2 keychain re-encryption and a finalizing phase, instead of a silent multi-minute operation. - sdk-core: KeychainPasswordUpdateProgress/-Callback on UpdatePasswordOptions; v1 and v2 updatePassword() emit one updated/skipped outcome per nonfatal keychain, observer exceptions are isolated and never affect rotation results or abort on fatal errors. - sdk-api: PasswordRotationProgress/-Callback on ChangePasswordOptions; BitGoAPI.changePassword() aggregates lower-level outcomes into a single keychains/started -> keychains/updated* -> finalizing/started -> finalizing/completed lifecycle with monotonic counters, without changing the existing batching/legacy POST fallback contract. - Unit tests cover v1/v2 outcome ordering, missing-encryptedPrv and known-decrypt-failure skips, unchanged fatal-error propagation, event-order/counter assertions, callback-throws isolation, and the batching-check-failure / batching-POST-failure / retry contracts. Ticket: WCN-2084
…progress Completes the WCN-2084 progress contract by giving the password-rotation callback a truthful denominator and fixing the counting unit. sdk-core: capture `encryptedTotalCount` from the first v2 key-list page and pass it through every progress event. Records without an `encryptedPrv` no longer emit progress at all. sdk-api: forward `total` from the lower-level keychain callbacks into the aggregated `PasswordRotationProgress` events. Denominator decision (the choice WCN-2084's scope doc left to product/SDK owners): option B, "encrypted wallet keychains". The unit is keychain records that hold encrypted user key material, matching the backend's `encryptedTotalCount`, which counts `users[]` entries with `encryptedPrv` set. The alternative, "records inspected", was rejected: it would count placeholder key records that no rotation ever touches. Emitting progress for those while the backend excluded them made `completed` overshoot `total` — an account with 50 key records of which 32 are encrypted rendered "50 of 32". Records that do hold ciphertext but fail to decrypt still emit `skipped`, so the counter always reaches the denominator exactly. Tests: v2 key without `encryptedPrv` emits nothing and keeps `total` intact; existing ordering, pagination, decrypt-failure, callback-exception, and finalization coverage unchanged. Ticket: WCN-2084
The changePassword progress counters are shared across the v1 and v2 sets, but the total came only from the v2 list's encryptedTotalCount — a mixed account with 2 SJCL and 32 v2 keychains finished the counter at 34 of 32. The v1 set has no server-provided count, but its size is knowable client side: every /user/encrypted entry emits exactly one progress event, so the returned re-encryption map's size is the v1 contribution. Captured after the v1 pass and added to every v2 event's total, so the mixed account above completes at 34 of 34, exactly. v1 events stay indeterminate: surfacing the client-side v1 count mid-flight would make the denominator jump the moment v2's server count arrives, and a denominator that moves is worse than none. When the backend supplies no encryptedTotalCount the total stays undefined — never fabricated. Test: the 2 v1 + 32 v2 account now asserts v1 events indeterminate, v2 events at total 34, and the final event at completed 34 of total 34; the total-forwarding test accounts for the combined denominator. Ticket: WCN-2084
Review follow-up: an account with only v1 keychains never receives a v2 event, so the total stayed undefined for the whole rotation and the observer could never render "n of n". After the v2 walk completes with zero events, emit one terminal keychains/updated event carrying the client-known v1 set size as the denominator (2 of 2), immediately before finalizing. Guarded on v2EventCount === 0 so mixed accounts keep the single stable total from encryptedTotalCount — surfacing the v1 size unconditionally would make the denominator jump mid-rotation (2 of 2, then 34 of 34). Also rebases onto latest master, where the safe-mode password rotation landed in sdk-core (safeId on UpdatePasswordOptions, batch persistence via PUT /api/v2/key/bulk). The UpdatePasswordOptions conflict resolves additively: progressCallback remains a legacy-mode observer and the safe-mode walk does not invoke it. Local suites: sdk-api bitgoAPI 74 passing; my keychain progress tests in modules/bitgo v1 (2) and v2 (4) passing. Pre-existing master-side failures in modules/bitgo's own keychain suites are unchanged by this diff and do not run in PR CI. Ticket: WCN-2084
Review direction (WCN-2084): the total is the generic list count (totalCount from the wallet-platform companion PR), so the walk emits skipped for listed records with no serialized encryptedPrv instead of silently dropping them — completed reaches the total on any account composition, and the SDK no longer needs to know which records the serializer suppresses. Renames the list-result field to totalCount. Ticket: WCN-2084
Document encryptionVersion and progressCallback on changePassword, state that safe mode never invokes the callback, and drop a design label from one comment and one test title. No behavior change. Ticket: WCN-2084
The message-signing policy (DEFI-653) parks signMessage/signTypedStructuredData txRequests behind a pending approval, but the SDK's message-sign paths never inspected the txRequest state: they ran all MPC signing rounds against a parked request and failed at the final send with a wrapped 'Expected transaction request to be in state pendingDelivery' error, leaving the UI unable to recover the pending approval id. After approval, the only retry path (signAndSendTxRequest) signs through the transaction path and crashes on message-only requests (transactions[0].unsignedTx of undefined). - signMessageTss/signTypedDataTss: after create/fetch, resolve the parked request as data instead of attempting to sign, mirroring the tx flow's early return in prebuildAndSignTransaction - SignedMessage: now a discriminated union on the wallet-platform txRequest state — { state: 'pendingApproval'; pendingApprovalId: string } | { state: 'delivered'; txHash: string; signature: string } — so consumers narrow on state instead of inferring from field presence - the surfaced state is derived from the server-reported txRequest state (the signing flow ends with a fresh getTxRequest, which lands after wallet-platform combines and delivers); any state other than 'delivered' at that point throws instead of surfacing a hardcoded value - assert pendingApprovalId on the parked branches of signMessageTss/ signTypedDataTss, matching signAndSendMessageTxRequest - new signAndSendMessageTxRequest({ txRequestId, walletPassphrase }): signs a message txRequest through the message path (WP-persisted messageEncoded as bufferToSign), for resuming a parked request after approval; resolves with the pendingApproval variant if the request is still parked; full txRequests only — lite is deprecated and receives no new features; hot wallets only (server-held encryptedPrv) — cold/external-signer wallets resume via wallet.signMessage with txRequestId and prv - rethrow the original signing errors instead of wrapping them in 'failed to sign message/typed data ...' so downstream callers can classify ApiResponseError results (e.g. the TxRequestPendingApprovalError 409) - sdk-coin-xdc: signXdcKycMessage fails loudly when the KYC sign request is parked behind a pending approval instead of returning an unusable signature-less result BREAKING CHANGE: SignedMessage is now a discriminated union on state. Consumers that previously read txHash or signature unguarded must narrow on state === 'delivered' first: const result = await wallet.signMessage(params); if (result.state === 'pendingApproval') { /* show approval UI */ } else { const { txHash, signature } = result; } Refs: DEFI-1014
Forward explicit SOL single-asset consolidation mode to wallet-platform. Ticket: CHALO-1755
Add createOfflineKeyGenRound2Share to EddsaMPCv2Utils in sdk-core, the
second of the three offline signer methods for the EdDSA MPCv2
external-signer key generation flow.
The method decrypts the persisted round-1 session, restores the DKG
state, verifies and deserializes all 3 incoming round-1 messages (own,
counterParty, BitGo) via MPSComms.verifyMpsMessage, calls
dkg.handleIncomingMessages to produce ownMsg2, signs it with the GPG
private key, and returns { signedMsg2, encryptedRound2Session }.
The round-1 session blob is bound to the caller via validateAdata
before decryption: the optional partyId param (defaulting to USER,
matching createOfflineKeyGenRound1Share) is validated against the
envelope's adata, so a blob encrypted for the other source fails
loudly instead of silently resuming the WASM DKG as the wrong party.
Also fix DKG.restoreSession in sdk-lib-mpc to be async and load WASM
before restoring state (mirrors DSG.restoreSession), which is required
so that handleIncomingMessages works on a restored session.
Ticket: WCI-890
…nalSigner - Add eddsaMPCv2Callbacks to GenerateWalletWithExternalSignerOptions in iWallets.ts - Update hasMpcCallbacks so createKeychainCallback + MPCv2 callbacks is rejected - Add the EdDSA MPCv2 routing branch in generateMpcWalletWithExternalSigner: dispatches to EddsaMPCv2Utils.createKeychainsWithExternalSigner when eddsaMPCv2Callbacks is set; rejects when both eddsaMPCv2Callbacks and eddsaCallbacks are provided; rejects when neither is provided; rejects MPC algorithms without external-signer support (e.g. redpallas) instead of silently routing them to the EdDSA path - Use sinon.stub on the EddsaMPCv2Utils prototype in tests instead of raw assignment + delete, which removed the real method (merged via WCI-916) from the prototype for the rest of the test run - Rebased onto latest master Ticket: WCI-917
…onsolidation feat(sdk): add SOL consolidation mode
V1TransactionBuilder gains fromVersionedData(envelope) (converts the client-supplied index-based envelope to address-based instructions internally via toV1TransactionInstruction), transactionConfig() coerces unset fields to null, and injectV1NonceAdvanceInstruction + the envelope-instruction bridge are public SDK exports — so the WP consumes the builder directly instead of carrying the conversion/injection helpers server-side. Refs: CHALO-1758
problem/goal: clients need authorizeTrustline transaction support. On Stellar, setTrustLineFlags (allow trust) is a low-security operation governed by the account's low threshold, so BitGo is tightening XLM wallet lowThreshold from 1 to 2 signatures to prevent a single client signature from bypassing approval security. The SDK must whitelist lowThreshold (=2) on accountConfig verification so platform-built transactions can be verified, and surface the threshold in explainTransaction output. implementation details: AccountConfigVerifyParams gains an optional lowThreshold, restricted to exactly 2 (mirroring the platform build restriction; med/high/master remain excluded); the accountConfig type guard accepts it; verifyAccountConfigOperations rejects any value other than 2 and compares the parsed setOptions op's lowThreshold against the request; explainTransaction parses lowThreshold into the accountConfig operation. verification: npx mocha test/unit/xlm.ts --grep accountConfig passes (24 tests including lowThreshold match/mismatch/restriction and explain parsing); tsc --noEmit clean. Ticket: CSHLD-1925
Problem/goal: createToken and the token map builders skip any coin already present in the static coin map, so an AMS payload for an existing token can never refresh its modifiable fields (features, fullName, decimalPlaces) without a statics release. Goal: let AMS update known tokens while the fields that define the asset stay immutable. Implementation details: - CoinMap.replace only swaps when the old and new records are both tokens and agree on id, symbol (prefix + suffix), contract address and alias. Otherwise the existing record is kept. Coins not yet in the map are still added. - createToken no longer returns the stale static record. For a known token it constructs the token, calls coins.replace, and returns the record the map holds. A config that fails token validation keeps the existing record instead of throwing. The initializer switch moved into a private constructToken. - createTokenMapUsingConfigDetails mirrors a refreshed token into its rebuilt map. The two trimmed-config gates now only skip known base chains; known tokens flow through the refresh path. Verification: Statics unit suite: 39324 passing, 0 failing. eslint on the changed files: 0 errors. New replace tests cover a matching swap with index lookups by name, id and contract address, and keeping the existing record on a differing symbol, contract address, alias or id and for base coins. The old precedence tests were rewritten to the new contract and the AMS fixture suite restores the global coin map afterwards. Ticket: CSHLD-863
feat(sdk-coin-sol): v1 envelope surface for WP (CHALO-1758)
problem/goal: verifyAccountConfigOperations compared only setFlags,
clearFlags, and lowThreshold. A rebuilt tx resubmitted for approval
could keep those identical while adding masterWeight, medThreshold,
highThreshold, signer, homeDomain, or inflationDest; the wallet
co-signers satisfy highThreshold automatically, so an injected
signer:{attacker,weight:3} would execute under an unchanged approval
and grant the attacker full control of the account.
implementation details: verifyAccountConfigOperations now rejects any
setOptions op carrying a field outside {setFlags, clearFlags,
lowThreshold} — the platform build layer never produces those fields,
so any occurrence is rejected on sight instead of comparing old vs
new values (which could pass if both sides carried the field).
verification: npx mocha test/unit/xlm.ts --grep accountConfig passes
(25 tests, including a new case injecting signer/masterWeight/
medThreshold/highThreshold/homeDomain alongside a matching
lowThreshold and asserting rejection).
Ticket: CSHLD-1925
chore(root): publish modules
…password-test test(sdk-api): pin v1-leg password rotation behavior
Add RecoveryProviderError alongside ErrorNoInputToRecover and retype empty-wallet throws and provider-failure paths across UTXO, EVM, XLM, EOS, SOL, and IOTA so a recovery scanner can distinguish the two by type Ticket: WCN-2892
feat: honest empty vs provider-failed in recover()
…s-indication-for-login-password-rotation feat(sdk-api,sdk-core): add password rotation progress callback with truthful keychain total
…messages feat(sdk-core): sign EdDSA safe MPS VRF keygen messages like the HSM
This is a follow-up to PR #9932 (#9932) which introduced honest "empty vs provider-failed" classification in recover(). This commit closes the loop by applying the same fix to all 17 remaining coin modules (and their abstract bases) that still conflated the two. Key changes across SUI, ADA, NEAR, POLYX, DOT, Substrate base, Cosmos base (and subclasses), XTZ, ICP, VET, HBAR, TRX, ALGO, TON, RUNE, STX, and XRP: - Retype verifiably-empty throws to ErrorNoInputToRecover - Wrap provider query boundaries in RecoveryProviderError - Convert scan loop empty string-match checks to ErrorNoInputToRecover - Add type-based negative assertions and provider-failure tests per coin Ticket: WCN-3036
problem/goal: parity gap with the wallet-platform round-2 review fixes (CSHLD-1925): the platform re-approval gate now rejects per-op source redirects, envelope fee swaps, and timeBounds swaps, but the SDK's unsupported setOptions field list omitted op-level source — a rebuilt tx with source:<attacker> would still pass verifyAccountConfigOperations while every verified field matched. implementation details: 'source' joins the unsupported setOptions fields rejected on sight; the lowThreshold error JSON-stringifies the got-value so wrong-typed input is distinguishable from the valid number. verification: npx mocha test/unit/xlm.ts --grep accountConfig passes (25 tests, including the new op-source injection case); tsc --noEmit clean. Note: fee/timeBounds parity does not map to this layer — verify compares tx-vs-params intent, not old-vs-new txs; the platform re-approval gate owns that comparison. Ticket: CSHLD-1925
…into-generate-wallet-with-external-signer feat(sdk-core): wire eddsaMPCv2Callbacks into generateWalletWithExternalSigner
…und2share feat(sdk-core): add createOfflineKeyGenRound2Share to EddsaMPCv2Utils
feat: PR from asset-metadata-service for token onboardings
Add createOfflineKeyGenFinalizeShare to EddsaMPCv2Utils in sdk-core, completing the three offline signer methods for the EdDSA MPCv2 external-signer key generation flow (WCI-888 plan). The method decrypts the persisted round-2 session, restores the DKG state, reconstructs the own round-2 message from the persisted payload, verifies and deserializes the incoming BitGo and counterParty round-2 messages via MPSComms.verifyMpsMessage, feeds all three into dkg.handleIncomingMessages (asserting no output messages remain), asserts dkg.getCommonKeychain() matches the bitgoCommonKeychain returned by WP round 2 (commonPublicKeychain), and returns { commonKeychain, keyShare } with the full key share base64-encoded. The round-2 session blob is bound to the caller via validateAdata before decryption: the optional partyId param (defaulting to USER, matching the other keygen methods) is validated against the envelope's adata, so a blob encrypted for the other source fails loudly instead of silently finalizing the DKG as the wrong party. Note: unlike the WCI-891 draft signature, this method does not take encryptedUserGpgPrvKey — finalize only verifies peer messages with their public keys and never signs, so the GPG private key is never decrypted on this path. Depends on the async DKG.restoreSession (WASM load) and createOfflineKeyGenRound2Share from the stacked WCI-890 branch. Ticket: WCI-891
…und2share feat(sdk-core): add createOfflineKeyGenFinalizeShare to EddsaMPCv2Utils (reland)
…-threshold CSHLD-1925 feat(sdk-coin-xlm): verify and explain lowThreshold on accountConfig
Structured-params surface (Option B): V1PaymentBuilder builds a v1 (SIMD-0296/0385) native SOL payment envelope from sender + recipients/amounts — the caller supplies fields, never instructions. Named after the payment intent it serves (WP's 'transfer' refers to tokens). Inherits AdvanceNonceAccount injection, message compile, and message-signer-order signature assembly from V1TransactionBuilder. Exposed via TransactionBuilderFactory.getV1PaymentBuilder(). Refs: CHALO-1603
The ERC-7984 wrapper mints floor(amount / rate()) and reverts only when that quotient overflows uint64. assertAmountTimesRateFitsUint64 instead rejected amounts whose amount * rate product exceeded uint64, so buildWrapCalldata and Erc7984Token.verifyWrapTransaction refused to wrap anything above ~1.8e-8 tokens for rate > 1 pairs (hteth:ctest1, rate 1e12). Rate 1 pairs were unaffected because both bounds coincide there. Rename the helper to assertWrapAmountFitsUint64, switch it to floor(amount / rate), and correct the doc comments. Tests cover 1 full 18-decimal token at rate 1e12 and the exact uint64 boundary. Ticket: CHALO-1793
…face-pendingapprovalid-from-tss-message-signing feat(sdk-core): surface pendingApprovalId from TSS message signing
…984-wrapapprove-uint64-guard-contradicts-deployed CHALO-1793 fix(abstract-eth): bound ERC-7984 wrap amount by amount / rate
problem/goal: preBuildTransaction picks build params with buildParamKeys from the BuildParams codec before POSTing to the platform's /tx/build. The codec whitelisted the other XLM accountConfig keys (type, flags, clearFlags, trustlines) but not lowThreshold, so a client-side lowThreshold change was stripped before the request left the SDK and the platform's coin-scoped validation never saw it. implementation details: add lowThreshold: t.unknown to the BuildParams codec next to the other XLM accountConfig keys. The platform pins it to exactly 2 and merges the coin-scoped whitelist on /tx/build (wallet-platform CSHLD-1925). verification: npx mocha test/unit/bitgo/wallet/BuildParams.ts passes (9 tests, including a new case asserting lowThreshold survives encode while unknown params are stripped). Ticket: CSHLD-1925
…params-codec CSHLD-1925 fix(sdk-core): pass lowThreshold through the client BuildParams codec
Go Accounts needs the OFC version of teuroc, the test ERC-20 counterpart of euroc, so test environments can mirror the existing production euroc OFC support. Adds a tofcerc20 definition for ofcteuroc backed by teuroc with 6 decimals, matching the existing teuroc terc20 and ofceuroc mainnet OFC definitions. Ticket: COINS-1796 Session-Id: cffd4af2-44bc-43d6-aeb2-4fea5b9f84e2 Task-Id: d7b1e8fc-9c40-49e9-b487-ea9e48d46823
problem/goal Onboard JPY Coin (JPYC) testnet ERC-20 tokens on Sepolia (sepeth:jpyc) and Polygon Amoy (tpolygon:jpyc) plus their OFC variants under ticket CECHO-2428. Per JPYC's official docs the testnet contract address is the same as mainnet on both networks. implementation details - Added 'sepeth:jpyc' and 'tpolygon:jpyc' to UnderlyingAsset enum in base.ts. - Registered 'sepeth:jpyc' (name 'JPY Coin', 18 decimals, contract 0xe7c3d8c9a439fede00d2600032d5db0be71c3c29) on Sepolia in erc20Coins.ts with ACCOUNT_COIN_DEFAULT_FEATURES. - Registered 'tpolygon:jpyc' (name 'JPY Coin', 18 decimals, same contract) in polygonTokens.ts with POLYGON_TOKEN_FEATURES, mirroring mainnet polygon:jpyc. - Registered 'ofcsepeth:jpyc' and 'ofctpolygon:jpyc' OFC tokens in ofcErc20Coins.ts and ofcCoins.ts. - Added 'sepeth:jpyc' to testnetPrefixExceptions in tokenNamingConvention.ts and 'ofctpolygon:jpyc' to knownExceptions in ofcTokenNaming.ts to comply with naming conventions (fullName mirrors mainnet, matching recent onboarding precedent). verification- how it was verified - Verified contract on Sepolia via sepolia.etherscan.io: JPY Coin (JPYC), 18 decimals; Amoy deployment confirmed via polygonscan token page. - UUID uniqueness checked across the repository for all four registrations. - yarn run unit-test --scope @bitgo/statics: 39,686 passing, 0 failing. - eslint on all changed files: 0 errors. - Registry smoke test via tsx: all 4 tokens resolve in statics CoinMap with decimals 18 and testnet network type. Ticket: CECHO-2428
The ERC-7984 shield approve leg is signed through the chain coin, whose generic checks never decode calldata, so nothing client-side confirmed spender == wrapper and amount == the entered amount before signing. Add decodeApproveCalldata (strict: approve selector, exactly 68 bytes) and, for type wrapApprove, have verifyTssTransaction require that the tx targets the pair's underlying ERC-20 with zero value and carries approve(wrapper, wrapParams.amount). Any deviation, a missing wrapParams, or an unregistered pair fails closed. Replace the wrapApprove test that used txHex 0x (no calldata checked) with cases for a valid approve, wrong spender, mutated amount, non-approve selector, trailing bytes, wrong target and missing wrapParams. Ticket: CHALO-1794 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…kens-to-onboard feat(statics): onboard jpyc testnet tokens on sepolia and polygon amoy
feat(statics): onboard ofcteuroc testnet OFC coin
…984-shield-client-side-decode-and-assert-for-the CHALO-1794 feat(abstract-eth): assert wrapApprove calldata before signing
…ields feat: allow updating already-registered coins via replaceExistingCoin
AllocationFactory_Allocate for native Canton Coin (Amulet) creates an AmuletAllocation, not a DvpLegAllocation or AllocationV2, so the parser found no sender, receiver or amount and failed. Read the identical allocation.transferLeg record from AmuletAllocation too. Also make the native check exact (instrument id Amulet administered by a DSO party) instead of a substring match on admin:id, so an unrelated token whose name contains "Amulet" is no longer parsed as the base coin, and throw a clear error for an unsupported instrument instead of a TypeError. Ticket: CHALO-1775 Co-Authored-By: Claude <noreply@anthropic.com>
Add a native AllocationFactory_Allocate prepared transaction captured on BitGo testnet and cover it in the parser and the allocation allocate builder: sender, receiver and amount from AmuletAllocation, no token, and base-coin inputs and outputs. Ticket: CHALO-1775 Co-Authored-By: Claude <noreply@anthropic.com>
The builder's setTransaction does not populate inputs and outputs, so the native base-coin assertion read an undefined entry. Call loadInputsAndOutputs first, as the raw-parse path does. Ticket: CHALO-1775 Co-Authored-By: Claude <noreply@anthropic.com>
The RealFi issuer renamed its Cardano stablecoin pair: "RealFi USDr" is now "RealFi USDrf" and "RealFi sUSDr" is now "RealFi sUSDrf". BitGoJS still displayed the old names, so wallets showed a stale product name to customers holding these tokens. Update the fullName display metadata for every statics definition of the renamed tokens: ada:usdr and ada:susdr, their testnet variants tada:usdr and tada:susdr, and the OFC wrappers ofcada:usdr, ofcada:susdr, ofctada:usdr and ofctada:susdr. Also update the staking suite's describe label. Coin names (ada:usdr), symbols (USDr), policy IDs, asset names and decimals are unchanged, so wallet addresses, balances and API integrations are unaffected. Ticket: CSHLD-1936 Session-Id: 9a5c6829-2548-45ab-9949-9aac35530c95 Task-Id: 8db036e4-fb87-4f29-a568-ebd0db826602
…-native-canton-coin-in-bitgojs-dvp-builders feat(sdk-coin-canton): parse native Canton Coin allocate transactions
Follow-up to the wrapApprove calldata assertion (#9949). 1. pendingApproval re-sign (recreateTxRequest -> signTxRequest) carries no txParams, so resolveEffectiveTxParams built them from the persisted intent without wrapParams and verifyWrapApproveTransaction rejected valid approve calldata. Derive wrapParams from the wrapApprove / wrap intent's tokenName and amount, the same way stakingRequestId is propagated. 2. The assertion only ran when the declared type was wrapApprove, and on the re-sign path that type is server-persisted, so a compromised WP could relabel a mutated approve(wrapper, amount) as another type. Force any approve(address,uint256) sent to a registered ERC-7984 underlying whose spender is that pair's wrapper through the wrapApprove check. Approvals to other spenders and every other call are untouched. A hex without the approve selector returns before any parse, and a tx the builder cannot parse is skipped so no new failure is introduced. Also route the wrapApprove precondition failures through TxIntentMismatchRecipientError and test the native-value branch. Ticket: CHALO-1794
…pprove-verify-followups CHALO-1794 fix(abstract-eth): propagate wrapParams, guard wrapper approves
fix(statics): rename RealFi USDr tokens to USDrf
…est-empty-vs-provider-failed-in-recover-remaining feat: complete empty vs provider-fail in recover()
prajwalu142
temporarily deployed
to
beta-alpha-release
October 13, 2026 17:49 — with
GitHub Actions
Inactive
Contributor
|
|
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.