A Next.js application for managing vaults, wallets, users, and policies for NGO administration.
- ✅ Create vaults for NGO admins (by email) - Integrated with Dynamic Labs
- ✅ Create multiple wallets under a vault - Dynamic wallet creation via Dynamic Labs API
- ✅ Associate wallets with user identities (email)
- ✅ Delegate access to other users (by email) - Integrated with Dynamic Labs Delegated Access
- ✅ Create and retrieve policies (spending limits, multi-sig rules, etc.) for wallets or vaults - Integrated with Dynamic Labs Policy Engine
- ✅ Simple internal UI for all operations
This POC integrates with Dynamic Labs for:
- Vault Creation: Creates users in Dynamic Labs when creating vaults
- Wallet Creation: Creates embedded wallets using Dynamic Labs API
- Policy Management: Creates and manages policies via Dynamic Labs Policy Engine
- Delegated Access: Allows delegating wallet access to other users via Dynamic Labs Delegated Access
The integration is optional - if Dynamic Labs credentials are not configured, the app will work in local-only mode.
- Node.js 18+ installed
- npm or yarn package manager
- Dynamic Labs account and API credentials (optional, for full integration)
- Install dependencies:
npm install- Set up environment variables (optional, for Dynamic Labs integration):
cp .env.example .envEdit .env and add your Dynamic Labs credentials:
DYNAMIC_ENVIRONMENT_ID=your_environment_id_here
DYNAMIC_AUTH_TOKEN=your_auth_token_here
Getting Dynamic Labs Credentials:
- Go to Dynamic Labs Dashboard
- Navigate to Developers → API Tokens
- Create a new API token with Policies and WaaS permissions
- Copy the token (starts with
dyn_...) - Get your Environment ID from the dashboard
Note: If you don't set up Dynamic Labs credentials, the app will still work but will only store data locally (in-memory). Vaults and wallets will be created locally without Dynamic Labs integration.
- Run the development server:
npm run dev- Open http://localhost:3000 in your browser
- Enter the admin email (e.g.,
admin@ngo.org) - Enter a vault name
- Click "Create Vault"
- Select a vault from the dropdown
- Enter the associated email (user identity)
- Click "Create Wallet"
- Select a vault
- Enter the delegate email (the user who will receive delegated access)
- (Optional) Select a wallet to delegate access to
- Click "Delegate Access (Local)" to store delegate email locally
- If a wallet is selected, use "Trigger Delegation (Client-side SDK)" to trigger Dynamic Labs delegation flow
- The delegate user will need to approve the delegation request
- After approval, your server will receive a webhook with encrypted delegation materials
- Enter a policy name
- Select policy type:
- Spending Limit: Set maximum spending amount
- Multi-Signature: Require multiple signatures for transactions
- Time Lock: Lock funds until a specific time
- Approval Required: Require approval for transactions
- Select target type (Wallet or Vault)
- Select the target wallet/vault
- Fill in policy-specific configuration
- Click "Create Policy"
POST /api/vaults- Create a vaultGET /api/vaults- Get all vaults (optional:?adminEmail=email)GET /api/vaults/[id]- Get vault by IDPOST /api/vaults/[id]/delegate- Delegate access to a vault
POST /api/wallets- Create a walletGET /api/wallets- Get all wallets (optional:?vaultId=idor?email=email)
POST /api/policies- Create a policyGET /api/policies- Get all policies (optional:?targetType=wallet&targetId=id)GET /api/policies/[id]- Get policy by ID
POST /api/webhooks/delegation- Webhook endpoint for receiving delegation materials from Dynamic LabsGET /api/delegated-accesses- Get all delegated accesses (optional:?vaultId=id,?walletId=id,?delegateEmail=email)
This POC uses in-memory storage. Data will be reset when the server restarts. For production, you would integrate with a database (PostgreSQL, MongoDB, etc.) or a blockchain service.
coala-poc/
├── app/
│ ├── api/ # API routes
│ ├── globals.css # Global styles
│ ├── layout.tsx # Root layout
│ └── page.tsx # Main dashboard page
├── lib/
│ ├── services/
│ │ └── dynamicLabsService.ts # Dynamic Labs API integration
│ ├── store.ts # In-memory data store
│ └── utils.ts # Utility functions
├── types/
│ └── index.ts # TypeScript type definitions
└── package.json
- Next.js 14 (App Router)
- TypeScript
- React 18
- CSS (no external UI library for simplicity)
- This is a proof of concept (POC) for internal use
- All data is stored in memory and will be lost on server restart
- With Dynamic Labs integration: Real wallets are created on Dynamic Labs platform
- Without Dynamic Labs: Wallet addresses are randomly generated (not real blockchain addresses)
- For production, integrate with a database (PostgreSQL, MongoDB, etc.) for persistent storage
To use the Policies feature, you need to configure the following in Dynamic Labs Dashboard:
- Go to Dynamic Labs Dashboard
- Navigate to your Environment settings
- Go to Wallets → Policies (or Settings → Features)
- Enable "Policy Engine" or "WaaS Policies" feature
- Save the changes
- Go to Developers → API Tokens
- Create a new API token with the following permissions:
- ✅ WaaS (Wallet as a Service)
- ✅ Policies (if available as a separate permission)
- Token should start with
dyn_...(not SDK keysk_...) - Copy and save the token securely (you won't be able to see it again)
- Ensure your Environment ID is correct
- Check that the environment has Policy Engine enabled
- Verify that embedded wallets are enabled (required for policies)
- Policy API requires JWT token from authenticated user (via SDK)
- User must be logged in with Dynamic Labs SDK
- JWT token is obtained via
getAuthToken()from SDK - Important: The JWT token must be from the user who owns the wallet, not from admin/dashboard account
If you get this error, check:
- ✅ Policy Engine is enabled in dashboard
- ✅ User is logged in with correct account (the one that owns the wallet)
- ✅ JWT token is not expired (check
expfield) - ✅ JWT token has correct
environment_idmatching your environment - ✅ Wallet address in policy matches a wallet owned by the authenticated user
- ✅ User has permission to create policies (may require specific user role)
- Test by calling the Policy API endpoint directly
- Use the JWT token from
getAuthToken()in Authorization header - If you get 401/403 errors, verify all above configurations
- Spending Limit: Set maximum spending amount per transaction
- Multi-Signature: Require multiple signatures for transactions
- Time Lock: Lock funds until a specific time
- Approval Required: Require approval before transactions
See Dynamic Labs Policies Documentation for more details.
To use the Delegated Access feature, you need to configure the following:
- Go to Dynamic Labs Dashboard
- Navigate to Developers → Delegated Access (or Settings → Features)
- Enable "Delegated Access" feature
- Save the changes
- In the Dashboard, go to Webhooks section
- Add a new webhook endpoint:
https://your-domain.com/api/webhooks/delegation - Subscribe to
wallet.delegation.createdevent - Save the webhook configuration
- Generate an RSA key pair (2048-bit or 4096-bit)
- Register the public key in Dynamic Labs Dashboard
- Keep the private key secure (store in environment variable
DYNAMIC_DELEGATION_PRIVATE_KEY) - Dynamic Labs will use this public key to encrypt delegation materials
Add to your .env file:
DYNAMIC_DELEGATION_PRIVATE_KEY=-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----
DYNAMIC_WEBHOOK_SECRET=your_webhook_secret_here # Optional, for webhook signature verification
- Wallet owner triggers delegation via client-side SDK (using
DelegateAccessClientcomponent) - Delegate user receives a request to approve delegation
- After approval, Dynamic Labs sends webhook to your server
- Server verifies webhook signature, decrypts materials, and stores securely
- Delegated materials can be used to act on behalf of the wallet owner
⚠️ Store delegated materials securely: Use envelope encryption, KMS, or at-rest encryption⚠️ Never expose private key: KeepDYNAMIC_DELEGATION_PRIVATE_KEYsecure⚠️ Verify webhook signatures: Always verify webhook signatures before processing⚠️ Use HTTPS: Webhook endpoint must use HTTPS in production
See Dynamic Labs Delegated Access Documentation for more details.