Skip to content

ChainSessionManager signed call caching and relay #277

@Dargon789

Description

@Dargon789

Reviewer's Guide

Implements 3.0.0-beta.12 beta release across wallet and services packages, adding extensive new userdata RPC methods and types, improving dapp client transport source validation, adding a short-lived cache for signed calls in ChainSessionManager, and bumping package versions/changelogs with corresponding changesets.

Sequence diagram for ChainSessionManager signed call caching and relay

sequenceDiagram
  actor Dapp
  participant ChainSessionManager
  participant Relayer

  Dapp->>ChainSessionManager: sendTransaction(calls)
  activate ChainSessionManager
  ChainSessionManager->>ChainSessionManager: _getCachedSignedCall(calls)
  alt cache hit and not expired
    ChainSessionManager-->>ChainSessionManager: use cached signedCall
  else cache miss or expired
    ChainSessionManager->>ChainSessionManager: _buildAndSignCalls(callsToSend)
    ChainSessionManager-->>ChainSessionManager: signedCall
    ChainSessionManager->>ChainSessionManager: _fingerprintCalls(callsToSend)
    ChainSessionManager-->>ChainSessionManager: fingerprint
    ChainSessionManager-->>ChainSessionManager: update lastSignedCallCache
  end
  ChainSessionManager->>Relayer: relay(signedCall.to, signedCall.data, chainId)
  activate Relayer
  Relayer-->>ChainSessionManager: opHash
  deactivate Relayer
  ChainSessionManager->>ChainSessionManager: _waitForTransactionReceipt(opHash, chainId)
  ChainSessionManager-->>Dapp: transaction status
  deactivate ChainSessionManager
Loading

Sequence diagram for DappTransport wallet window message validation

sequenceDiagram
  actor Browser
  participant DappTransport
  participant WalletWindow

  Browser->>DappTransport: message(event)
  activate DappTransport
  alt walletWindow not set
    DappTransport-->>Browser: ignore event
  else walletWindow set
    alt event.source is not walletWindow
      DappTransport-->>Browser: ignore event
    else event.source is walletWindow
      DappTransport-->>WalletWindow: process message for wallet
    end
  end
  deactivate DappTransport
Loading

Class diagram for new userdata RPC types and UserData client

classDiagram
class Version {
  string webrpcVersion
  string schemaVersion
  string schemaHash
  string appVersion
}

class RuntimeStatus {
  boolean healthOK
  string startTime
  number uptime
  string ver
  string branch
  string commitHash
}

class Wallet {
  string address
  number ecosystem
  WalletPreferences preferences
  string updatedAt
  string createdAt
}

class WalletPreferences {
  boolean manualSigning
  boolean hideUnlistedTokens
  boolean includeTestnets
  string currency
}

class WalletSigner {
  string walletAddress
  string signerAddress
  string kind
  string email
  string updatedAt
  string createdAt
}

class Session {
  string walletAddress
  string address
  string appUrl
  string updatedAt
  string createdAt
}

class Contact {
  string walletAddress
  string contactAddress
  string nickname
  string updatedAt
  string createdAt
}

class WatchedWallet {
  string walletAddress
  string watchedAddress
  string nickname
  string updatedAt
  string createdAt
}

class DiscoverFavorite {
  string walletAddress
  number id
  string dappId
  string createdAt
}

class DiscoverHistory {
  string walletAddress
  number id
  string dappId
  string accessedAt
}

class TokenFavorite {
  string walletAddress
  number id
  string chainId
  string contractAddress
  string tokenId
  string createdAt
}

class SessionProps {
  string address
  string appUrl
}

class WalletSignerProps {
  string address
  string kind
  string email
}

class ContactProps {
  string address
  string nickname
}

class DiscoverProps {
  string dappId
}

class TokenFavoriteProps {
  string chainId
  string contractAddress
  string tokenId
}

class WatchedWalletProps {
  string watchedAddress
  string nickname
}

class GetWalletPreferencesRequest {
  string wallet
}

class GetWalletPreferencesResponse {
  WalletPreferences preferences
}

class PutWalletPreferencesRequest {
  string wallet
  WalletPreferences preferences
}

class PutWalletPreferencesResponse {
}

class ListWalletSignersRequest {
  string wallet
  number pageSize
  string cursor
}

class ListWalletSignersResponse {
  WalletSigner[] signers
  string nextCursor
}

class PutWalletSignerRequest {
  string wallet
  WalletSignerProps signer
}

class PutWalletSignerResponse {
  WalletSigner signer
}

class DeleteWalletSignerRequest {
  string wallet
  string signer
}

class DeleteWalletSignerResponse {
}

class ListSessionsRequest {
  string wallet
  number pageSize
  string cursor
}

class ListSessionsResponse {
  Session[] sessions
  string nextCursor
}

class PutSessionRequest {
  string wallet
  SessionProps session
}

class PutSessionResponse {
  Session session
}

class DeleteSessionRequest {
  string wallet
  string session
}

class DeleteSessionResponse {
}

class ListContactsRequest {
  string wallet
  number pageSize
  string cursor
}

class ListContactsResponse {
  Contact[] contacts
  string nextCursor
}

class PutContactRequest {
  string wallet
  ContactProps contact
}

class PutContactResponse {
  Contact contact
}

class DeleteContactRequest {
  string wallet
  string contact
}

class DeleteContactResponse {
}

class ListWatchedWalletsRequest {
  string wallet
  number pageSize
  string cursor
}

class ListWatchedWalletsResponse {
  WatchedWallet[] watchedWallets
  string nextCursor
}

class PutWatchedWalletRequest {
  string wallet
  WatchedWalletProps watchedWallet
}

class PutWatchedWalletResponse {
  WatchedWallet watchedWallet
}

class DeleteWatchedWalletRequest {
  string wallet
  string watchedWallet
}

class DeleteWatchedWalletResponse {
}

class ListDiscoverFavoritesRequest {
  string wallet
  number pageSize
  string cursor
}

class ListDiscoverFavoritesResponse {
  DiscoverFavorite[] favorites
  string nextCursor
}

class PutDiscoverFavoriteRequest {
  string wallet
  DiscoverProps favorite
}

class PutDiscoverFavoriteResponse {
  DiscoverFavorite favorite
}

class DeleteDiscoverFavoriteRequest {
  string wallet
  number id
}

class DeleteDiscoverFavoriteResponse {
}

class ListDiscoverHistoryRequest {
  string wallet
  number pageSize
  string cursor
}

class ListDiscoverHistoryResponse {
  DiscoverHistory[] history
  string nextCursor
}

class PutDiscoverHistoryRequest {
  string wallet
  DiscoverProps history
}

class PutDiscoverHistoryResponse {
  DiscoverHistory history
}

class DeleteDiscoverHistoryRequest {
  string wallet
  number id
}

class DeleteDiscoverHistoryResponse {
}

class ListTokenFavoritesRequest {
  string wallet
  number pageSize
  string cursor
}

class ListTokenFavoritesResponse {
  TokenFavorite[] favorites
  string nextCursor
}

class PutTokenFavoriteRequest {
  string wallet
  TokenFavoriteProps favorite
}

class PutTokenFavoriteResponse {
  TokenFavorite favorite
}

class DeleteTokenFavoriteRequest {
  string wallet
  number id
}

class DeleteTokenFavoriteResponse {
}

class UserDataClient {
  getWalletPreferences(req, headers, signal) Promise
  putWalletPreferences(req, headers, signal) Promise
  listWalletSigners(req, headers, signal) Promise
  putWalletSigner(req, headers, signal) Promise
  deleteWalletSigner(req, headers, signal) Promise
  listSessions(req, headers, signal) Promise
  putSession(req, headers, signal) Promise
  deleteSession(req, headers, signal) Promise
  listContacts(req, headers, signal) Promise
  putContact(req, headers, signal) Promise
  deleteContact(req, headers, signal) Promise
  listWatchedWallets(req, headers, signal) Promise
  putWatchedWallet(req, headers, signal) Promise
  deleteWatchedWallet(req, headers, signal) Promise
  listDiscoverFavorites(req, headers, signal) Promise
  putDiscoverFavorite(req, headers, signal) Promise
  deleteDiscoverFavorite(req, headers, signal) Promise
  listDiscoverHistory(req, headers, signal) Promise
  putDiscoverHistory(req, headers, signal) Promise
  deleteDiscoverHistory(req, headers, signal) Promise
  listTokenFavorites(req, headers, signal) Promise
  putTokenFavorite(req, headers, signal) Promise
  deleteTokenFavorite(req, headers, signal) Promise
}

class UserData {
}

UserData ..|> UserDataClient

Wallet --> WalletPreferences
Wallet --> WalletSigner
Wallet --> Session
Wallet --> Contact
Wallet --> WatchedWallet
Wallet --> DiscoverFavorite
Wallet --> DiscoverHistory
Wallet --> TokenFavorite

WalletSignerProps --> WalletSigner
SessionProps --> Session
ContactProps --> Contact
WatchedWalletProps --> WatchedWallet
DiscoverProps --> DiscoverFavorite
DiscoverProps --> DiscoverHistory
TokenFavoriteProps --> TokenFavorite

GetWalletPreferencesRequest --> GetWalletPreferencesResponse
PutWalletPreferencesRequest --> PutWalletPreferencesResponse
ListWalletSignersRequest --> ListWalletSignersResponse
PutWalletSignerRequest --> PutWalletSignerResponse
DeleteWalletSignerRequest --> DeleteWalletSignerResponse
ListSessionsRequest --> ListSessionsResponse
PutSessionRequest --> PutSessionResponse
DeleteSessionRequest --> DeleteSessionResponse
ListContactsRequest --> ListContactsResponse
PutContactRequest --> PutContactResponse
DeleteContactRequest --> DeleteContactResponse
ListWatchedWalletsRequest --> ListWatchedWalletsResponse
PutWatchedWalletRequest --> PutWatchedWalletResponse
DeleteWatchedWalletRequest --> DeleteWatchedWalletResponse
ListDiscoverFavoritesRequest --> ListDiscoverFavoritesResponse
PutDiscoverFavoriteRequest --> PutDiscoverFavoriteResponse
DeleteDiscoverFavoriteRequest --> DeleteDiscoverFavoriteResponse
ListDiscoverHistoryRequest --> ListDiscoverHistoryResponse
PutDiscoverHistoryRequest --> PutDiscoverHistoryResponse
DeleteDiscoverHistoryRequest --> DeleteDiscoverHistoryResponse
ListTokenFavoritesRequest --> ListTokenFavoritesResponse
PutTokenFavoriteRequest --> PutTokenFavoriteResponse
DeleteTokenFavoriteRequest --> DeleteTokenFavoriteResponse

UserData --> GetWalletPreferencesRequest
UserData --> PutWalletPreferencesRequest
UserData --> ListWalletSignersRequest
UserData --> PutWalletSignerRequest
UserData --> DeleteWalletSignerRequest
UserData --> ListSessionsRequest
UserData --> PutSessionRequest
UserData --> DeleteSessionRequest
UserData --> ListContactsRequest
UserData --> PutContactRequest
UserData --> DeleteContactRequest
UserData --> ListWatchedWalletsRequest
UserData --> PutWatchedWalletRequest
UserData --> DeleteWatchedWalletRequest
UserData --> ListDiscoverFavoritesRequest
UserData --> PutDiscoverFavoriteRequest
UserData --> DeleteDiscoverFavoriteRequest
UserData --> ListDiscoverHistoryRequest
UserData --> PutDiscoverHistoryRequest
UserData --> DeleteDiscoverHistoryRequest
UserData --> ListTokenFavoritesRequest
UserData --> PutTokenFavoriteRequest
UserData --> DeleteTokenFavoriteRequest
Loading

File-Level Changes

Change Details Files
Extend userdata service client with wallet preferences, signers, sessions, contacts, watched wallets, discover history/favorites, and token favorites RPCs and types.
  • Update Webrpc schema hash and generated banner to new schema version
  • Add new Version and RuntimeStatus types plus rich Wallet, WalletPreferences, WalletSigner, Contact, WatchedWallet, DiscoverFavorite, DiscoverHistory, TokenFavorite and associated Props interfaces
  • Introduce request/response interfaces for wallet preferences, wallet signers, sessions, contacts, watched wallets, discover favorites/history, and token favorites including pagination and cursor fields
  • Wire new RPC methods into UserDataClient interface and UserData class, including method map entries and HTTP request/response handling with JsonEncode/JsonDecode
packages/services/userdata/src/userdata.gen.ts
Optimize dapp transaction submission by caching recently signed calls and tighten wallet window message source validation in the dapp client.
  • Add lastSignedCallCache field to ChainSessionManager with TTL-based reuse of signed calls when subsequent calls fingerprint is identical
  • Implement _fingerprintCalls helper to deterministically serialize call arrays and log failures without throwing
  • Use _getCachedSignedCall in sendTransaction to avoid redundant signatures when re-sending identical calls
  • Remove auto-refresh logic on signer-expired errors in hasPermission to simply treat them as permission failures
  • Update DappTransport postMessage handler to require event.source strictly equals walletWindow, ignoring WALLET_OPENED exception and removing previous relaxed closed-window check
packages/wallet/dapp-client/src/ChainSessionManager.ts
packages/wallet/dapp-client/src/DappTransport.ts
Cut 3.0.0-beta.11 and 3.0.0-beta.12 releases across multiple packages with version bumps, changelog entries, and changeset metadata.
  • Add 3.0.0-beta.11 and 3.0.0-beta.12 sections to multiple package CHANGELOGs noting beta release and dapp connector fixes plus updated dependencies
  • Bump package.json versions from 3.0.0-beta.10 to 3.0.0-beta.12 for services, utils, and wallet packages to keep the monorepo in sync
  • Add changeset markdown files documenting patch releases for all affected packages for 3.0.0 beta and beta.12 with dapp connector fixes
packages/wallet/wdk/CHANGELOG.md
packages/wallet/dapp-client/CHANGELOG.md
packages/wallet/core/CHANGELOG.md
packages/services/relayer/CHANGELOG.md
packages/services/api/CHANGELOG.md
packages/services/builder/CHANGELOG.md
packages/services/guard/CHANGELOG.md
packages/services/identity-instrument/CHANGELOG.md
packages/services/indexer/CHANGELOG.md
packages/services/marketplace/CHANGELOG.md
packages/services/metadata/CHANGELOG.md
packages/services/userdata/CHANGELOG.md
packages/utils/abi/CHANGELOG.md
packages/wallet/primitives/CHANGELOG.md
packages/services/api/package.json
packages/services/builder/package.json
packages/services/guard/package.json
packages/services/identity-instrument/package.json
packages/services/indexer/package.json
packages/services/marketplace/package.json
packages/services/metadata/package.json
packages/services/relayer/package.json
packages/services/userdata/package.json
packages/utils/abi/package.json
packages/wallet/core/package.json
packages/wallet/dapp-client/package.json
packages/wallet/primitives/package.json
packages/wallet/wdk/package.json
.changeset/bright-pots-hope.md
.changeset/free-tips-switch.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Originally posted by @sourcery-ai[bot] in #276 (comment)

Sub-issues

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationduplicateThis issue or pull request already existsenhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededinvalidThis doesn't seem rightjavascriptPull requests that update javascript code

Projects

Status

Backlog

Status

Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions