diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 6e42fec..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: 🐛 Bug report -description: Report a reproducible bug or regression in this library. -labels: [bug] -body: - - type: markdown - attributes: - value: | - # Bug report - - 👋 Hi! - - **Please fill the following carefully before opening a new issue ❗** - *(Your issue may be closed if it doesn't provide the required pieces of information)* - - type: checkboxes - attributes: - label: Before submitting a new issue - description: Please perform simple checks first. - options: - - label: I tested using the latest version of the library, as the bug might be already fixed. - required: true - - label: I tested using a [supported version](https://github.com/reactwg/react-native-releases/blob/main/docs/support.md) of react native. - required: true - - label: I checked for possible duplicate issues, with possible answers. - required: true - - type: textarea - id: summary - attributes: - label: Bug summary - description: | - Provide a clear and concise description of what the bug is. - If needed, you can also provide other samples: error messages / stack traces, screenshots, gifs, etc. - validations: - required: true - - type: input - id: library-version - attributes: - label: Library version - description: What version of the library are you using? - placeholder: "x.x.x" - validations: - required: true - - type: textarea - id: react-native-info - attributes: - label: Environment info - description: Run `react-native info` in your terminal and paste the results here. - render: shell - validations: - required: true - - type: textarea - id: steps-to-reproduce - attributes: - label: Steps to reproduce - description: | - You must provide a clear list of steps and code to reproduce the problem. - value: | - 1. … - 2. … - validations: - required: true - - type: input - id: reproducible-example - attributes: - label: Reproducible example repository - description: Please provide a link to a repository on GitHub with a reproducible example. - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 2df382a..0000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,8 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Feature Request 💡 - url: https://github.com/tetherto/discussions/new?category=ideas - about: If you have a feature request, please create a new discussion on GitHub. - - name: Discussions on GitHub 💬 - url: https://github.com/tetherto/discussions - about: If this library works as promised but you need help, please ask questions there. diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml deleted file mode 100644 index a613332..0000000 --- a/.github/actions/setup/action.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Setup -description: Setup Node.js and install dependencies - -runs: - using: composite - steps: - - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version-file: .nvmrc - - - name: Restore dependencies - id: yarn-cache - uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: | - **/node_modules - .yarn/install-state.gz - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}-${{ hashFiles('**/package.json', '!node_modules/**') }} - restore-keys: | - ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - ${{ runner.os }}-yarn- - - - name: Install dependencies - if: steps.yarn-cache.outputs.cache-hit != 'true' - run: yarn install --immutable - shell: bash - - - name: Cache dependencies - if: steps.yarn-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - with: - path: | - **/node_modules - .yarn/install-state.gz - key: ${{ steps.yarn-cache.outputs.cache-primary-key }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index f6b5585..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: build - -on: - push: - branches: [main, develop] - pull_request: - branches: [main, develop] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - cache: 'npm' - - - name: Install dependencies - run: npm clean-install - - - name: Lint - run: npm run lint - - - name: Type check - run: npm run typecheck - - - name: Test - run: npm test - - - name: Build - run: npm run prepare diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 6f3d70d..0000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: publish - -on: - release: - types: [published] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - cache: 'npm' - registry-url: 'https://registry.npmjs.org' - - - name: Install dependencies - run: npm clean-install - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Lint - run: npm run lint - - - name: Test - run: npm test - - - name: Type check - run: npm run typecheck - - publish: - needs: test - runs-on: ubuntu-latest - environment: npm-publish - - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - cache: 'npm' - registry-url: 'https://registry.npmjs.org' - - - name: Install dependencies - run: npm clean-install - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Build - run: npm run prepare - - - name: Publish to npm - run: npm publish - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48baba7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +yarn.lock + +# Build outputs +dist/ +build/ +*.tsbuildinfo +*.js.map + +# TypeScript +*.log +*.tgz + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store + +# Testing +coverage/ +.nyc_output/ + +# OS +.DS_Store +Thumbs.db +.AppleDouble +.LSOverride + +# Temporary files +*.tmp +*.temp +.cache/ + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..86b1986 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,184 @@ +# Contributing Guide + +Thank you for your interest in contributing to WDK React Native Provider! This guide will help you get started. + +## 🚀 Getting Started + +### 1. Fork and Clone + +```bash +# Fork the repository on GitHub, then clone your fork +git clone -b v2 https://github.com/YOUR_USERNAME/wdk-react-native-provider.git +cd wdk-react-native-provider +``` + +### 2. Install Dependencies + +```bash +npm install +``` + +### 3. Build All Packages + +```bash +npm run build +``` + +## 🛠️ Development Workflow + +### Making Changes + +1. Create a new branch for your feature/fix: + ```bash + git checkout -b feature/my-new-feature + ``` + +2. Make your changes in the appropriate package: + - `wdk-rn-secure-storage/src/` - Secure storage functionality + - `wdk-rn-worklet/src/` - Worklet and wallet operations + - `wdk-rn-balance-fetcher/src/` - Balance fetching functionality + +3. Rebuild the packages: + ```bash + npm run build + ``` + +4. Type check your changes: + ```bash + npm run typecheck + ``` + +### Testing Your Changes + +To test your changes in a real app: + +1. In your app's `package.json`, add: + ```json + { + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:../wdk-react-native-provider/wdk-rn-secure-storage", + "@tetherto/wdk-rn-worklet": "file:../wdk-react-native-provider/wdk-rn-worklet", + "@tetherto/wdk-rn-balance-fetcher": "file:../wdk-react-native-provider/wdk-rn-balance-fetcher" + } + } + ``` + +2. Install: + ```bash + npm install + ``` + +3. After making changes, rebuild: + ```bash + cd wdk-react-native-provider + npm run build + ``` + +4. Reinstall in your app if needed: + ```bash + cd your-app + npm install + ``` + +## 📝 Commit Guidelines + +- Write clear, descriptive commit messages +- Use present tense ("Add feature" not "Added feature") +- Reference issues and PRs when relevant + +Example: +``` +feat: add balance caching to reduce RPC calls + +- Implement in-memory cache with TTL +- Add cache invalidation on manual refresh +- Fixes #123 +``` + +## 🔍 Code Quality + +### TypeScript + +- All code must be properly typed +- Avoid using `any` unless absolutely necessary +- Export types that consumers might need + +### Code Style + +- Follow the existing code style in the project +- Use meaningful variable and function names +- Add comments for complex logic +- Keep functions small and focused + +## 📦 Package Structure + +Each package follows this structure: + +``` +package-name/ +├── src/ # Source TypeScript files +├── dist/ # Compiled JavaScript (gitignored) +├── package.json # Package configuration +├── tsconfig.json # TypeScript configuration +└── README.md # Package documentation +``` + +## 🚢 Submitting Changes + +1. Commit your changes: + ```bash + git add . + git commit -m "feat: your feature description" + ``` + +2. Push to your fork: + ```bash + git push origin feature/my-new-feature + ``` + +3. Create a Pull Request: + - Go to the original repository on GitHub + - Click "New Pull Request" + - Select your branch + - Fill in the PR template with: + - Description of changes + - Why the change is needed + - How to test it + - Any breaking changes + +## 🐛 Reporting Issues + +When reporting issues, please include: + +1. **Description** - Clear description of the issue +2. **Steps to Reproduce** - How to reproduce the issue +3. **Expected Behavior** - What you expected to happen +4. **Actual Behavior** - What actually happened +5. **Environment** - React Native version, OS, etc. +6. **Code Sample** - Minimal code that reproduces the issue + +## 💡 Feature Requests + +We welcome feature requests! Please: + +1. Check if the feature already exists or is being worked on +2. Open an issue describing: + - The feature you'd like + - Why it would be useful + - Possible implementation approach +3. Be open to discussion and feedback + +## 📄 License + +By contributing, you agree that your contributions will be licensed under the Apache-2.0 License. + +## ❓ Questions? + +If you have questions: +- Open an issue on GitHub +- Check existing issues and discussions +- Review the package READMEs + +Thank you for contributing! 🎉 + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..819d851 --- /dev/null +++ b/README.md @@ -0,0 +1,260 @@ +# WDK React Native Provider + +A monorepo containing React Native wallet development kit packages. + +## 📦 Packages + +- **[@tetherto/wdk-rn-secure-storage](./wdk-rn-secure-storage)** - Secure storage abstractions using react-native-keychain +- **[@tetherto/wdk-rn-worklet](./wdk-rn-worklet)** - Worklet functionality for wallet operations +- **[@tetherto/wdk-rn-balance-fetcher](./wdk-rn-balance-fetcher)** - Balance fetching functionality + +## 🚀 Quick Start + +### Installation Options + +**Want "just `npm install`"?** Use **Option 1 (Git Submodules)** - set it up once, then `npm install` works forever! + +Choose the method that works best for your project: + +#### Option 1: Git Submodules (Recommended - Cleanest) + +**Best for:** Projects where you want the dependency managed by git and stay in sync automatically. + +1. **Add as a git submodule in your project:** + +```bash +git submodule add -b main https://github.com/itsdeka/wdk-react-native-provider.git packages/wdk-react-native-provider +``` + +> **Note:** Replace `main` with your desired branch (e.g., `v2`, `develop`) + +2. **Add to your `package.json`:** + +```json +{ + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:./packages/wdk-react-native-provider/wdk-rn-secure-storage", + "@tetherto/wdk-rn-worklet": "file:./packages/wdk-react-native-provider/wdk-rn-worklet", + "@tetherto/wdk-rn-balance-fetcher": "file:./packages/wdk-react-native-provider/wdk-rn-balance-fetcher" + } +} +``` + +3. **Install (builds automatically!):** + +```bash +npm install +``` + +**How automatic building works:** +- Each package has a `prepare` script that runs `npm run build` +- When you run `npm install`, npm automatically runs `prepare` for each package installed via `file:` paths +- TypeScript (in devDependencies) is automatically installed for file-based packages +- Packages build in the correct order (dependencies first) +- ✅ **No manual build step needed!** + +**Benefits:** +- ✅ Cleaner - dependency is part of your repo structure +- ✅ Automatic building - packages compile during `npm install` +- ✅ Automatic updates - `git submodule update --remote` keeps it in sync +- ✅ Version controlled - submodule points to specific commit +- ✅ No manual cloning needed after initial setup +- ✅ Just `npm install` works! + +**To update the submodule later:** +```bash +git submodule update --remote packages/wdk-react-native-provider +npm install # Rebuilds packages automatically +``` + +**For new team members:** +```bash +git clone --recurse-submodules +npm install # Automatically builds all packages! +``` + +#### Option 2: Direct GitHub Installation + +**Best for:** Quick setup, but requires manual cloning first. + +⚠️ **Note:** npm doesn't natively support installing from git subdirectories. This method requires cloning the repo first, then using file paths. For true "just npm install", use **Option 1 (Git Submodules)** instead. + +#### Option 3: Manual Clone (Simple & Reliable) + +**Best for:** Development or when other methods don't work. + +1. **Clone the repository:** + +```bash +git clone -b main https://github.com/itsdeka/wdk-react-native-provider.git +``` + +2. **Add to your `package.json`:** + +```json +{ + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:../wdk-react-native-provider/wdk-rn-secure-storage", + "@tetherto/wdk-rn-worklet": "file:../wdk-react-native-provider/wdk-rn-worklet", + "@tetherto/wdk-rn-balance-fetcher": "file:../wdk-react-native-provider/wdk-rn-balance-fetcher" + } +} +``` + +3. **Install:** + +```bash +npm install +``` + +### Automatic Building + +All methods automatically build packages during `npm install` via the `prepare` scripts. No manual build step needed! + +1. **Clone the repository:** + +```bash +git clone -b main https://github.com/itsdeka/wdk-react-native-provider.git +# Or use a specific branch: git clone -b v2 https://github.com/itsdeka/wdk-react-native-provider.git +``` + +2. **Add to your `package.json`:** + +```json +{ + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:../wdk-react-native-provider/wdk-rn-secure-storage", + "@tetherto/wdk-rn-worklet": "file:../wdk-react-native-provider/wdk-rn-worklet", + "@tetherto/wdk-rn-balance-fetcher": "file:../wdk-react-native-provider/wdk-rn-balance-fetcher" + } +} +``` + +3. **Install:** + +```bash +npm install +``` + +The packages will build automatically via the `prepare` script. + +1. **Clone the repository** + +```bash +git clone -b v2 https://github.com/itsdeka/wdk-react-native-provider.git +cd wdk-react-native-provider +``` + +2. **Install and build** + +```bash +npm install +npm run build +``` + +3. **Install in your app** + +Add to your app's `package.json`: + +```json +{ + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:../wdk-react-native-provider/wdk-rn-secure-storage", + "@tetherto/wdk-rn-worklet": "file:../wdk-react-native-provider/wdk-rn-worklet", + "@tetherto/wdk-rn-balance-fetcher": "file:../wdk-react-native-provider/wdk-rn-balance-fetcher" + } +} +``` + +Then run: + +```bash +npm install +``` + +> **Note:** Adjust the file paths based on where you cloned the repository relative to your app. + +### For Contributors + +1. **Fork and clone** + +```bash +git clone -b v2 https://github.com/YOUR_USERNAME/wdk-react-native-provider.git +cd wdk-react-native-provider +``` + +2. **Make your changes** + +Edit any files in the packages: +- `wdk-rn-secure-storage/src/` +- `wdk-rn-worklet/src/` +- `wdk-rn-balance-fetcher/src/` + +3. **Rebuild and test** + +```bash +npm run build +``` + +If you have the packages installed in an app via file paths, the changes will be reflected immediately (or after reinstalling). + +4. **Submit a PR** + +Push your changes and create a pull request to the `v2` branch. + +## 🛠️ Development + +### Building All Packages + +```bash +npm run build +``` + +### Building Individual Packages + +```bash +cd wdk-rn-secure-storage && npm run build +cd wdk-rn-worklet && npm run build +cd wdk-rn-balance-fetcher && npm run build +``` + +### Type Checking + +```bash +npm run typecheck +``` + +## 📝 Important Notes + +- **Build Output**: The `dist/` folders are gitignored and will be built automatically when packages are installed via the `prepare` script +- **Dependencies**: Internal package dependencies (e.g., `@tetherto/wdk-rn-worklet` depends on `@tetherto/wdk-rn-secure-storage`) will be resolved automatically when using file paths +- **TypeScript**: Make sure TypeScript is available in your project or install it globally for the `prepare` script to work + +## 📚 Documentation + +See individual package READMEs: +- [wdk-rn-secure-storage README](./wdk-rn-secure-storage/README.md) +- [wdk-rn-worklet README](./wdk-rn-worklet/README.md) +- [wdk-rn-balance-fetcher README](./wdk-rn-balance-fetcher/README.md) + +## 🤝 Contributing + +We welcome contributions! Here's how: + +1. Clone the repository +2. Make your changes +3. Test in your app using file paths +4. Submit a pull request + +Since users install directly from the repository, they can easily modify the code and contribute back. + +## 📄 License + +Apache-2.0 + +## 🔗 Links + +- GitHub: https://github.com/itsdeka/wdk-react-native-provider +- Issues: https://github.com/itsdeka/wdk-react-native-provider/issues + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..e10ccd2 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "@tetherto/wdk-react-native-provider-monorepo", + "version": "1.0.0", + "private": true, + "description": "Monorepo for WDK React Native packages - wallet development kit for React Native applications", + "repository": { + "type": "git", + "url": "git+https://github.com/itsdeka/wdk-react-native-provider.git" + }, + "bugs": { + "url": "https://github.com/itsdeka/wdk-react-native-provider/issues" + }, + "homepage": "https://github.com/itsdeka/wdk-react-native-provider/tree/v2#readme", + "author": "Tetherto", + "license": "Apache-2.0", + "workspaces": [ + "wdk-rn-secure-storage", + "wdk-rn-worklet", + "wdk-rn-balance-fetcher" + ], + "scripts": { + "typecheck": "npm run typecheck --workspaces", + "build": "npm run build --workspaces", + "clean": "rm -rf wdk-rn-*/dist wdk-rn-*/*.tgz", + "postinstall": "npm run build" + }, + "dependencies": { + "typescript": "^5.3.3" + }, + "devDependencies": {} +} + diff --git a/wdk-rn-balance-fetcher/.npmignore b/wdk-rn-balance-fetcher/.npmignore new file mode 100644 index 0000000..714af03 --- /dev/null +++ b/wdk-rn-balance-fetcher/.npmignore @@ -0,0 +1,7 @@ +src/ +tsconfig.json +node_modules/ +*.tgz +*.log +.DS_Store + diff --git a/wdk-rn-balance-fetcher/README.md b/wdk-rn-balance-fetcher/README.md new file mode 100644 index 0000000..d80a1c4 --- /dev/null +++ b/wdk-rn-balance-fetcher/README.md @@ -0,0 +1,114 @@ +# @tetherto/wdk-rn-balance-fetcher + +Balance fetching functionality for React Native wallets - fetch token balances through worklet integration. + +## Installation + +### Step 1: Clone the Repository + +```bash +# Clone the v2 branch +git clone -b v2 https://github.com/itsdeka/wdk-react-native-provider.git +cd wdk-react-native-provider + +# Install dependencies and build +npm install +npm run build +``` + +### Step 2: Install in Your App + +From your app directory: + +```bash +npm install /path/to/wdk-react-native-provider/wdk-rn-balance-fetcher +``` + +Or add to your `package.json`: + +```json +{ + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:../wdk-react-native-provider/wdk-rn-secure-storage", + "@tetherto/wdk-rn-worklet": "file:../wdk-react-native-provider/wdk-rn-worklet", + "@tetherto/wdk-rn-balance-fetcher": "file:../wdk-react-native-provider/wdk-rn-balance-fetcher" + } +} +``` + +Then run `npm install`. + +### Contributing + +Since you're installing from source, you can: +1. Make changes to the code in `wdk-react-native-provider/wdk-rn-balance-fetcher` +2. Rebuild: `cd wdk-react-native-provider && npm run build` +3. The changes will be reflected in your app immediately (or after reinstalling) +4. Submit a pull request with your improvements! + +## Peer Dependencies + +```bash +npm install react@">=18.0.0" react-native@">=0.70.0" +npm install '@tetherto/wdk-rn-worklet' +``` + +## Usage + +```typescript +import { useBalanceFetcher } from '@tetherto/wdk-rn-balance-fetcher'; + +function BalanceDisplay() { + const { balances, isLoading, error, refresh } = useBalanceFetcher({ + enabled: true, + refreshInterval: 30000, // Refresh every 30 seconds + }); + + if (isLoading) return ; + if (error) return ; + + return ( + + {balances.map((balance) => ( + + {balance.token}: {balance.value} + + ))} + + + ); +} +``` + +## Features + +- 💰 Automatic balance fetching +- 🔄 Configurable refresh intervals +- 📊 Multiple token support +- ⚡ Optimized for performance +- 🎯 Worklet integration + +## API + +### `useBalanceFetcher(options)` + +#### Options + +- `enabled` (boolean): Enable/disable balance fetching +- `refreshInterval` (number): Interval in milliseconds for auto-refresh +- `onSuccess` (callback): Called when balances are fetched successfully +- `onError` (callback): Called when an error occurs + +#### Returns + +- `balances`: Array of balance objects +- `isLoading`: Loading state +- `error`: Error object if any +- `refresh()`: Manual refresh function + +See [src/index.ts](./src/index.ts) for full API documentation. + +## License + +Apache-2.0 + diff --git a/wdk-rn-balance-fetcher/package.json b/wdk-rn-balance-fetcher/package.json index 88e1e59..23c2db8 100644 --- a/wdk-rn-balance-fetcher/package.json +++ b/wdk-rn-balance-fetcher/package.json @@ -2,17 +2,31 @@ "name": "@tetherto/wdk-rn-balance-fetcher", "version": "1.0.0", "description": "Balance fetching functionality for React Native wallets - fetch token balances through worklet", - "main": "src/index.ts", - "types": "src/index.ts", + "main": "dist/wdk-rn-balance-fetcher/src/index.js", + "types": "dist/wdk-rn-balance-fetcher/src/index.d.ts", "exports": { ".": { - "types": "./src/index.ts", - "default": "./src/index.ts" + "types": "./dist/wdk-rn-balance-fetcher/src/index.d.ts", + "default": "./dist/wdk-rn-balance-fetcher/src/index.js" } }, + "files": [ + "dist", + "README.md" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/itsdeka/wdk-react-native-provider.git", + "directory": "wdk-rn-balance-fetcher" + }, + "bugs": { + "url": "https://github.com/itsdeka/wdk-react-native-provider/issues" + }, + "homepage": "https://github.com/itsdeka/wdk-react-native-provider/tree/v2/wdk-rn-balance-fetcher#readme", "scripts": { "build": "tsc", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "prepare": "npm run build" }, "keywords": [ "wallet", @@ -24,15 +38,15 @@ "author": "Tetherto", "license": "Apache-2.0", "dependencies": { - "@tetherto/wdk-rn-worklet": "file:../wdk-rn-worklet", - "@tetherto/wdk-rn-secure-storage": "file:../wdk-rn-secure-storage" + "@tetherto/wdk-rn-worklet": "file:../wdk-rn-worklet" }, "peerDependencies": { "react": ">=18.0.0", "react-native": ">=0.70.0" }, "devDependencies": { - "typescript": "^5.3.3" + "typescript": "^5.3.3", + "@types/react": "^18.2.0" } } diff --git a/wdk-rn-balance-fetcher/src/hooks/useBalanceFetcher.ts b/wdk-rn-balance-fetcher/src/hooks/useBalanceFetcher.ts index 5252e8a..5ddb5d7 100644 --- a/wdk-rn-balance-fetcher/src/hooks/useBalanceFetcher.ts +++ b/wdk-rn-balance-fetcher/src/hooks/useBalanceFetcher.ts @@ -361,7 +361,7 @@ export function useBalanceFetcher(options: { try { // Fetch balances for all wallets in parallel await Promise.all( - allWallets.map(async (wallet) => { + allWallets.map(async (wallet: Wallet) => { try { console.log(`[BalanceFetcher] Processing wallet ${wallet.accountIndex}...`) const walletResults = await fetchAllBalancesForWallet( @@ -400,7 +400,7 @@ export function useBalanceFetcher(options: { // Fetch balances for all wallets and tokens in parallel await Promise.all( - allWallets.flatMap((wallet) => + allWallets.flatMap((wallet: Wallet) => tokens.map(async (token) => { const result = await fetchBalance( network, diff --git a/wdk-rn-balance-fetcher/src/types.ts b/wdk-rn-balance-fetcher/src/types.ts index 4ec7725..5938c49 100644 --- a/wdk-rn-balance-fetcher/src/types.ts +++ b/wdk-rn-balance-fetcher/src/types.ts @@ -2,7 +2,7 @@ * Balance fetcher types */ -import type { TokenConfig, TokenConfigs } from '@tetherto/wdk-rn-worklet' +import type { TokenConfig, TokenConfigs, Wallet } from '@tetherto/wdk-rn-worklet' /** * Wallet interface for balance fetching diff --git a/wdk-rn-secure-storage/.npmignore b/wdk-rn-secure-storage/.npmignore new file mode 100644 index 0000000..714af03 --- /dev/null +++ b/wdk-rn-secure-storage/.npmignore @@ -0,0 +1,7 @@ +src/ +tsconfig.json +node_modules/ +*.tgz +*.log +.DS_Store + diff --git a/wdk-rn-secure-storage/README.md b/wdk-rn-secure-storage/README.md new file mode 100644 index 0000000..569f0d4 --- /dev/null +++ b/wdk-rn-secure-storage/README.md @@ -0,0 +1,82 @@ +# @tetherto/wdk-rn-secure-storage + +Secure storage abstractions for React Native - provides secure storage for sensitive data (encrypted seeds, keys) using react-native-keychain. + +## Installation + +### Step 1: Clone the Repository + +```bash +# Clone the v2 branch +git clone -b v2 https://github.com/itsdeka/wdk-react-native-provider.git +cd wdk-react-native-provider + +# Install dependencies and build +npm install +npm run build +``` + +### Step 2: Install in Your App + +From your app directory: + +```bash +npm install /path/to/wdk-react-native-provider/wdk-rn-secure-storage +``` + +Or add to your `package.json`: + +```json +{ + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:../wdk-react-native-provider/wdk-rn-secure-storage" + } +} +``` + +Then run `npm install`. + +### Contributing + +Since you're installing from source, you can: +1. Make changes to the code in `wdk-react-native-provider/wdk-rn-secure-storage` +2. Rebuild: `cd wdk-react-native-provider && npm run build` +3. The changes will be reflected in your app immediately (or after reinstalling) +4. Submit a pull request with your improvements! + +## Peer Dependencies + +```bash +npm install react-native@">=0.70.0" +``` + +## Usage + +```typescript +import { SecureStorage } from '@tetherto/wdk-rn-secure-storage'; + +// Store sensitive data +await SecureStorage.setItem('key', 'sensitive-value'); + +// Retrieve data +const value = await SecureStorage.getItem('key'); + +// Remove data +await SecureStorage.removeItem('key'); +``` + +## Features + +- 🔒 Secure storage using native keychain/keystore +- 📱 iOS Keychain integration +- 🤖 Android Keystore integration +- 🔐 Biometric authentication support +- 💾 Encrypted data storage + +## API + +See [src/index.ts](./src/index.ts) for full API documentation. + +## License + +Apache-2.0 diff --git a/wdk-rn-secure-storage/package.json b/wdk-rn-secure-storage/package.json index e85b119..f69c61c 100644 --- a/wdk-rn-secure-storage/package.json +++ b/wdk-rn-secure-storage/package.json @@ -1,29 +1,44 @@ { "name": "@tetherto/wdk-rn-secure-storage", "version": "1.0.0", - "description": "Secure storage abstractions for React Native - provides secure storage for sensitive data (encrypted seeds, keys)", - "main": "src/index.ts", - "types": "src/index.ts", + "description": "Secure storage abstractions for React Native - provides secure storage for sensitive data (encrypted seeds, keys) using react-native-keychain", + "main": "dist/index.js", + "types": "dist/index.d.ts", "exports": { ".": { - "types": "./src/index.ts", - "default": "./src/index.ts" + "types": "./dist/index.d.ts", + "default": "./dist/index.js" } }, + "files": [ + "dist", + "README.md" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/itsdeka/wdk-react-native-provider.git", + "directory": "wdk-rn-secure-storage" + }, + "bugs": { + "url": "https://github.com/itsdeka/wdk-react-native-provider/issues" + }, + "homepage": "https://github.com/itsdeka/wdk-react-native-provider/tree/v2/wdk-rn-secure-storage#readme", "scripts": { "build": "tsc", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "prepare": "npm run build" }, "keywords": [ "wallet", "react-native", "secure-storage", - "expo-secure-store" + "react-native-keychain", + "keychain" ], "author": "Tetherto", "license": "Apache-2.0", "dependencies": { - "expo-secure-store": "~15.0.8", + "react-native-keychain": "^10.0.0", "expo-local-authentication": "~17.0.8" }, "peerDependencies": { diff --git a/wdk-rn-secure-storage/src/secureStorage.ts b/wdk-rn-secure-storage/src/secureStorage.ts index 6664ecb..e9729f8 100644 --- a/wdk-rn-secure-storage/src/secureStorage.ts +++ b/wdk-rn-secure-storage/src/secureStorage.ts @@ -1,4 +1,4 @@ -import * as SecureStore from 'expo-secure-store' +import * as Keychain from 'react-native-keychain' import * as LocalAuthentication from 'expo-local-authentication' /** @@ -34,14 +34,20 @@ let secureStorageInstance: SecureStorage | null = null /** * Secure storage wrapper factory for wallet credentials - * Uses expo-secure-store which provides encrypted storage on device + * Uses react-native-keychain which provides encrypted storage with cloud sync * * Returns a singleton instance to maintain referential equality across the app. * This eliminates the need for useMemo() in React components. * * SECURITY NOTE: Storage is app-scoped by the OS: - * - iOS: Uses Keychain Services, isolated by bundle identifier - * - Android: Uses KeyStore, isolated by package name + * - iOS: Uses Keychain Services with iCloud Keychain sync (when user signed into iCloud) + * - Android: Uses KeyStore with Google Cloud backup (when device backup enabled) + * + * CLOUD SYNC: Wallet credentials automatically sync to cloud for seamless device migration: + * - iOS: ACCESSIBLE.WHEN_UNLOCKED enables iCloud Keychain synchronization + * - Android: Default behavior backs up to Google Cloud when user has backup enabled + * - Data is encrypted by Apple/Google's E2EE infrastructure + * - Requires device unlock + biometric/PIN authentication to access * * Two different apps will NOT share data because storage is isolated by bundle ID/package name. */ @@ -113,33 +119,35 @@ export function createSecureStorage(): SecureStorage { /** * Store encryption key securely * - * SECURITY: Data is ALWAYS encrypted at rest by SecureStore (OS-level encryption via - * Keychain/KeyStore), regardless of requireAuthentication flag. + * SECURITY: Data is ALWAYS encrypted at rest by Keychain (iOS) / KeyStore (Android). + * With WHEN_UNLOCKED accessibility, the key will: + * - Sync to iCloud Keychain (iOS) when user is signed into iCloud + * - Backup to Google Cloud (Android) when device backup is enabled + * - Be accessible only when device is unlocked + * - Require biometric authentication if available * - * - If device has authentication: requires authentication to access (more secure) - * - If device has no authentication: still encrypted at rest, but accessible without auth - * (acceptable tradeoff - if device has no PIN, physical access = wallet access anyway) + * This allows seamless device migration while maintaining strong security. */ async setEncryptionKey(key: string): Promise { const deviceAuthAvailable = await isDeviceAuthenticationAvailable() - // Use authentication if available, otherwise fallback to encrypted storage without auth requirement - // Data is still encrypted at rest in both cases - await SecureStore.setItemAsync(STORAGE_KEYS.ENCRYPTION_KEY, key, { - requireAuthentication: deviceAuthAvailable, - authenticationPrompt: deviceAuthAvailable ? 'Authenticate to access your wallet' : undefined, + await Keychain.setGenericPassword(STORAGE_KEYS.ENCRYPTION_KEY, key, { + service: STORAGE_KEYS.ENCRYPTION_KEY, + accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED, // Enables iCloud Keychain sync + // Only set accessControl if device authentication is available + // Without accessControl, data is still encrypted at rest but doesn't require authentication + ...(deviceAuthAvailable && { + accessControl: Keychain.ACCESS_CONTROL.BIOMETRY_ANY_OR_DEVICE_PASSCODE + }), }) }, /** * Get encryption key from secure storage * - * SECURITY: Data is ALWAYS encrypted at rest by SecureStore (OS-level encryption via - * Keychain/KeyStore), regardless of requireAuthentication flag. - * - * - If device has authentication: requires authentication to access (biometrics or PIN/password) - * - If device has no authentication: still encrypted at rest, but accessible without auth - * (acceptable tradeoff - if device has no PIN, physical access = wallet access anyway) + * SECURITY: Data is encrypted at rest by Keychain (iOS) / KeyStore (Android). + * Biometric authentication is enforced if available. + * Data may be synced from iCloud Keychain (iOS) or Google Cloud (Android) on new devices. */ async getEncryptionKey(): Promise { try { @@ -161,22 +169,25 @@ export function createSecureStorage(): SecureStorage { return null } } else { - // Device has authentication but not biometrics - will use device PIN/password - // expo-secure-store will prompt for device credentials automatically console.log('🔐 Biometrics not available - will use device PIN/password') } } else { console.log('🔐 Device has no authentication - using encrypted storage without auth requirement') } - // Retrieve key - will require authentication if device has it, otherwise just encrypted at rest + // Retrieve key - will require authentication based on accessControl settings console.log('🔐 Retrieving encryption key from secure storage...') - const key = await SecureStore.getItemAsync(STORAGE_KEYS.ENCRYPTION_KEY, { - requireAuthentication: deviceAuthAvailable, - authenticationPrompt: deviceAuthAvailable ? 'Authenticate to access your wallet' : undefined, + const credentials = await Keychain.getGenericPassword({ + service: STORAGE_KEYS.ENCRYPTION_KEY, }) + + if (!credentials) { + console.log('🔐 No encryption key found') + return null + } + console.log('✅ Encryption key retrieved successfully') - return key + return credentials.password } catch (error) { console.error('❌ Failed to get encryption key:', error) return null @@ -187,8 +198,9 @@ export function createSecureStorage(): SecureStorage { * Store encrypted seed securely */ async setEncryptedSeed(encryptedSeed: string): Promise { - await SecureStore.setItemAsync(STORAGE_KEYS.ENCRYPTED_SEED, encryptedSeed, { - requireAuthentication: false, + await Keychain.setGenericPassword(STORAGE_KEYS.ENCRYPTED_SEED, encryptedSeed, { + service: STORAGE_KEYS.ENCRYPTED_SEED, + accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED, // Enables iCloud Keychain sync }) }, @@ -197,10 +209,10 @@ export function createSecureStorage(): SecureStorage { */ async getEncryptedSeed(): Promise { try { - const seed = await SecureStore.getItemAsync(STORAGE_KEYS.ENCRYPTED_SEED, { - requireAuthentication: false, + const credentials = await Keychain.getGenericPassword({ + service: STORAGE_KEYS.ENCRYPTED_SEED, }) - return seed + return credentials ? credentials.password : null } catch (error) { console.error('Failed to get encrypted seed:', error) return null @@ -211,8 +223,9 @@ export function createSecureStorage(): SecureStorage { * Store encrypted entropy securely */ async setEncryptedEntropy(encryptedEntropy: string): Promise { - await SecureStore.setItemAsync(STORAGE_KEYS.ENCRYPTED_ENTROPY, encryptedEntropy, { - requireAuthentication: false, + await Keychain.setGenericPassword(STORAGE_KEYS.ENCRYPTED_ENTROPY, encryptedEntropy, { + service: STORAGE_KEYS.ENCRYPTED_ENTROPY, + accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED, // Enables iCloud Keychain sync }) }, @@ -221,10 +234,10 @@ export function createSecureStorage(): SecureStorage { */ async getEncryptedEntropy(): Promise { try { - const entropy = await SecureStore.getItemAsync(STORAGE_KEYS.ENCRYPTED_ENTROPY, { - requireAuthentication: false, + const credentials = await Keychain.getGenericPassword({ + service: STORAGE_KEYS.ENCRYPTED_ENTROPY, }) - return entropy + return credentials ? credentials.password : null } catch (error) { console.error('Failed to get encrypted entropy:', error) return null @@ -242,10 +255,14 @@ export function createSecureStorage(): SecureStorage { } try { - const encryptionKey = await SecureStore.getItemAsync(STORAGE_KEYS.ENCRYPTION_KEY, { - requireAuthentication: false, + const credentials = await Keychain.getGenericPassword({ + service: STORAGE_KEYS.ENCRYPTION_KEY, + authenticationPrompt: { + title: 'Authenticate', + cancel: 'Cancel', + }, }) - return encryptionKey !== null + return credentials !== false } catch { return true } @@ -260,9 +277,9 @@ export function createSecureStorage(): SecureStorage { */ async deleteWallet(): Promise { await Promise.all([ - SecureStore.deleteItemAsync(STORAGE_KEYS.ENCRYPTION_KEY), - SecureStore.deleteItemAsync(STORAGE_KEYS.ENCRYPTED_SEED), - SecureStore.deleteItemAsync(STORAGE_KEYS.ENCRYPTED_ENTROPY), + Keychain.resetGenericPassword({ service: STORAGE_KEYS.ENCRYPTION_KEY }), + Keychain.resetGenericPassword({ service: STORAGE_KEYS.ENCRYPTED_SEED }), + Keychain.resetGenericPassword({ service: STORAGE_KEYS.ENCRYPTED_ENTROPY }), ]) }, } diff --git a/wdk-rn-worklet/.npmignore b/wdk-rn-worklet/.npmignore new file mode 100644 index 0000000..714af03 --- /dev/null +++ b/wdk-rn-worklet/.npmignore @@ -0,0 +1,7 @@ +src/ +tsconfig.json +node_modules/ +*.tgz +*.log +.DS_Store + diff --git a/wdk-rn-worklet/README.md b/wdk-rn-worklet/README.md new file mode 100644 index 0000000..13724ec --- /dev/null +++ b/wdk-rn-worklet/README.md @@ -0,0 +1,114 @@ +# @tetherto/wdk-rn-worklet + +Worklet functionality for React Native wallets - worklet store, hooks, and services for managing wallet operations. + +## Installation + +### Step 1: Clone the Repository + +```bash +# Clone the v2 branch +git clone -b v2 https://github.com/itsdeka/wdk-react-native-provider.git +cd wdk-react-native-provider + +# Install dependencies and build +npm install +npm run build +``` + +### Step 2: Install in Your App + +From your app directory: + +```bash +npm install /path/to/wdk-react-native-provider/wdk-rn-worklet +``` + +Or add to your `package.json`: + +```json +{ + "dependencies": { + "@tetherto/wdk-rn-secure-storage": "file:../wdk-react-native-provider/wdk-rn-secure-storage", + "@tetherto/wdk-rn-worklet": "file:../wdk-react-native-provider/wdk-rn-worklet" + } +} +``` + +Then run `npm install`. + +### Contributing + +Since you're installing from source, you can: +1. Make changes to the code in `wdk-react-native-provider/wdk-rn-worklet` +2. Rebuild: `cd wdk-react-native-provider && npm run build` +3. The changes will be reflected in your app immediately (or after reinstalling) +4. Submit a pull request with your improvements! + +## Peer Dependencies + +```bash +npm install react@">=18.0.0" react-native@">=0.70.0" +npm install '@tetherto/wdk-rn-secure-storage' +``` + +## Usage + +```typescript +import { useWallet, useWorklet } from '@tetherto/wdk-rn-worklet'; + +function WalletComponent() { + const { wallet, isLoading } = useWallet(); + const { createWallet, sendTransaction } = useWorklet(); + + // Create a new wallet + const handleCreateWallet = async () => { + await createWallet({ name: 'My Wallet' }); + }; + + // Send transaction + const handleSend = async () => { + await sendTransaction({ + to: 'recipient-address', + amount: '100', + token: 'USDT' + }); + }; + + if (isLoading) return ; + + return ( + + {!wallet ? ( + + ) : ( + + )} + + ); +} +``` + +## Features + +- 💼 Wallet management (create, import, delete) +- 🔄 Transaction handling +- 📊 State management with Zustand +- 🔐 Secure storage integration +- 📱 React Native optimized + +## API + +### Hooks + +- `useWallet()` - Access wallet state and operations +- `useWorklet()` - Access worklet operations +- `useWalletSetup()` - Wallet initialization utilities +- `useWdkApp()` - WDK app context + +See [src/index.ts](./src/index.ts) for full API documentation. + +## License + +Apache-2.0 + diff --git a/wdk-rn-worklet/package.json b/wdk-rn-worklet/package.json index 9cf38aa..bb84225 100644 --- a/wdk-rn-worklet/package.json +++ b/wdk-rn-worklet/package.json @@ -2,17 +2,31 @@ "name": "@tetherto/wdk-rn-worklet", "version": "1.0.0", "description": "Worklet functionality for React Native wallets - worklet store, hooks, and services", - "main": "src/index.ts", - "types": "src/index.ts", + "main": "dist/wdk-rn-worklet/src/index.js", + "types": "dist/wdk-rn-worklet/src/index.d.ts", "exports": { ".": { - "types": "./src/index.ts", - "default": "./src/index.ts" + "types": "./dist/wdk-rn-worklet/src/index.d.ts", + "default": "./dist/wdk-rn-worklet/src/index.js" } }, + "files": [ + "dist", + "README.md" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/itsdeka/wdk-react-native-provider.git", + "directory": "wdk-rn-worklet" + }, + "bugs": { + "url": "https://github.com/itsdeka/wdk-react-native-provider/issues" + }, + "homepage": "https://github.com/itsdeka/wdk-react-native-provider/tree/v2/wdk-rn-worklet#readme", "scripts": { "build": "tsc", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "prepare": "npm run build" }, "keywords": [ "wallet", @@ -35,7 +49,8 @@ "react-native": ">=0.70.0" }, "devDependencies": { - "typescript": "^5.3.3" + "typescript": "^5.3.3", + "@types/react": "^18.2.0" } }