-
Notifications
You must be signed in to change notification settings - Fork 13
Fix: Connected accounts can now claim via whitelisted root (#24) #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
5bb6618
e480b45
e5ac108
9bd79df
c1df3a9
e448c83
d7f059e
902eddd
ccae930
8d179ce
3f0642f
edc8094
efd20d6
e218df6
0955bef
a1f19d2
7e52bd0
0fe046d
a927b9a
547951f
18bde41
aca253c
1cfd097
0344180
5096bf4
f6eb039
7442ed9
6132ef6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| #!/bin/bash | ||
| # Helper script to run connected accounts tests with example addresses | ||
| # | ||
| # Usage: | ||
| # ./run-test.sh | ||
| # | ||
| # Or with custom addresses: | ||
| # MAIN_ACCOUNT=0x... CONNECTED_ACCOUNT=0x... ./run-test.sh | ||
|
|
||
| # Example test addresses (replace with real ones) | ||
| # These are example addresses - you need to replace them with actual test accounts | ||
| MAIN_ACCOUNT=${MAIN_ACCOUNT:-"0x0000000000000000000000000000000000000000"} | ||
| CONNECTED_ACCOUNT=${CONNECTED_ACCOUNT:-"0x0000000000000000000000000000000000000000"} | ||
| NON_WHITELISTED_ACCOUNT=${NON_WHITELISTED_ACCOUNT:-"0x0000000000000000000000000000000000000000"} | ||
| ENV=${ENV:-"development"} | ||
|
|
||
| echo "🧪 Running Connected Accounts SDK Test (TypeScript)" | ||
| echo "" | ||
| echo "Configuration:" | ||
| echo " Main Account: $MAIN_ACCOUNT" | ||
| echo " Connected Account: $CONNECTED_ACCOUNT" | ||
| echo " Non-Whitelisted: $NON_WHITELISTED_ACCOUNT" | ||
| echo " Environment: $ENV" | ||
| echo "" | ||
|
|
||
| MAIN_ACCOUNT=$MAIN_ACCOUNT \ | ||
| CONNECTED_ACCOUNT=$CONNECTED_ACCOUNT \ | ||
| NON_WHITELISTED_ACCOUNT=$NON_WHITELISTED_ACCOUNT \ | ||
| ENV=$ENV \ | ||
| npx tsx test/connected-accounts.ts |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,4 @@ | ||
| import { | ||
| type Account, | ||
| type Address, | ||
| type Chain, | ||
| type PublicClient, | ||
| type SimulateContractParameters, | ||
| type WalletClient, | ||
| ContractFunctionExecutionError, | ||
| TransactionReceipt, | ||
| } from "viem" | ||
| import { zeroAddress, type Account, type Address, type Chain, type PublicClient, type SimulateContractParameters, type WalletClient, ContractFunctionExecutionError, TransactionReceipt } from "viem" | ||
|
||
|
|
||
| import { waitForTransactionReceipt } from "viem/actions" | ||
|
|
||
|
|
@@ -83,6 +74,7 @@ export class ClaimSDK { | |
| private readonly account: Address | ||
| private readonly env: contractEnv | ||
| public readonly rdu: string | ||
| private whitelistedRootCache: Address | null = null | ||
L03TJ3 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| constructor({ | ||
| account, | ||
|
|
@@ -164,6 +156,51 @@ export class ClaimSDK { | |
| return this.chainId | ||
| } | ||
|
|
||
| /** | ||
| * Resolves the whitelisted root address for the connected account. | ||
| * This enables connected accounts to claim on behalf of their main whitelisted account. | ||
| * | ||
| * Failure modes are normalized so callers see predictable behavior: | ||
| * - Throws when no whitelisted root exists for the connected account. | ||
| * - Throws when the SDK cannot resolve a whitelisted root (network / domain errors). | ||
| * | ||
| * @returns The whitelisted root address to use for entitlement checks. | ||
| * @throws Error if no whitelisted root exists or resolution fails for any reason. | ||
| */ | ||
| private async getWhitelistedRootAddress(): Promise<Address> { | ||
sirpy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // Return cached value if available | ||
| if (this.whitelistedRootCache) { | ||
sirpy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return this.whitelistedRootCache | ||
| } | ||
|
|
||
| try { | ||
| // Resolve the whitelisted root for this account | ||
| const { root, isWhitelisted } = await this.identitySDK.getWhitelistedRoot(this.account) | ||
|
|
||
| // Normalize "no root" / "not whitelisted" cases | ||
| if (!isWhitelisted || !root || root === zeroAddress) { | ||
sirpy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| throw new Error( | ||
| "No whitelisted root address found for connected account; the user may not be whitelisted.", | ||
| ) | ||
| } | ||
|
|
||
| // Cache the result | ||
| this.whitelistedRootCache = root | ||
|
|
||
| return root | ||
| } catch (error) { | ||
| // Normalize SDK and transport errors into a predictable failure mode | ||
| const message = | ||
| error instanceof Error && error.message | ||
| ? error.message | ||
| : String(error) | ||
|
|
||
| throw new Error( | ||
| `Unable to resolve whitelisted root address for connected account: ${message}`, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| private async readChainEntitlement( | ||
| chainId: SupportedChains, | ||
| client?: PublicClient, | ||
|
|
@@ -184,12 +221,16 @@ export class ClaimSDK { | |
| altClient = resolvedClient | ||
| } | ||
|
|
||
| // Use whitelisted root address for entitlement check | ||
| // This enables connected accounts to claim on behalf of their main account | ||
| const rootAddress = await this.getWhitelistedRootAddress() | ||
|
|
||
| return this.readContract<bigint>( | ||
| { | ||
| address: contracts.ubiContract as Address, | ||
| abi: ubiSchemeV2ABI, | ||
| functionName: "checkEntitlement", | ||
| args: [this.account], | ||
| args: [rootAddress], | ||
| }, | ||
| altClient, | ||
| chainId, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| # Connected Accounts Test Script | ||
|
||
|
|
||
| This directory contains a standalone test script to verify the connected accounts claiming flow works correctly. | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Basic Usage | ||
|
|
||
| ```bash | ||
| npx tsx test/connected-accounts.ts | ||
| ``` | ||
|
|
||
| Or use the npm script: | ||
|
|
||
| ```bash | ||
| npm run test:connected | ||
| ``` | ||
|
|
||
| ### With Environment Variables | ||
|
|
||
| ```bash | ||
| MAIN_ACCOUNT=0x1234... \ | ||
| CONNECTED_ACCOUNT=0x5678... \ | ||
| NON_WHITELISTED_ACCOUNT=0x9abc... \ | ||
| ENV=development \ | ||
| npx tsx test/connected-accounts.ts | ||
| ``` | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| | Variable | Description | Required | Default | | ||
| |----------|-------------|----------|---------| | ||
| | `MAIN_ACCOUNT` | Main whitelisted account address | No | 0x0...0 | | ||
| | `CONNECTED_ACCOUNT` | Account connected to main account | No | 0x0...0 | | ||
| | `NON_WHITELISTED_ACCOUNT` | Non-whitelisted account | No | 0x0...0 | | ||
| | `ENV` | Environment (development/staging/production) | No | development | | ||
| | `RPC_URL` | Custom RPC URL | No | https://forno.celo.org | | ||
|
|
||
| ## What It Tests | ||
|
|
||
| 1. **Main Account Resolution** - Verifies main whitelisted account returns itself as root | ||
| 2. **Connected Account Resolution** - Verifies connected account returns main account as root | ||
| 3. **Non-Whitelisted Account** - Verifies non-whitelisted account returns 0x0 | ||
| 4. **Main Account Entitlement** - Verifies entitlement check works for main account | ||
| 5. **Connected Account Entitlement** - Verifies entitlement check uses root address (simulating SDK behavior) | ||
|
|
||
| ## Example Output | ||
|
|
||
| ``` | ||
| 🧪 Testing Connected Accounts Claiming Flow | ||
|
|
||
| Environment: development | ||
| RPC: https://forno.celo.org | ||
| Identity Contract: 0xF25fA0D4896271228193E782831F6f3CFCcF169C | ||
| UBI Contract: 0x6B86F82293552C3B9FE380FC038A89e0328C7C5f | ||
|
|
||
| Test 1: Main whitelisted account | ||
| ✓ Main account is whitelisted | ||
| Root: 0x1234... | ||
|
|
||
| Test 2: Connected account resolution | ||
| ✓ Connected account resolves to main | ||
| Root: 0x1234... | ||
|
|
||
| Test 3: Non-whitelisted account | ||
| ✓ Non-whitelisted account returns 0x0 | ||
| Root: 0x0000000000000000000000000000000000000000 | ||
|
|
||
| Test 4: Entitlement check (main account) | ||
| ✓ Main account entitlement retrieved | ||
| Entitlement: 1000000000000000000 | ||
|
|
||
| Test 5: Entitlement check (connected account → root) | ||
| ✓ Connected account entitlement via root | ||
| Root: 0x1234..., Entitlement: 1000000000000000000 | ||
|
|
||
| ================================================== | ||
|
|
||
| Test Results: 5/5 passed | ||
|
|
||
| ✅ All tests passed! Connected accounts flow is working correctly. | ||
| ``` | ||
|
|
||
| ## Integration with CI/CD | ||
|
|
||
| Add to your CI pipeline: | ||
|
|
||
| ```yaml | ||
| # .github/workflows/test.yml | ||
| - name: Test Connected Accounts | ||
| run: | | ||
| cd packages/citizen-sdk | ||
| MAIN_ACCOUNT=${{ secrets.TEST_MAIN_ACCOUNT }} \ | ||
| CONNECTED_ACCOUNT=${{ secrets.TEST_CONNECTED_ACCOUNT }} \ | ||
| NON_WHITELISTED_ACCOUNT=${{ secrets.TEST_NON_WHITELISTED }} \ | ||
| ENV=development \ | ||
| npm run test:connected | ||
| ``` | ||
|
|
||
| ## Notes | ||
|
|
||
| - This script only tests contract interactions, not the full SDK | ||
| - Requires valid test accounts to be set via environment variables | ||
| - Uses read-only contract calls (no transactions) | ||
| - No private key needed (read-only operations) | ||
Uh oh!
There was an error while loading. Please reload this page.