Skip to content

TonLib improvements#947

Merged
tomiir merged 9 commits intomainfrom
pr-943-feature-signatures
Nov 24, 2025
Merged

TonLib improvements#947
tomiir merged 9 commits intomainfrom
pr-943-feature-signatures

Conversation

@tomiir
Copy link
Contributor

@tomiir tomiir commented Nov 24, 2025

Supersedes #943

Copilot AI review requested due to automatic review settings November 24, 2025 21:55
@vercel
Copy link

vercel bot commented Nov 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
decentralized-relay-app Error Error Nov 24, 2025 9:56pm
decentralized-relay-wallet Building Building Preview Comment Nov 24, 2025 9:56pm
pos-dapp Ready Ready Preview Comment Nov 24, 2025 9:56pm
react-wallet-v2 Building Building Preview Comment Nov 24, 2025 9:56pm
wallet-pay-dapp Error Error Nov 24, 2025 9:56pm
8 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
appkit-react-wagmi-example Ignored Ignored Nov 24, 2025 9:56pm
appkit-solana Ignored Ignored Nov 24, 2025 9:56pm
chain-abstraction-demo Ignored Ignored Nov 24, 2025 9:56pm
malicious-dapp-verify-simulation Ignored Ignored Nov 24, 2025 9:56pm
react-dapp-v2 Ignored Ignored Nov 24, 2025 9:56pm
react-dapp-v2-cosmos-provider Ignored Ignored Nov 24, 2025 9:56pm
react-dapp-v2-with-ethers Ignored Ignored Nov 24, 2025 9:56pm
smart-sessions-demo Ignored Ignored Nov 24, 2025 9:56pm

@cloudflare-workers-and-pages
Copy link

Deploying demo-ai-agents with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0baf806
Status:🚫  Build failed.

View logs

Copy link
Member

@chris13524 chris13524 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@tomiir tomiir merged commit 14668b0 into main Nov 24, 2025
17 of 22 checks passed
@tomiir tomiir deleted the pr-943-feature-signatures branch November 24, 2025 21:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the TON blockchain integration in the React wallet by adding comprehensive validation, improving message signing according to TON Connect specifications, and adding session properties for public keys and state initialization.

  • Adds request validation with early error detection for TON transactions and messages
  • Implements TON Connect compliant signing for authentication (ton-proof) and data signing with domain-aware hashing
  • Introduces retry logic for network operations and comprehensive message validation

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
advanced/wallets/react-wallet-v2/package.json Adds crc-32 dependency for TON signature verification
advanced/wallets/react-wallet-v2/pnpm-lock.yaml Updates lock file with crc-32 package
advanced/wallets/react-wallet-v2/src/lib/TonLib.ts Implements comprehensive validation, TON Connect compliant signing, retry logic, and new methods for public key/state init
advanced/wallets/react-wallet-v2/src/utils/TonRequestHandlerUtil.ts Adds validateTonRequest function and updates approveTonRequest to accept session parameter for domain extraction
advanced/wallets/react-wallet-v2/src/views/SessionSignTonTransactionModal.tsx Adds validation useEffect hook and passes session to approval handler
advanced/wallets/react-wallet-v2/src/views/SessionSignTonPersonalMessageModal.tsx Adds validation useEffect hook and passes session to approval handler
advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx Adds TON-specific session properties (public key and state init)
advanced/wallets/react-wallet-v2/src/utils/AuthUtil.ts Implements TON-proof authentication using generateTonProof method with iat, domain, and payload
Files not reviewed (1)
  • advanced/wallets/react-wallet-v2/pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (4)

advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx:463

  • Missing dependency in useCallback. The authenticationMessagesToSign variable is used within the callback on line 445, but it's not included in the dependency array on line 463. This could lead to stale closure issues where the callback uses an outdated value. Add authenticationMessagesToSign to the dependency array.
  const onApprove = useCallback(async () => {
    console.log('onApprove', { proposal, namespaces })
    try {
      if (proposal && namespaces) {
        setIsLoadingApprove(true)
        if (reorderedEip155Accounts.length > 0) {
          // we should append the smart accounts to the available eip155 accounts
          namespaces.eip155.accounts = reorderedEip155Accounts.concat(namespaces.eip155.accounts)
        }
        //get capabilities for all reorderedEip155Accounts in wallet
        const capabilities = getWalletCapabilities(reorderedEip155Accounts)
        let sessionProperties = {
          capabilities: JSON.stringify(capabilities)
        } as any

        // Add TRON-specific properties if TRON namespace exists
        if (namespaces.tron) {
          sessionProperties['tron_method_version'] = 'v1'
        }

        if (namespaces.bip122) {
          const bip122Chain = namespaces.bip122.chains?.[0]!
          sessionProperties.bip122_getAccountAddresses = JSON.stringify({
            payment: Array.from(bip122Wallet.getAddresses(bip122Chain as IBip122ChainId).values()),
            ordinal: Array.from(
              bip122Wallet.getAddresses(bip122Chain as IBip122ChainId, ['ordinal']).values()
            )
          })
        }

        if (namespaces.sui) {
          const suiWallet = await getSuiWallet()
          const accounts = suiWallet.getAccounts()
          sessionProperties.sui_getAccounts = JSON.stringify(accounts)
        }

        if (namespaces.stacks) {
          const accounts = stacksWallet.getAccounts()
          sessionProperties.stacks_getAddresses = JSON.stringify([
            accounts.mainnet,
            accounts.testnet
          ])
        }

        if (namespaces.ton) {
          const tonWallet = await getWallet();
          sessionProperties.ton_getPublicKey = tonWallet.getPublicKey();
          sessionProperties.ton_getStateInit = tonWallet.getStateInit();
        }

        console.log('sessionProperties', sessionProperties)

        const signedAuths = await signAuthenticationMessages(authenticationMessagesToSign)

        await walletkit.approveSession({
          id: proposal.id,
          namespaces,
          sessionProperties,
          proposalRequestsResponses: {
            authentication: signedAuths
          }
        })
        SettingsStore.setSessions(Object.values(walletkit.getActiveSessions()))
      }
    } catch (e) {
      styledToast((e as Error).message, 'error')
    } finally {
      setIsLoadingApprove(false)
      ModalStore.close()
    }
  }, [namespaces, proposal, reorderedEip155Accounts])

advanced/wallets/react-wallet-v2/src/views/SessionSignTonTransactionModal.tsx:72

  • Missing requestSession in the useCallback dependency array. The callback uses requestSession on line 60, but it's not included in the dependency array on line 72. This could lead to stale closure issues. Add requestSession to the dependency array.
  const onApprove = useCallback(async () => {
    try {
      if (requestEvent) {
        setIsLoadingApprove(true)
        const response = await approveTonRequest(requestEvent, requestSession)
        await walletkit.respondSessionRequest({
          topic,
          response
        })
      }
    } catch (e) {
      styledToast((e as Error).message, 'error')
    } finally {
      setIsLoadingApprove(false)
      ModalStore.close()
    }
  }, [requestEvent, topic])

advanced/wallets/react-wallet-v2/src/views/SessionSignTonPersonalMessageModal.tsx:70

  • Missing requestSession in the useCallback dependency array. The callback uses requestSession on line 58, but it's not included in the dependency array on line 70. This could lead to stale closure issues. Add requestSession to the dependency array.
  const onApprove = useCallback(async () => {
    try {
      if (requestEvent) {
        setIsLoadingApprove(true)
        const response = await approveTonRequest(requestEvent, requestSession)
        await walletkit.respondSessionRequest({
          topic,
          response
        })
      }
    } catch (e) {
      styledToast((e as Error).message, 'error')
    } finally {
      setIsLoadingApprove(false)
      ModalStore.close()
    }
  }, [requestEvent, topic])

