from nacl.exceptions import BadSignatureError
from ton_core import NetworkGlobalID
from ton_connect import AppWalletsLoader, FileStorage, TonConnect, VerifySignData
from ton_connect.models import (
SignDataPayloadDto,
SignDataPayloadText,
)
# Setup constants — see Installation and Initialization
MANIFEST_URL = "https://raw.githubusercontent.com/nessshon/ton-connect/main/assets/tonconnect-manifest.json"
SESSION_KEY = "user-123"
STORAGE_PATH = "./tonconnect-storage.json"
# Domain your app is served from — must match your tonconnect-manifest.json
APP_DOMAIN = "github.com"
# Text the user will be asked to sign in their wallet UI
SIGN_TEXT = "I agree to the Terms of Service"
async def main() -> None:
storage = FileStorage(STORAGE_PATH)
app_wallets_loader = AppWalletsLoader(include_wallets=["tonkeeper"])
tc = TonConnect(
storage=storage,
manifest_url=MANIFEST_URL,
app_wallets=app_wallets_loader.get_wallets(),
)
connector = tc.create_connector(SESSION_KEY)
# Try to restore a previously saved connection before starting a new one
restored = await connector.restore()
if not restored:
request = connector.make_connect_request()
await connector.connect(
request=request,
network=NetworkGlobalID.TESTNET,
)
tonkeeper = app_wallets_loader.get_wallet("tonkeeper")
tonkeeper_url = connector.make_connect_url(request, tonkeeper)
print(f"Tonkeeper URL: {tonkeeper_url}")
wallet, error = await connector.wait_connect()
if error:
print(f"Connection failed: {error}")
return
address = connector.account.address.to_str(is_bounceable=False)
print(f"Address: {address}")
# Build the sign data payload
payload = SignDataPayloadText(text=SIGN_TEXT)
# Send the sign data request to the connected wallet
# Returns a request_id immediately — the user approves in their wallet app
request_id = await connector.sign_data(payload)
print("Sign request sent, waiting for confirmation...")
# Block until the wallet signs the data (or rejects/times out)
result, error = await connector.wait_sign_data(request_id)
if error:
print(f"Signing failed: {error}")
return
print(f"Signature: {result.signature.as_hex}")
print(f"Signed at: {result.timestamp}")
try:
# Verify the signature returned by the wallet
sign_data_payload = SignDataPayloadDto(
address=connector.account.address,
network=connector.account.network,
public_key=connector.account.public_key,
wallet_state_init=connector.account.state_init,
signature=result.signature,
timestamp=result.timestamp,
domain=result.domain,
payload=result.payload,
)
await VerifySignData(sign_data_payload).verify(
allowed_domains=[APP_DOMAIN],
valid_auth_time=5 * 60, # 5 minutes
)
print("SignData verified")
except BadSignatureError as e:
print(f"SignData verification failed: {e}")
# Close all active bridge connections
await tc.close_all()
if __name__ == "__main__":
import asyncio
asyncio.run(main())