@@ -428,9 +428,20 @@ <h3>Browser-side key generation</h3>
428428 Wallet connection is required to write records under your ENS name.< br >
429429 Payment/provisioning is required for CommandLayer-native namespace activation.
430430 </ div >
431+
432+ < div style ="margin-top:16px;padding:14px;border-radius:12px;border:1px solid var(--border);background:#fff ">
433+ < div style ="font-weight:700;margin-bottom:6px "> Sign in with Ethereum</ div >
434+ < div style ="font-size:13px;color:var(--text-2);margin-bottom:10px "> Authenticate the wallet that will submit this activation request.</ div >
435+ < div style ="font-size:12px;color:var(--muted);margin-bottom:10px "> Your Ethereum wallet authenticates the claim request. Your Ed25519 key signs agent receipts.</ div >
436+ < button class ="btn btn-secondary " id ="siweAuthBtn " onclick ="signInWithEthereum() "> Sign-In with Ethereum</ button >
437+ < div id ="siweStatus " style ="font-size:13px;color:var(--text-2);margin-top:10px "> Status: Not authenticated</ div >
438+ < div id ="siweWallet " style ="font-family:var(--mono);font-size:12px;color:var(--muted);margin-top:4px "> </ div >
439+ < div id ="siweModeHint " style ="font-size:12px;color:var(--muted);margin-top:8px "> </ div >
440+ </ div >
441+
431442 < div class ="btn-row ">
432443 < button class ="btn btn-ghost " onclick ="goToStep(4) "> ← Back</ button >
433- < button class ="btn btn-primary " onclick ="goToStep(6 ) "> Continue →</ button >
444+ < button class ="btn btn-primary " onclick ="goStep5Auth( ) "> Continue →</ button >
434445 </ div >
435446 </ div >
436447
@@ -573,7 +584,8 @@ <h3>Payment and provisioning are coming next.</h3>
573584 capMode :'packs' , selectedPack :null , cherryVerbs :[ ] ,
574585 pubKeyB64 :'' , privKeyB64 :'' , kid :'' ,
575586 keyGenerated :false , keyDownloaded :false , keyAcked :false ,
576- _cardJson :''
587+ _cardJson :'' ,
588+ authenticatedAddress :'' , authStatus :'NOT_AUTHENTICATED' , authChainId :null
577589} ;
578590
579591// ── HELPERS ───────────────────────────────────────────────────────────────────
@@ -665,6 +677,7 @@ <h3>Payment and provisioning are coming next.</h3>
665677 document . getElementById ( 'mode-' + id ) . classList . toggle ( 'selected' , id === m ) ;
666678 } ) ;
667679 updateNamePreview ( ) ;
680+ updateSiweModeHint ( ) ;
668681}
669682
670683function updateNamePreview ( ) {
@@ -685,11 +698,13 @@ <h3>Payment and provisioning are coming next.</h3>
685698 if ( ! state . activationMode ) { alert ( 'Please choose an activation mode.' ) ; return ; }
686699 // default to CL mode if none selected
687700 if ( ! document . querySelector ( '.mode-card.selected' ) ) selectMode ( 'cl' ) ;
701+ updateSiweModeHint ( ) ;
688702 goToStep ( 3 ) ;
689703}
690704
691705// Auto-select CL mode on load
692706selectMode ( 'cl' ) ;
707+ updateSiweModeHint ( ) ;
693708
694709// ── STEP 3: CAPABILITIES ──────────────────────────────────────────────────────
695710function setCapMode ( m ) {
@@ -754,6 +769,63 @@ <h3>Payment and provisioning are coming next.</h3>
754769 goToStep ( 4 ) ;
755770}
756771
772+
773+
774+ function shortAddr ( addr ) { return addr ?`${ addr . slice ( 0 , 6 ) } ...${ addr . slice ( - 4 ) } ` :'' ; }
775+
776+ function updateSiweModeHint ( ) {
777+ const el = document . getElementById ( 'siweModeHint' ) ;
778+ if ( ! el ) return ;
779+ if ( state . activationMode === 'own' || state . activationMode === 'single' ) {
780+ el . textContent = 'ENS ownership verification comes after wallet authentication.' ;
781+ } else {
782+ el . textContent = 'CommandLayer namespace activation requires wallet authentication before submission.' ;
783+ }
784+ }
785+
786+ async function signInWithEthereum ( ) {
787+ if ( ! window . ethereum ) { alert ( 'No Ethereum wallet detected. Install a wallet extension first.' ) ; return ; }
788+ updateSiweModeHint ( ) ;
789+ const statusEl = document . getElementById ( 'siweStatus' ) ;
790+ const walletEl = document . getElementById ( 'siweWallet' ) ;
791+ statusEl . textContent = 'Status: Requesting signature...' ;
792+ const [ address ] = await window . ethereum . request ( { method :'eth_requestAccounts' } ) ;
793+ const nonceRes = await fetch ( '/api/auth/nonce' , { method :'GET' , headers :{ 'Accept' :'application/json' } } ) ;
794+ const nonceData = await nonceRes . json ( ) ;
795+ if ( ! nonceData . ok ) { throw new Error ( 'Nonce request failed' ) ; }
796+ const domain = window . location . host ;
797+ const uri = window . location . origin ;
798+ const chainHex = await window . ethereum . request ( { method :'eth_chainId' } ) ;
799+ const chainId = parseInt ( chainHex , 16 ) ;
800+ const issuedAt = new Date ( ) . toISOString ( ) ;
801+ const msg = `${ domain } wants you to sign in with your Ethereum account:
802+ ${ address }
803+
804+ CommandLayer Claim activation
805+
806+ URI: ${ uri }
807+ Version: 1
808+ Chain ID: ${ chainId }
809+ Nonce: ${ nonceData . nonce }
810+ Issued At: ${ issuedAt } ` ;
811+ const signature = await window . ethereum . request ( { method :'personal_sign' , params :[ msg , address ] } ) ;
812+ const verifyRes = await fetch ( '/api/auth/verify' , { method :'POST' , headers :{ 'Content-Type' :'application/json' } , body :JSON . stringify ( { message :msg , signature} ) } ) ;
813+ const verify = await verifyRes . json ( ) ;
814+ if ( ! verify . ok ) { throw new Error ( verify . error || 'Authentication failed' ) ; }
815+ state . authenticatedAddress = verify . address ; state . authStatus = verify . status ; state . authChainId = verify . chainId ;
816+ statusEl . textContent = 'Status: Authenticated' ;
817+ walletEl . textContent = `Connected wallet: ${ shortAddr ( verify . address ) } ` ;
818+ }
819+
820+ function goStep5Auth ( ) {
821+ updateSiweModeHint ( ) ;
822+ if ( state . activationMode === 'cl' && ! state . authenticatedAddress ) {
823+ alert ( 'Sign-In with Ethereum is required before submitting CommandLayer activation request.' ) ;
824+ return ;
825+ }
826+ goToStep ( 6 ) ;
827+ }
828+
757829// ── STEP 4: KEY GEN ───────────────────────────────────────────────────────────
758830async function generateKey ( ) {
759831 const errorBox = document . getElementById ( 'keyError' ) ;
@@ -1073,6 +1145,7 @@ <h3>Payment and provisioning are coming next.</h3>
10731145 const err = document . getElementById ( 'keyError' ) ; if ( err ) { err . classList . remove ( 'show' ) ; err . textContent = '' ; }
10741146 document . getElementById ( 'namePreview' ) . classList . remove ( 'show' ) ;
10751147 selectMode ( 'cl' ) ;
1148+ updateSiweModeHint ( ) ;
10761149 goToStep ( 1 ) ;
10771150}
10781151
0 commit comments