What
Both the Verify identity app and the Community Bounty app fail at the "sign ownership" step with Cannot read properties of undefined (reading 'publicKey'). Both flows go through byte-identical adapter code that calls selectedProvider.request({ method: "sign", params: [message] }). These are the only two provider.request({ method: "sign" }) call sites in the codebase, and both fail the same way — so the bug is in the shared sign provider method, not in either page.
randomblocker confirmed the failure shape and posted the lead on incentives PR #81 (https://github.com/kynesyslabs/incentives/pull/81): DemosSdkProvider.sign (the seed-phrase path) calls demos.crypto.sign("ed25519", ...) directly and skips the keypair-init step (getIdentity('ed25519') → generate) that the SDK's own demos.signMessage performs. With the keypair never initialised, this.keypair.publicKey is undefined when the signing call dereferences it. The extension-handler path may have a separate variant of the same bug.
Acceptance
Source
What
Both the Verify identity app and the Community Bounty app fail at the "sign ownership" step with
Cannot read properties of undefined (reading 'publicKey'). Both flows go through byte-identical adapter code that callsselectedProvider.request({ method: "sign", params: [message] }). These are the only twoprovider.request({ method: "sign" })call sites in the codebase, and both fail the same way — so the bug is in the sharedsignprovider method, not in either page.randomblocker confirmed the failure shape and posted the lead on incentives PR #81 (https://github.com/kynesyslabs/incentives/pull/81):
DemosSdkProvider.sign(the seed-phrase path) callsdemos.crypto.sign("ed25519", ...)directly and skips the keypair-init step (getIdentity('ed25519')→ generate) that the SDK's owndemos.signMessageperforms. With the keypair never initialised,this.keypair.publicKeyis undefined when the signing call dereferences it. The extension-handler path may have a separate variant of the same bug.Acceptance
DemosSdkProvider.sign)DemosSdkProvider.signso it walks the same keypair-init sequence asdemos.signMessagebefore reaching the underlying signerprovider.request({ method: "sign", params: [message] })so a future SDK refactor cannot silently re-introduce the gapSource