@@ -62,6 +62,8 @@ import {
6262 setDefaultFee as saveDefaultFee ,
6363 getFeeUnit ,
6464 setFeeUnit as saveFeeUnit ,
65+ getNetwork ,
66+ setNetwork as saveNetwork ,
6567 getActiveTab as getSavedTab ,
6668 setActiveTab as saveActiveTab ,
6769 getUnreadGame as getSavedUnreadGame ,
@@ -79,6 +81,8 @@ import {
7981 peekAlias ,
8082 setAlias ,
8183} from '../hooks/save' ;
84+ import type { ChiaNetwork } from '../lib/session/saveEnvelope' ;
85+ import { getCurrencyLabels } from '../constants/currency' ;
8286import {
8387 sessionController ,
8488 destroySessionController ,
@@ -100,6 +104,7 @@ import {
100104 isAvailableForNewSessionPrompt as checkAvailableForNewSessionPrompt ,
101105 isRestoreBlocked ,
102106 restoreGateAfterTerminalFinalization ,
107+ sessionLocksNetwork ,
103108 shouldCancelAttemptOnDisconnect ,
104109 shouldCancelOnPeerUnreachable ,
105110 shouldMountGameSession ,
@@ -132,6 +137,7 @@ import {
132137 isValidTimeoutString ,
133138 parseOptionalBigInt ,
134139 parseSessionAmount ,
140+ sessionProposalNetworkMatches ,
135141} from '../lib/session/peerSessionParams' ;
136142import { sessionModelForReactProps } from '../lib/session/finishedSessionDisplay' ;
137143import { finalizeTerminalSession } from '../lib/session/terminalFinalization' ;
@@ -245,6 +251,7 @@ function SessionBuyIn({
245251 channelTimeout ?: string ;
246252 unrollTimeout ?: string ;
247253} ) {
254+ const labels = getCurrencyLabels ( ) ;
248255 const effectiveChannelTimeout =
249256 parseOptionalBigInt ( channelTimeout ) ?? DEFAULT_CHANNEL_TIMEOUT_BLOCKS ;
250257 const effectiveUnrollTimeout =
@@ -253,7 +260,7 @@ function SessionBuyIn({
253260 return (
254261 < >
255262 < br />
256- Buy-in: < strong > { myAmount } </ strong > mojos
263+ Buy-in: < strong > { myAmount } </ strong > { labels . mojos }
257264 < br />
258265 Channel timeout: < strong > { effectiveChannelTimeout . toString ( ) } </ strong > blocks
259266 < br />
@@ -265,9 +272,9 @@ function SessionBuyIn({
265272 return (
266273 < >
267274 < br />
268- Your buy-in: < strong > { myAmount } </ strong > mojos
275+ Your buy-in: < strong > { myAmount } </ strong > { labels . mojos }
269276 < br />
270- Their buy-in: < strong > { theirAmount } </ strong > mojos
277+ Their buy-in: < strong > { theirAmount } </ strong > { labels . mojos }
271278 < br />
272279 Channel timeout: < strong > { effectiveChannelTimeout . toString ( ) } </ strong > blocks
273280 < br />
@@ -1055,6 +1062,7 @@ const Shell = () => {
10551062 const wcAbortRef = useRef ( false ) ;
10561063 const [ defaultFee , setDefaultFee ] = useState < bigint > ( ( ) => getDefaultFee ( ) ) ;
10571064 const [ feeUnit , setFeeUnit ] = useState < 'mojo' | 'xch' > ( ( ) => getFeeUnit ( ) ) ;
1065+ const [ network , setNetwork ] = useState < ChiaNetwork > ( ( ) => getNetwork ( ) ) ;
10581066 const [ feeEditing , setFeeEditing ] = useState ( false ) ;
10591067 const [ feeInput , setFeeInput ] = useState ( '' ) ;
10601068 const feeInputRef = useRef < HTMLInputElement > ( null ) ;
@@ -1133,6 +1141,8 @@ const Shell = () => {
11331141 [ feeEditing , feeInput , parseFeeInput ] ,
11341142 ) ;
11351143
1144+ const currency = getCurrencyLabels ( ) ;
1145+
11361146 // Theme state
11371147 const [ isDark , setIsDark ] = useState < boolean > ( ( ) => {
11381148 const stored = getTheme ( ) ;
@@ -1166,6 +1176,26 @@ const Shell = () => {
11661176 const sessionPhaseRef = useRef < SessionPhase > ( 'none' ) ;
11671177 sessionPhaseRef . current = sessionPhase ;
11681178
1179+ const networkLocked = sessionLocksNetwork (
1180+ sessionPhase ,
1181+ sessionSaveRef . current ?. phase ,
1182+ sessionConfig ?. pairingToken ,
1183+ ) ;
1184+
1185+ const handleNetworkChange = useCallback ( ( next : ChiaNetwork ) => {
1186+ if (
1187+ sessionLocksNetwork (
1188+ sessionPhaseRef . current ,
1189+ sessionSaveRef . current ?. phase ,
1190+ sessionConfigRef . current ?. pairingToken ,
1191+ )
1192+ ) {
1193+ return ;
1194+ }
1195+ setNetwork ( next ) ;
1196+ saveNetwork ( next ) ;
1197+ } , [ ] ) ;
1198+
11691199 const deferStateUpdate = useCallback ( ( fn : ( ) => void ) => {
11701200 if ( typeof queueMicrotask === 'function' ) {
11711201 queueMicrotask ( fn ) ;
@@ -1576,6 +1606,7 @@ const Shell = () => {
15761606 channel_timeout : advisory . channel_timeout ,
15771607 unroll_timeout : advisory . unroll_timeout ,
15781608 game_session_id : gameSessionId ,
1609+ network : getNetwork ( ) ,
15791610 } ) ;
15801611 await startFreshSessionWithPeer ( {
15811612 peerId : advisory . peer_id ,
@@ -1881,6 +1912,13 @@ const Shell = () => {
18811912 sendSessionReject ( fromId ) ;
18821913 return ;
18831914 }
1915+ if ( ! sessionProposalNetworkMatches ( msg . network , getNetwork ( ) ) ) {
1916+ log (
1917+ `[Shell] session_reject to=${ fromId } : proposal network mismatch theirs=${ msg . network ?? 'none' } mine=${ getNetwork ( ) } ` ,
1918+ ) ;
1919+ sendSessionReject ( fromId ) ;
1920+ return ;
1921+ }
18841922 const proposalSessionId = msg . game_session_id ?? generateSessionId ( ) ;
18851923 peerSessionRef . current ?. destroy ( ) ;
18861924 peerSessionRef . current = new PeerSession ( fromId , proposalSessionId , conn ) ;
@@ -3720,7 +3758,7 @@ const Shell = () => {
37203758 </ div >
37213759 { balance !== undefined && (
37223760 < p className = "text-2xl font-bold text-canvas-text-contrast" >
3723- { balance . toLocaleString ( ) } mojos
3761+ { balance . toLocaleString ( ) } { currency . mojos }
37243762 </ p >
37253763 ) }
37263764 < div className = "w-full max-w-xs text-sm text-canvas-text" >
@@ -3731,13 +3769,13 @@ const Shell = () => {
37313769 onClick = { ( ) => handleFeeUnitChange ( 'mojo' ) }
37323770 className = { `px-2 py-0.5 transition-colors ${ feeUnit === 'mojo' ? 'bg-canvas-bg-active font-semibold' : 'hover:bg-canvas-bg-hover' } ` }
37333771 >
3734- mojo
3772+ { currency . mojo }
37353773 </ button >
37363774 < button
37373775 onClick = { ( ) => handleFeeUnitChange ( 'xch' ) }
37383776 className = { `px-2 py-0.5 transition-colors border-l border-canvas-border ${ feeUnit === 'xch' ? 'bg-canvas-bg-active font-semibold' : 'hover:bg-canvas-bg-hover' } ` }
37393777 >
3740- XCH
3778+ { currency . xch }
37413779 </ button >
37423780 </ div >
37433781 </ div >
@@ -3774,7 +3812,7 @@ const Shell = () => {
37743812 onClick = { startEditingFee }
37753813 className = "w-full text-left px-3 py-2 rounded-md bg-canvas-bg-subtle text-canvas-text border border-canvas-border hover:bg-canvas-bg-hover transition-colors cursor-pointer"
37763814 >
3777- { feeDisplayText ( ) } { feeUnit === 'xch' ? 'XCH' : ' mojos' }
3815+ { feeDisplayText ( ) } { feeUnit === 'xch' ? currency . xch : currency . mojos }
37783816 </ button >
37793817 ) }
37803818 </ div >
@@ -3851,13 +3889,13 @@ const Shell = () => {
38513889 onClick = { ( ) => handleFeeUnitChange ( 'mojo' ) }
38523890 className = { `px-2 py-0.5 transition-colors ${ feeUnit === 'mojo' ? 'bg-canvas-bg-active font-semibold' : 'hover:bg-canvas-bg-hover' } ` }
38533891 >
3854- mojo
3892+ { currency . mojo }
38553893 </ button >
38563894 < button
38573895 onClick = { ( ) => handleFeeUnitChange ( 'xch' ) }
38583896 className = { `px-2 py-0.5 transition-colors border-l border-canvas-border ${ feeUnit === 'xch' ? 'bg-canvas-bg-active font-semibold' : 'hover:bg-canvas-bg-hover' } ` }
38593897 >
3860- XCH
3898+ { currency . xch }
38613899 </ button >
38623900 </ div >
38633901 </ div >
@@ -3894,7 +3932,7 @@ const Shell = () => {
38943932 onClick = { startEditingFee }
38953933 className = "w-full text-left px-3 py-2 rounded-md bg-canvas-bg-subtle text-canvas-text border border-canvas-border hover:bg-canvas-bg-hover transition-colors cursor-pointer"
38963934 >
3897- { feeDisplayText ( ) } { feeUnit === 'xch' ? 'XCH' : ' mojos' }
3935+ { feeDisplayText ( ) } { feeUnit === 'xch' ? currency . xch : currency . mojos }
38983936 </ button >
38993937 ) }
39003938 </ div >
@@ -3932,6 +3970,32 @@ const Shell = () => {
39323970 ) : (
39333971 < div className = "flex flex-col justify-center items-center w-full px-4 py-6 gap-4" >
39343972 < p className = "text-lg font-semibold text-canvas-text-contrast" > Choose Connection</ p >
3973+ < div className = "w-full max-w-sm flex flex-col items-center gap-1" >
3974+ < span className = "text-sm text-canvas-text" > Network</ span >
3975+ < div className = "flex rounded-md border border-canvas-border overflow-hidden text-xs" >
3976+ < button
3977+ type = "button"
3978+ disabled = { networkLocked }
3979+ onClick = { ( ) => handleNetworkChange ( 'mainnet' ) }
3980+ className = { `px-3 py-1 transition-colors ${ network === 'mainnet' ? 'bg-canvas-bg-active font-semibold' : networkLocked ? '' : 'hover:bg-canvas-bg-hover' } ${ networkLocked ? 'opacity-40 cursor-default' : '' } ` }
3981+ >
3982+ Mainnet
3983+ </ button >
3984+ < button
3985+ type = "button"
3986+ disabled = { networkLocked }
3987+ onClick = { ( ) => handleNetworkChange ( 'testnet' ) }
3988+ className = { `px-3 py-1 transition-colors border-l border-canvas-border ${ network === 'testnet' ? 'bg-canvas-bg-active font-semibold' : networkLocked ? '' : 'hover:bg-canvas-bg-hover' } ${ networkLocked ? 'opacity-40 cursor-default' : '' } ` }
3989+ >
3990+ Testnet
3991+ </ button >
3992+ </ div >
3993+ { networkLocked && (
3994+ < p className = "text-xs text-canvas-text text-center" >
3995+ Network is locked for this session
3996+ </ p >
3997+ ) }
3998+ </ div >
39353999 < div className = "w-full max-w-sm flex flex-col gap-3" >
39364000 < Button
39374001 variant = "solid"
0 commit comments