Add headless connectToContract and RPC-visibility polling for OZ smart accounts#151
Merged
Conversation
…d delay The smart-account auto-fund path funded a throwaway account via Friendbot, then waited a fixed 5 seconds before simulating that account's balance on the Soroban RPC. When testnet propagation exceeds that window the simulation fails with "account entry is missing". Replace the fixed delay with a bounded poll of SorobanServer.getAccount (1.5s interval, 45s timeout, cooperatively cancellable) that proceeds as soon as the account is visible and otherwise fails with a clear timeout error.
…xed delay After the deploy transaction confirms, the deployed smart-account contract instance may not yet be visible to the Soroban RPC simulation endpoint, so the auto-fund flow waited a fixed 5 seconds before simulating against it. When testnet propagation exceeds that window, funding fails with "account entry is missing". Replace both fixed waits (the createWallet and deployPendingCredential auto-fund paths) with a bounded poll of the contract's instance ledger entry (1.5s interval, 45s timeout, cooperatively cancellable, clear timeout error). The shared visibility constants are renamed from friendbot- to rpc-prefixed since both the account and contract waits use them, and both visibility-wait timeouts now raise the dedicated SmartAccountTransactionTimeout category rather than the submission-failed category.
Connects the kit to a deployed smart account by contract address alone — no passkey credential, no WebAuthn ceremony, no session — for autonomous signers and backends operating through the multi-signer / external-signer pipeline. The single-passkey submit() path guards on a sentinel credential and fails fast if misrouted; a dedicated OZSmartAccountEventHeadlessConnected event is emitted.
- Represent a headless connection with a null credentialId and a new isHeadless discriminator; OZConnectedState.credentialId is now nullable and isConnected is gated on the bound contract address. - Narrow the RPC visibility-poll catches to Exception so programmer errors propagate, and correct the timeout-cause documentation. - Cover headless connect with tests (cancellation, best-effort session clear, event equality, and the real kit's connection-state API), and make the test fixture's disconnect emit for any contract-bound state. - Add a CHANGELOG entry for the new API and the nullability change.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #151 +/- ##
==========================================
+ Coverage 90.02% 90.10% +0.07%
==========================================
Files 665 665
Lines 33825 33880 +55
==========================================
+ Hits 30452 30528 +76
+ Misses 3373 3352 -21
🚀 New features to boost your workflow:
|
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.
Summary
Two improvements to the OpenZeppelin smart-account kit:
connectToContractthat connects a smart account by its contract address alone, with no passkey credential.Headless connectToContract
connectToContract(contractId)connects to an existing OZ smart account by its contract address, performing no WebAuthn ceremony and persisting no session.The motivating use case is the agent-signer flow: an autonomous agent is granted a scoped, spend-capped Ed25519 signing authority on a smart account (an external-signer context rule) but does not own the account's passkey. Headless connect lets such an agent — or any backend service that signs through the multi-signer / external-signer path — connect by contract address alone and act as the delegated signer. A headless connection holds no passkey credential, so the single-passkey operations (
submit,transfer,contractCall, …) reject it; calls must use the multi-signer path with an explicit signer.New public surface:
OZWalletOperations.connectToContract→OZConnectToContractResultOZSmartAccountEventHeadlessConnected— emitted on a headless connect, carrying only the contract addressOZSmartAccountKit.isHeadlessandOZConnectedState.isHeadlessRPC-visibility polling
Wallet creation (funding-account visibility) and contract connection (contract-instance visibility) previously waited a fixed delay before continuing, which could be too short on a slow RPC and needlessly long otherwise. Both now poll the Soroban RPC until the entry is visible, up to a bounded timeout, improving reliability.
Breaking change
OZConnectedState.credentialIdis now nullable (String→String?). Anullvalue indicates a headless connection. Code that readscredentialIdas a non-nullStringmust handlenull; useOZConnectedState.isHeadless(orOZSmartAccountKit.isHeadless) to distinguish a headless connection from a passkey one.