Sovereign V2 Genesis Push#13
Conversation
… with conflict resolution Co-authored-by: Freedomwithin <166790647+Freedomwithin@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Reviewer's GuideImplements the first version of the TrustChain notary on-chain program plus a backend notary sync script, and wires them into the existing integrity engine and frontend via a reusable hook and guard component, while standardizing the PDA seed to "config" for integrity data storage. Sequence diagram for frontend integrity verification flowsequenceDiagram
actor User
participant FrontendGuard as Frontend_Guard
participant UseIntegrityHook as UseIntegrity_Hook
participant WalletAdapter as Wallet_Adapter
participant BackendAPI as Backend_API
User->>FrontendGuard: Navigate to protected feature
FrontendGuard->>UseIntegrityHook: useIntegrity()
UseIntegrityHook->>WalletAdapter: Read publicKey, connected
alt Wallet connected
UseIntegrityHook->>BackendAPI: POST /api/verify { address }
BackendAPI-->>UseIntegrityHook: { giniScore, hhiScore, status }
UseIntegrityHook-->>FrontendGuard: { giniScore, status, loading=false, error=null }
FrontendGuard->>FrontendGuard: Compute isSybil based on threshold and status
alt isSybil
FrontendGuard-->>User: Show blocked fallback or default guard-blocked UI
else not Sybil
FrontendGuard-->>User: Render protected children content
end
else Wallet not connected
UseIntegrityHook-->>FrontendGuard: { giniScore=null, status=null, loading=false }
FrontendGuard-->>User: Prompt to connect wallet or show neutral UI
end
Sequence diagram for backend notary sync to on-chain programsequenceDiagram
participant NotarySyncScript as Notary_Sync_Script
participant Env as Environment
participant IntegrityEngine as Integrity_Engine
participant SolanaRPC as Solana_RPC
participant TrustchainProgram as Trustchain_Notary_Program
NotarySyncScript->>Env: Load NOTARY_SECRET
Env-->>NotarySyncScript: Secret key bytes
NotarySyncScript->>NotarySyncScript: Derive NOTARY_KEYPAIR
NotarySyncScript->>IntegrityEngine: fetchVerifiedScore(MOCK_WALLET)
IntegrityEngine-->>NotarySyncScript: IntegrityScore { gini, hhi, status }
NotarySyncScript->>SolanaRPC: getLatestBlockhash()
SolanaRPC-->>NotarySyncScript: blockhash
NotarySyncScript->>NotarySyncScript: Derive PDA with seeds ["config", wallet]
NotarySyncScript->>NotarySyncScript: Build instruction data (discriminator + gini + hhi + status)
NotarySyncScript->>NotarySyncScript: Create Transaction with accounts [user_integrity PDA, user, notary, system_program]
NotarySyncScript->>NotarySyncScript: Sign transaction with NOTARY_KEYPAIR
NotarySyncScript->>NotarySyncScript: Verify signatures via transaction.verifySignatures()
NotarySyncScript->>NotarySyncScript: Verify Ed25519 with nacl.sign.detached.verify
alt Signature valid
NotarySyncScript-->>TrustchainProgram: Submit signed transaction update_integrity
TrustchainProgram->>TrustchainProgram: Check notary signer matches NOTARY_PUBKEY
TrustchainProgram->>TrustchainProgram: Update UserIntegrity account at PDA
TrustchainProgram-->>NotarySyncScript: Success
else Invalid signature
NotarySyncScript-->>NotarySyncScript: Throw Security Violation error
end
Class diagram for new frontend integrity hook and guard componentclassDiagram
class IntegrityData {
+number giniScore
+number hhiScore
+string status
+boolean loading
+string error
}
class UseIntegrityHookModule {
+API_BASE_URL : string
+useIntegrity() IntegrityData
}
class GuardProps {
+ReactNode children
+ReactNode fallback
+number threshold
+string sybilStatus
}
class GuardComponent {
+Guard(props GuardProps) ReactNode
}
class IntegrityConstants {
+number PROBATIONARY_THRESHOLD
+string SYBIL_STATUS
}
UseIntegrityHookModule --> IntegrityData : returns
GuardComponent --> GuardProps : uses
GuardComponent --> UseIntegrityHookModule : calls_useIntegrity
GuardComponent --> IntegrityConstants : reads_thresholds
Class diagram for on-chain TrustChain notary program and accountsclassDiagram
class TrustchainNotaryProgram {
+update_integrity(ctx UpdateIntegrity, gini_score u16, hhi_score u16, status u8) Result
}
class UpdateIntegrity {
+Account~UserIntegrity~ user_integrity
+UncheckedAccount user
+Signer notary
+Program~System~ system_program
}
class UserIntegrity {
+u16 gini_score
+u16 hhi_score
+u8 status
+i64 last_updated
}
class GlobalConfig {
+u8 bump
}
class TrustChainError {
<<enumeration>>
UnauthorizedNotary
}
TrustchainNotaryProgram --> UpdateIntegrity : uses_context
UpdateIntegrity --> UserIntegrity : initializes_updates
TrustchainNotaryProgram --> TrustChainError : returns_on_error
GlobalConfig <.. TrustchainNotaryProgram : PDA_config_account
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- The
notary_sync.tsscript mixes runtime configuration with module initialization (e.g., throwing ifNOTARY_SECRETis missing and parsing it at import time); consider moving the env validation/parsing intomain()so importing or tooling around this file doesn’t immediately crash the process. - Several values that are likely environment-specific are currently hardcoded (e.g., the devnet RPC URL in
notary_sync.ts, the defaultAPI_BASE_URLinuseIntegrity, and the program ID/NOTARY_PUBKEY in the on-chain code); it would be safer to drive these from configuration or env vars to avoid accidental misuse across environments. - The mapping between integrity
statusstrings in the backend script (VERIFIED,PROBATIONARY, etc.) and the on-chainstatus: u8field is implicit—consider extracting a shared constant/enum (or at least a clearly documented mapping) to reduce the risk of mismatches as statuses evolve.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `notary_sync.ts` script mixes runtime configuration with module initialization (e.g., throwing if `NOTARY_SECRET` is missing and parsing it at import time); consider moving the env validation/parsing into `main()` so importing or tooling around this file doesn’t immediately crash the process.
- Several values that are likely environment-specific are currently hardcoded (e.g., the devnet RPC URL in `notary_sync.ts`, the default `API_BASE_URL` in `useIntegrity`, and the program ID/NOTARY_PUBKEY in the on-chain code); it would be safer to drive these from configuration or env vars to avoid accidental misuse across environments.
- The mapping between integrity `status` strings in the backend script (`VERIFIED`, `PROBATIONARY`, etc.) and the on-chain `status: u8` field is implicit—consider extracting a shared constant/enum (or at least a clearly documented mapping) to reduce the risk of mismatches as statuses evolve.
## Individual Comments
### Comment 1
<location> `backend/services/notary_sync.ts:19-28` </location>
<code_context>
+const MOCK_WALLET = new PublicKey("11111111111111111111111111111111");
+
+// Load Notary Secret from Environment Variable
+if (!process.env.NOTARY_SECRET) {
+ throw new Error("NOTARY_SECRET environment variable not set. Please set it in .env file.");
+}
+
+// Support both JSON array format and Hex string format for convenience
+let notarySecret: Uint8Array;
+try {
+ const parsed = JSON.parse(process.env.NOTARY_SECRET);
+ if (Array.isArray(parsed)) {
+ notarySecret = new Uint8Array(parsed);
+ } else {
+ throw new Error("NOTARY_SECRET JSON is not an array");
+ }
+} catch (e) {
+ // If not JSON, try Hex
+ // Remove '0x' prefix if present
+ const cleanHex = process.env.NOTARY_SECRET.replace(/^0x/, '');
+ if (/^[0-9a-fA-F]+$/.test(cleanHex)) {
+ notarySecret = Uint8Array.from(Buffer.from(cleanHex, 'hex'));
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Tighten NOTARY_SECRET validation to avoid ambiguous or malformed key material
Currently any hex string is accepted and only fails later inside `Keypair.fromSecretKey` if the length is wrong. Consider checking that the decoded `Uint8Array` has the expected length (e.g., 64 bytes) before constructing the keypair, and throwing a clear error when it doesn’t.
Suggested implementation:
```typescript
dotenv.config();
const NOTARY_SECRET_KEY_LENGTH = 64;
// Mock data
const MOCK_WALLET = new PublicKey("11111111111111111111111111111111");
```
```typescript
if (/^[0-9a-fA-F]+$/.test(cleanHex)) {
notarySecret = Uint8Array.from(Buffer.from(cleanHex, 'hex'));
} else {
throw new Error("Invalid NOTARY_SECRET format. Must be JSON array of numbers or Hex string.");
}
}
if (!notarySecret || notarySecret.length !== NOTARY_SECRET_KEY_LENGTH) {
throw new Error(
`NOTARY_SECRET must decode to a ${NOTARY_SECRET_KEY_LENGTH}-byte secret key; got ${notarySecret ? notarySecret.length : 0} bytes.`
);
}
const NOTARY_KEYPAIR = Keypair.fromSecretKey(notarySecret);
```
</issue_to_address>
### Comment 2
<location> `backend/services/notary_sync.ts:69` </location>
<code_context>
+ // Connect to devnet (or localnet)
+ const connection = new Connection("https://api.devnet.solana.com", "confirmed");
+
+ // PDA derivation: seeds = [b"integrity", user.key().as_ref()]
+ const [pda] = PublicKey.findProgramAddressSync(
+ [Buffer.from("config"), wallet.toBuffer()],
+ PROGRAM_ID
+ );
</code_context>
<issue_to_address>
**suggestion (typo):** Align PDA seed comment with actual implementation (`config` vs `integrity`)
The inline comment still refers to `[b"integrity", user.key().as_ref()]`, but the actual PDA uses `["config", wallet]`. Please update the comment to match the real seeds (`"config"` + wallet) to avoid confusion when working with the PDA or comparing against the on-chain Anchor account definition.
```suggestion
// PDA derivation: seeds = [b"config", wallet.toBuffer()]
```
</issue_to_address>
### Comment 3
<location> `docs/FAIRSCALE_API.md:18` </location>
<code_context>
+- **URL:** `https://api.fairscale.xyz/v1/reputation/:address` (Hypothetical endpoint)
+- **Method:** `GET`
+- **Params:**
+ - `address`: The Solana wallet address (Base58 encoded).
+
+#### Response
</code_context>
<issue_to_address>
**nitpick (typo):** Consider hyphenating "Base58 encoded" to "Base58-encoded" for grammatical correctness.
Because it modifies “wallet address” as a compound adjective, the hyphenated form is preferred.
```suggestion
- `address`: The Solana wallet address (Base58-encoded).
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| if (!process.env.NOTARY_SECRET) { | ||
| throw new Error("NOTARY_SECRET environment variable not set. Please set it in .env file."); | ||
| } | ||
|
|
||
| // Support both JSON array format and Hex string format for convenience | ||
| let notarySecret: Uint8Array; | ||
| try { | ||
| const parsed = JSON.parse(process.env.NOTARY_SECRET); | ||
| if (Array.isArray(parsed)) { | ||
| notarySecret = new Uint8Array(parsed); |
There was a problem hiding this comment.
suggestion (bug_risk): Tighten NOTARY_SECRET validation to avoid ambiguous or malformed key material
Currently any hex string is accepted and only fails later inside Keypair.fromSecretKey if the length is wrong. Consider checking that the decoded Uint8Array has the expected length (e.g., 64 bytes) before constructing the keypair, and throwing a clear error when it doesn’t.
Suggested implementation:
dotenv.config();
const NOTARY_SECRET_KEY_LENGTH = 64;
// Mock data
const MOCK_WALLET = new PublicKey("11111111111111111111111111111111"); if (/^[0-9a-fA-F]+$/.test(cleanHex)) {
notarySecret = Uint8Array.from(Buffer.from(cleanHex, 'hex'));
} else {
throw new Error("Invalid NOTARY_SECRET format. Must be JSON array of numbers or Hex string.");
}
}
if (!notarySecret || notarySecret.length !== NOTARY_SECRET_KEY_LENGTH) {
throw new Error(
`NOTARY_SECRET must decode to a ${NOTARY_SECRET_KEY_LENGTH}-byte secret key; got ${notarySecret ? notarySecret.length : 0} bytes.`
);
}
const NOTARY_KEYPAIR = Keypair.fromSecretKey(notarySecret);| // Connect to devnet (or localnet) | ||
| const connection = new Connection("https://api.devnet.solana.com", "confirmed"); | ||
|
|
||
| // PDA derivation: seeds = [b"integrity", user.key().as_ref()] |
There was a problem hiding this comment.
suggestion (typo): Align PDA seed comment with actual implementation (config vs integrity)
The inline comment still refers to [b"integrity", user.key().as_ref()], but the actual PDA uses ["config", wallet]. Please update the comment to match the real seeds ("config" + wallet) to avoid confusion when working with the PDA or comparing against the on-chain Anchor account definition.
| // PDA derivation: seeds = [b"integrity", user.key().as_ref()] | |
| // PDA derivation: seeds = [b"config", wallet.toBuffer()] |
| - **URL:** `https://api.fairscale.xyz/v1/reputation/:address` (Hypothetical endpoint) | ||
| - **Method:** `GET` | ||
| - **Params:** | ||
| - `address`: The Solana wallet address (Base58 encoded). |
There was a problem hiding this comment.
nitpick (typo): Consider hyphenating "Base58 encoded" to "Base58-encoded" for grammatical correctness.
Because it modifies “wallet address” as a compound adjective, the hyphenated form is preferred.
| - `address`: The Solana wallet address (Base58 encoded). | |
| - `address`: The Solana wallet address (Base58-encoded). |
PR created automatically by Jules for task 15335853524727996490 started by @Freedomwithin
Summary by Sourcery
Integrate an on-chain notary program with backend and frontend integrity checks, adding support for syncing verified integrity scores to Solana and gating protected actions in the UI based on wallet integrity.
New Features:
trustchain-notaryprogram to store and update per-user integrity scores under aconfig-seeded PDA.Build:
Documentation: