diff --git a/changelogs/v31.0.0-next.md b/changelogs/v31.0.0-next.md index c2d24d16e8..11923f5808 100644 --- a/changelogs/v31.0.0-next.md +++ b/changelogs/v31.0.0-next.md @@ -1,6 +1,6 @@ --- title: SDK Changelog - v31.0.0 to next release -description: Pending changes since Polymesh SDK v31.0.0. Adds Ethereum wallet signing and address mapping, broadcasting a transaction without waiting for it, issuing NFTs to an Account, connecting from runtimes that disallow WASM compilation, ordering POLYX transaction history, an optional middleware API key, and staking coverage for chill, rebond, era progress, historical era data, the validator set, commission and total issuance. Fixes BigNumber checks across duplicate package copies, ignored authorization expiry options, unbounded Portfolio scans, on-chain failure reporting, staking permission checks, withdrawing unbonded POLYX where the controller is not the stash, and the units of the total staked amount. +description: Pending changes since Polymesh SDK v31.0.0. Adds Ethereum wallet signing and address mapping, broadcasting a transaction without waiting for it, issuing NFTs to an Account, connecting from runtimes that disallow WASM compilation, ordering POLYX transaction history, an optional middleware API key, and staking coverage for chill, rebond, era progress, historical era data, the validator set, commission and total issuance. Fixes BigNumber checks across duplicate package copies, ignored authorization expiry options, unbounded Portfolio scans, on-chain failure reporting, staking permission checks, withdrawing unbonded POLYX where the controller is not the stash, the units of the total staked amount, and a false "not included" rejection when claiming dividends. sidebar_label: v31.0.0 → next id: v31-0-to-next tags: @@ -383,6 +383,14 @@ All seven now return `permissions: true`: it short-circuits both checks, makes n The count now comes from the stash named in the controller's ledger. An Account that is its own controller is unaffected. +### Claiming dividends could reject a genuine participant as "not included" + +`DividendDistribution.claim()` checks a Distribution's participants by calling `getParticipant()` with no arguments, which defaults the Identity to check to whatever `Context.getSigningIdentity()` returns. `prepareClaimDividends` called it on `distribution` — the `DividendDistribution` entity — rather than on the Procedure's own `Context`. Those are not always the same object: `distribution` carries whichever `Context` it happened to be fetched with, while the Procedure runs against a fresh clone scoped to this call's `signingAccount`. + +For a consumer that fetches entities off one shared, long-lived `Context` while overriding `signingAccount` per call — the REST API is the clearest example — `claim()` checked participation against whatever Identity that shared `Context`'s signing Account last happened to be, not the Identity actually signing the claim. The result was a deterministic `'The signing Identity is not included in this Distribution'`, even for a real, funded participant. + +`prepareClaimDividends` now resolves the signing Identity from its own `Context` explicitly and passes it into `getParticipant()`, so the Identity checked always matches the one signing the call. + --- ## Other changes diff --git a/src/api/procedures/claimDividends.ts b/src/api/procedures/claimDividends.ts index 1ebb2a4909..7eeccb3020 100644 --- a/src/api/procedures/claimDividends.ts +++ b/src/api/procedures/claimDividends.ts @@ -31,7 +31,18 @@ export async function prepareClaimDividends( assertDistributionOpen(paymentDate, expiryDate); - const participant = await distribution.getParticipant(); + // `distribution` was fetched through (and carries) whatever Context it happened to be + // constructed with, which is *not* necessarily this Procedure's own Context (`context` above, + // scoped to this call's `signingAccount`). Since `getParticipant` defaults its `identity` by + // reading the *signing* Identity off whichever Context it's given, calling it with no args here + // would resolve against `distribution`'s Context instead of this one, silently checking the + // wrong Identity's participation (and balance) whenever the two differ - e.g. any multi-account + // consumer, such as the REST API, that fetches entities off a shared Context while overriding + // `signingAccount` per call. Resolve the signing Identity from this Procedure's Context + // explicitly and pass it through so the correct Identity is always the one checked. + const signingIdentity = await context.getSigningIdentity(); + + const participant = await distribution.getParticipant({ identity: signingIdentity }); if (!participant) { throw new PolymeshError({