advanced/wallets/react-wallet-v2/src/lib/TonLib.ts:265

  • Unused variable innerMessage.
    const innerMessage = {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +307 to +312
const domain = params.domain

const dataToSign = this.createTonProofMessageBytes({
address: this.wallet.address,
domain: {
lengthBytes: domain.length,
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant variable assignment. The domain variable is assigned params.domain on line 307, but then params.domain is used directly on line 313. Either use domain consistently throughout the function or remove the redundant variable assignment.

Suggested change
const domain = params.domain
const dataToSign = this.createTonProofMessageBytes({
address: this.wallet.address,
domain: {
lengthBytes: domain.length,
const dataToSign = this.createTonProofMessageBytes({
address: this.wallet.address,
domain: {
lengthBytes: params.domain.length,

Copilot uses AI. Check for mistakes.
private parseTonMessages(params: TonLib.SendMessage['params']) {
this.validateSendMessage(params)
return params.messages.map(m => {
const amountBigInt = typeof m.amount === 'string' ? BigInt(m.amount) : BigInt(m.amount)
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant type check and conversion. The condition typeof m.amount === 'string' ? BigInt(m.amount) : BigInt(m.amount) performs the same BigInt(m.amount) conversion in both branches. Since the type definition requires amount to be a string (line 511), this can be simplified to just BigInt(m.amount).

Suggested change
const amountBigInt = typeof m.amount === 'string' ? BigInt(m.amount) : BigInt(m.amount)
const amountBigInt = BigInt(m.amount)

Copilot uses AI. Check for mistakes.
domain: AuthMessage.domain,
payload: AuthMessage.statement,
})
return { signature: tonResult.signature, publicKey: tonResult.publicKey, type: 'ton' }
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing break statement after the ton case. This causes fall-through to the solana case, which will execute the solana logic when TON authentication doesn't have a statement. Add a break statement after line 141 or return early from the function.

Suggested change
return { signature: tonResult.signature, publicKey: tonResult.publicKey, type: 'ton' }
return { signature: tonResult.signature, publicKey: tonResult.publicKey, type: 'ton' }
} else {
throw new Error('TON authentication requires a statement');

Copilot uses AI. Check for mistakes.
const payload = Array.isArray(request.params) ? request.params[0] : request.params || {}

useEffect(() => {
if (!requestEvent) {
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent validation check. In SessionSignTonTransactionModal.tsx line 38, the validation checks if (!request.params), but in SessionSignTonPersonalMessageModal.tsx line 36, it checks if (!requestEvent). These should be consistent. The check should likely be if (!request.params) in both files to validate that the request has parameters before calling validateTonRequest.

Suggested change
if (!requestEvent) {
if (!requestEvent || !requestEvent.params || !requestEvent.params.request) {

Copilot uses AI. Check for mistakes.
case TON_SIGNING_METHODS.SIGN_DATA:
break
case TON_SIGNING_METHODS.SEND_MESSAGE:
wallet.validateSendMessage(payload)
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing break statement in switch case. The SEND_MESSAGE case should have a break statement to prevent fall-through to the default case, even though it's the last explicit case before default. This is a best practice for maintainability.

Suggested change
wallet.validateSendMessage(payload)
wallet.validateSendMessage(payload)
break

Copilot uses AI. Check for mistakes.
Comment on lines +328 to +330
* Creates hash for Cell payload according to TON Connect specification.
*/
/**
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate documentation comment. There are two JSDoc comments on lines 327-329 and 330-334, both attempting to document the same method createTextBinaryHash. The first comment (line 327-329) is incomplete and should be removed.

Suggested change
* Creates hash for Cell payload according to TON Connect specification.
*/
/**

Copilot uses AI. Check for mistakes.
Comment on lines +265 to +272
const innerMessage = {
workchain: message.address.workChain,
address: message.address.hash,
domain: message.domain,
payload: message.payload,
timestamp: message.timestamp
}

Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable innerMessage is created but never used. The variable is constructed on lines 265-271 but serves no purpose. Consider removing it to clean up the code.

Suggested change
const innerMessage = {
workchain: message.address.workChain,
address: message.address.hash,
domain: message.domain,
payload: message.payload,
timestamp: message.timestamp
}

Copilot uses AI. Check for mistakes.
const walletContract = client.open(this.wallet)
const seqno = await retry(() => walletContract.getSeqno())


Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Extra blank line. There's an unnecessary blank line on line 222 that should be removed to maintain consistent code formatting.

Suggested change

Copilot uses AI. Check for mistakes.
import StacksLib from '@/lib/StacksLib'
import { TON_CHAINS, TON_SIGNING_METHODS } from '@/data/TonData'
import { tonAddresses } from '@/utils/TonWalletUtil'
import { getWallet, tonAddresses, tonWallets } from '@/utils/TonWalletUtil'
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import tonWallets.

Suggested change
import { getWallet, tonAddresses, tonWallets } from '@/utils/TonWalletUtil'
import { getWallet, tonAddresses } from '@/utils/TonWalletUtil'

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants