2026-09-07 00:56:33 +02:00
// Aegis dapp bridges. Runs in the isolated world of every matching tab and
// puts up to two dapp APIs on the page's main world:
//
// window.bitcoincash Silent Mode's own BCH API (only on .x pages —
// matches the pre-multi-wallet gate).
// window.tronWeb TronLink-shaped Tron dapp bridge (on any page).
// window.tronLink TronLink shim; `tron_requestAccounts` triggers
// an approval overlay via activate().
//
// Everything crosses into the wallet's activate() context in main, which
// shows the approval overlay and enforces per-origin permissions. Nothing
// here can sign, read a balance, or read an address on its own.
2026-09-06 02:56:34 +02:00
//
// `theseus` is provided by the host: { id, origin, contextBridge, invoke }.
2026-09-07 00:56:33 +02:00
2026-09-06 02:56:34 +02:00
const call = ( msg , payload ) =>
theseus . invoke ( msg , payload ) . catch ( ( e ) => {
const text = String ( e && e . message || e ) . replace ( /^Error invoking remote method '[^']+': (Error: )?/ , "" ) ;
throw new Error ( text ) ;
} ) ;
2026-09-07 00:56:33 +02:00
// -------- BCH bridge (window.bitcoincash), only on .x pages ------------------
const isBchOrigin = ( ( ) => { try { return /\.x$/i . test ( location . hostname ) ; } catch { return false ; } } ) ( ) ;
if ( isBchOrigin ) {
theseus . contextBridge . exposeInMainWorld ( "bitcoincash" , {
isTheseus : true ,
version : "0.2.0" ,
network : "mainnet" ,
getAddress : ( ) => call ( "getAddress" ) ,
signAndSend : ( txSpec ) => call ( "signAndSend" , txSpec && typeof txSpec === "object" ? txSpec : { } ) ,
signMessage : ( message ) => call ( "signMessage" , { message : String ( message ? ? "" ) } ) ,
} ) ;
}
// -------- Tron bridge (window.tronWeb, window.tronLink), everywhere ---------
//
// Matches enough of the TronLink surface for read + send flows on dapps like
// tronscan, sunswap, and justlend (mainnet or Nile). Not implemented:
// TRC20/TRC721 abstractions, address utilities beyond base58<->hex, event
// emitters beyond the "message" events TronLink documents.
let CACHED = { address : null , network : null } ;
const listeners = new Set ( ) ;
// Public copy of tronWeb.trx.
const trx = {
// Returns the account object TronGrid gives (may be {} for never-funded).
// Deliberately mirrors tronWeb.trx.getAccount.
getAccount : async ( ) => call ( "trx.getAccount" ) ,
// Sign an assembled transaction (dapp built it via its own tronWeb).
// Returns the same object with a `signature` field populated.
sign : async ( transaction ) => {
if ( ! transaction || typeof transaction !== "object" || ! transaction . raw _data _hex ) {
throw new Error ( "tronWeb.trx.sign: expected an assembled transaction with raw_data_hex" ) ;
}
return call ( "trx.signTransaction" , { transaction } ) ;
} ,
// Broadcast a signed transaction. Returns { result: true, txid } on success.
sendRawTransaction : async ( signedTx ) => {
const r = await call ( "trx.sendRawTransaction" , { transaction : signedTx } ) ;
return { result : true , txid : r . txid } ;
} ,
// Convenience wrappers matching the tronWeb surface — dapps call these
// when the wallet is supposed to build the tx too. Left unimplemented
// in this build so a dapp that hits them gets a clear error instead of
// silently unassembled behavior; assemble on the dapp side.
sendTrx : async ( ) => { throw new Error ( "tronWeb.trx.sendTrx not implemented — build the transaction with tronWeb.transactionBuilder and call sign+sendRawTransaction" ) ; } ,
// TronLink documents signMessage (legacy, keccak of just the message) and
// signMessageV2 (adds the "\x19TRON Signed Message:\n<len>" prefix). We
// only implement V2 because that is what modern dapps use.
signMessageV2 : async ( message ) => {
const r = await call ( "trx.signMessageV2" , { message : String ( message ? ? "" ) } ) ;
return r . signature ;
} ,
} ;
// Shallow tronWeb — enough for `tronWeb.defaultAddress.base58` / `.hex` reads
// and the trx methods. Populated once the user connects.
const tronWeb = {
ready : false ,
defaultAddress : { base58 : false , hex : false , name : false } ,
fullNode : { host : "" } ,
solidityNode : { host : "" } ,
eventServer : { host : "" } ,
trx ,
// Utility helpers a few dapps poke at.
isConnected : ( ) => tronWeb . ready === true && ! ! tronWeb . defaultAddress . base58 ,
address : {
fromHex : ( hex ) => hex , // no-op stub; dapps that need a real
toHex : ( base58 ) => base58 , // conversion should use their own copy.
} ,
// Some dapps read this to decide "Tron mainnet vs testnet".
get currentNetwork ( ) { return CACHED . network || null ; } ,
} ;
function nodeHost ( network ) {
return network === "nile" ? "https://nile.trongrid.io" : "https://api.trongrid.io" ;
}
function applyConnection ( { address , network } ) {
CACHED = { address , network } ;
tronWeb . defaultAddress = { base58 : address || false , hex : false , name : false } ;
tronWeb . ready = ! ! address ;
tronLink . ready = ! ! address ;
const host = nodeHost ( network ) ;
tronWeb . fullNode = { host } ;
tronWeb . solidityNode = { host } ;
tronWeb . eventServer = { host } ;
// Broadcast on the window in the way TronLink documents.
try {
window . postMessage ( { message : { action : "accountsChanged" , data : { address } } , isTronLink : true } , location . origin ) ;
window . postMessage ( { message : { action : "setAccount" , data : { address } } , isTronLink : true } , location . origin ) ;
window . postMessage ( { message : { action : "setNode" , data : { node : { fullNode : host , solidityNode : host , eventServer : host , chain : network === "nile" ? "0xcd8690dc" : "0x2b6653dc" } } } , isTronLink : true } , location . origin ) ;
} catch { }
for ( const fn of listeners ) { try { fn ( { address , network } ) ; } catch { } }
}
const tronLink = {
ready : false ,
tronWeb : tronWeb ,
// TronLink's canonical request router. Handles at minimum tron_requestAccounts.
request : async ( opts ) => {
const method = String ( opts ? . method || "" ) ;
if ( method === "tron_requestAccounts" || method === "requestAccounts" ) {
const r = await call ( "trx.requestAccounts" ) ;
applyConnection ( { address : r . address , network : r . network } ) ;
return { code : 200 , message : "ok" } ;
}
if ( method === "tron_accounts" ) {
const r = await call ( "trx.getAccount" ) . catch ( ( ) => null ) ;
return r ? [ r . address ] : [ ] ;
}
throw new Error ( "Aegis: unsupported tronLink method " + method ) ;
} ,
// Dapps sometimes attach here to react to wallet changes.
on : ( event , fn ) => {
if ( event === "message" || event === "accountsChanged" || event === "networkChanged" ) listeners . add ( fn ) ;
} ,
removeListener : ( _event , fn ) => listeners . delete ( fn ) ,
} ;
theseus . contextBridge . exposeInMainWorld ( "tronWeb" , tronWeb ) ;
theseus . contextBridge . exposeInMainWorld ( "tronLink" , tronLink ) ;