@myrxwallet/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +173 -0
- package/examples/quickstart.js +80 -0
- package/package.json +56 -0
- package/src/bridge.js +67 -0
- package/src/chain.js +122 -0
- package/src/constants.js +67 -0
- package/src/health.js +207 -0
- package/src/index.js +51 -0
- package/src/token.js +86 -0
- package/types/index.d.ts +126 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MyRxWallet North America Corporation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# @myrxwallet/sdk
|
|
2
|
+
|
|
3
|
+
Official SDK for **Chain 8472 (MyRx Chain)** — the EVM-compatible blockchain securing patient health data under the 21st Century Cures Act.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@myrxwallet/sdk)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://explorer.myrxwallet.io)
|
|
8
|
+
[](https://ehr.myrxwallet.io/api/v1/fhir/r4/metadata)
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @myrxwallet/sdk
|
|
14
|
+
# Optional: ERC-20 + bridge operations require ethers v6
|
|
15
|
+
npm install ethers
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Chain 8472 Quick Connect
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const { Chain8472Provider, CHAIN_8472 } = require('@myrxwallet/sdk');
|
|
22
|
+
|
|
23
|
+
const provider = new Chain8472Provider();
|
|
24
|
+
const block = await provider.getBlockNumber();
|
|
25
|
+
const balanceMRT = await provider.getBalanceMRT('0xYourAddress');
|
|
26
|
+
|
|
27
|
+
console.log(`Chain ${CHAIN_8472.chainId} — block ${block}`);
|
|
28
|
+
console.log(`MRT balance: ${balanceMRT}`);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**RPC:** `https://rpc.myrxwallet.io`
|
|
32
|
+
**Chain ID:** `8472`
|
|
33
|
+
**Explorer:** `https://explorer.myrxwallet.io`
|
|
34
|
+
**Native Token:** MRT (MyRxWallet Reward Token, 18 decimals)
|
|
35
|
+
|
|
36
|
+
Add to MetaMask / any EVM wallet:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"chainId": "0x2118",
|
|
41
|
+
"chainName": "MyRx Chain",
|
|
42
|
+
"rpcUrls": ["https://rpc.myrxwallet.io"],
|
|
43
|
+
"nativeCurrency": { "name": "MyRx Token", "symbol": "MRT", "decimals": 18 },
|
|
44
|
+
"blockExplorerUrls": ["https://explorer.myrxwallet.io"]
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## MRT Token
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
const { MRTToken, CONTRACTS_8472 } = require('@myrxwallet/sdk');
|
|
52
|
+
|
|
53
|
+
const mrt = new MRTToken();
|
|
54
|
+
|
|
55
|
+
// Get token metadata
|
|
56
|
+
const meta = await mrt.metadata();
|
|
57
|
+
// { name: 'Wrapped MRT', symbol: 'wMRT', decimals: 18, totalSupply: '...' }
|
|
58
|
+
|
|
59
|
+
// Check balance
|
|
60
|
+
const balance = await mrt.balanceOf('0xYourAddress');
|
|
61
|
+
|
|
62
|
+
// Transfer MRT
|
|
63
|
+
const receipt = await mrt.transfer(privateKey, recipientAddress, '10.0');
|
|
64
|
+
|
|
65
|
+
// Approve bridge
|
|
66
|
+
await mrt.approve(privateKey, BRIDGE_CONTRACT_ADDRESS, '100.0');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Wrapped MRT:** `0x00e69754c21090d69D29a2abe3B6CF153D3F1dF7`
|
|
70
|
+
**Regulatory note:** MRT rewards are infrastructure compensation — not investment yield. [Full regulatory analysis →](https://myrxwallet.io/compliance.html#staking-validators)
|
|
71
|
+
|
|
72
|
+
## Multi-chain Bridge
|
|
73
|
+
|
|
74
|
+
MRT is live across 5 EVM networks via MRTBridgeMint contracts.
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
const { MRTBridge } = require('@myrxwallet/sdk');
|
|
78
|
+
|
|
79
|
+
// List supported chains
|
|
80
|
+
const chains = MRTBridge.supportedChains();
|
|
81
|
+
// [{ chainId: 8453, name: 'Base', role: 'Primary bridge hub' }, ...]
|
|
82
|
+
|
|
83
|
+
// Bridge MRT from Base → Chain 8472
|
|
84
|
+
const bridge = new MRTBridge(BRIDGE_CONTRACT_ON_BASE, BASE_RPC_URL);
|
|
85
|
+
const fee = await bridge.getBridgeFee(8472, '100');
|
|
86
|
+
const result = await bridge.bridgeTo(privateKey, 8472, recipientAddress, '100');
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
| Chain | Role |
|
|
90
|
+
|-------|------|
|
|
91
|
+
| Base (8453) | Primary bridge hub — Across Protocol |
|
|
92
|
+
| Arbitrum (42161) | L2 settlement layer |
|
|
93
|
+
| Polygon (137) | High-throughput transactions |
|
|
94
|
+
| Ethereum (1) | Institutional settlement |
|
|
95
|
+
| BNB Chain (56) | Global accessibility |
|
|
96
|
+
|
|
97
|
+
## Healthcare API (FHIR R4)
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const { MyRxHealthClient } = require('@myrxwallet/sdk');
|
|
101
|
+
|
|
102
|
+
// Authenticate via SMART on FHIR (PKCE)
|
|
103
|
+
const authUrl = MyRxHealthClient.buildAuthUrl({
|
|
104
|
+
clientId: 'your-client-id',
|
|
105
|
+
redirectUri: 'https://your-app.com/callback',
|
|
106
|
+
codeChallenge: codeChallenge,
|
|
107
|
+
scope: 'patient/*.read openid fhirUser',
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// After redirect, exchange code for token
|
|
111
|
+
const token = await MyRxHealthClient.exchangeCode({
|
|
112
|
+
code: authorizationCode,
|
|
113
|
+
clientId: 'your-client-id',
|
|
114
|
+
redirectUri: 'https://your-app.com/callback',
|
|
115
|
+
codeVerifier: codeVerifier,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Access patient data
|
|
119
|
+
const client = new MyRxHealthClient(token.access_token);
|
|
120
|
+
const patient = await client.getPatient(patientId);
|
|
121
|
+
const meds = await client.getMedications(patientId);
|
|
122
|
+
const vitals = await client.getObservations(patientId, 'vital-signs');
|
|
123
|
+
const nfts = await client.getNFTs(patientId);
|
|
124
|
+
const score = await client.getMyRxScore(patientId);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**FHIR Endpoint:** `https://ehr.myrxwallet.io/api/v1/fhir/r4/metadata`
|
|
128
|
+
**Standards:** HL7 FHIR R4 · US Core 6.1.0 · SMART App Launch 2.0.0 · Bulk Data 2.0.0
|
|
129
|
+
**Inferno Result:** 317/317 PASS (ONC (g)(10) certification baseline)
|
|
130
|
+
|
|
131
|
+
## Validators
|
|
132
|
+
|
|
133
|
+
Chain 8472 validator network secures federally-mandated patient health infrastructure.
|
|
134
|
+
|
|
135
|
+
- **Phase 1 (2026):** 10–50 validators — founding team + DAO members + credentialed developers
|
|
136
|
+
- **NFT-gated credentialing:** Validator rights tied to NFT tier (Founding/Provider/Community/Developer)
|
|
137
|
+
- **DAO governance:** DAORX.IO — protocol parameters, emission schedules, validator standards
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
// Get validator network status via raw RPC
|
|
141
|
+
const provider = new Chain8472Provider();
|
|
142
|
+
await provider.verify(); // confirms you're on Chain 8472
|
|
143
|
+
|
|
144
|
+
// Full regulatory framework:
|
|
145
|
+
// https://myrxwallet.io/docs/staking-validators-whitepaper.html
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Developer Portal
|
|
149
|
+
|
|
150
|
+
Register for API keys and sandbox access:
|
|
151
|
+
|
|
152
|
+
- **Developer Portal:** https://myrxwallet.io/developer.html
|
|
153
|
+
- **Sandbox:** Instant keys prefixed `mrx_sb_`
|
|
154
|
+
- **Production:** Manual review, prefixed `mrx_lv_`
|
|
155
|
+
- **SMART App Registration:** `POST /api/v1/developer/register`
|
|
156
|
+
|
|
157
|
+
## Compliance
|
|
158
|
+
|
|
159
|
+
| Standard | Status |
|
|
160
|
+
|----------|--------|
|
|
161
|
+
| FHIR R4 / US Core 6.1.0 | ✅ Inferno 317/317 PASS |
|
|
162
|
+
| SMART on FHIR 2.0.0 + PKCE | ✅ Live |
|
|
163
|
+
| HIPAA Security Rule (45 CFR §164.312) | ✅ AES-256-GCM |
|
|
164
|
+
| 21st Century Cures Act / ONC Interoperability Rule | ✅ Core requirement |
|
|
165
|
+
| DEA EPCS (21 CFR Part 1311) | ✅ TOTP 2FA + audit log |
|
|
166
|
+
| SEC Howey Test (MRT) | ✅ Prongs 3 & 4 not satisfied |
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
Apache 2.0 — MyRxWallet North America Corporation
|
|
171
|
+
CAGE: 9VNZ7 · UEI: RKYFJECN9GL3
|
|
172
|
+
|
|
173
|
+
[myrxwallet.io](https://myrxwallet.io) · [compliance](https://myrxwallet.io/compliance.html) · [developer docs](https://myrxwallet.io/developer.html)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @myrxwallet/sdk — Quickstart Examples
|
|
3
|
+
*
|
|
4
|
+
* Run: node examples/quickstart.js
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
Chain8472Provider,
|
|
9
|
+
MRTToken,
|
|
10
|
+
MRTBridge,
|
|
11
|
+
MyRxHealthClient,
|
|
12
|
+
CHAIN_8472,
|
|
13
|
+
CONTRACTS_8472,
|
|
14
|
+
BRIDGE_CHAINS,
|
|
15
|
+
} = require('../src/index');
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
console.log('\n=== @myrxwallet/sdk Quickstart ===\n');
|
|
19
|
+
|
|
20
|
+
// ── 1. Connect to Chain 8472 ──────────────────────────────────────────────
|
|
21
|
+
console.log('1. Connecting to Chain 8472...');
|
|
22
|
+
const provider = new Chain8472Provider();
|
|
23
|
+
const network = await provider.getNetwork();
|
|
24
|
+
console.log(` Network: ${network.name} (Chain ID: ${network.chainId})`);
|
|
25
|
+
console.log(` RPC: ${CHAIN_8472.rpcUrl}`);
|
|
26
|
+
|
|
27
|
+
const blockNumber = await provider.getBlockNumber();
|
|
28
|
+
console.log(` Latest block: ${blockNumber}`);
|
|
29
|
+
console.log(` Explorer: ${CHAIN_8472.explorerUrl}\n`);
|
|
30
|
+
|
|
31
|
+
// ── 2. Check MRT balance ──────────────────────────────────────────────────
|
|
32
|
+
console.log('2. MRT Token (Wrapped MRT on Chain 8472)...');
|
|
33
|
+
try {
|
|
34
|
+
const mrt = new MRTToken();
|
|
35
|
+
const meta = await mrt.metadata();
|
|
36
|
+
console.log(` Name: ${meta.name}`);
|
|
37
|
+
console.log(` Symbol: ${meta.symbol}`);
|
|
38
|
+
console.log(` Total Supply: ${meta.totalSupply} MRT\n`);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.log(` (requires ethers v6: npm install ethers) — ${e.message}\n`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── 3. Bridge support ────────────────────────────────────────────────────
|
|
44
|
+
console.log('3. Multi-chain Bridge — Supported Networks:');
|
|
45
|
+
const chains = MRTBridge.supportedChains();
|
|
46
|
+
chains.forEach(c => console.log(` Chain ${c.chainId}: ${c.name} — ${c.role}`));
|
|
47
|
+
console.log('');
|
|
48
|
+
|
|
49
|
+
// ── 4. FHIR Capability Statement ─────────────────────────────────────────
|
|
50
|
+
console.log('4. FHIR R4 Capability Statement...');
|
|
51
|
+
try {
|
|
52
|
+
const cap = await MyRxHealthClient.getCapabilityStatement();
|
|
53
|
+
console.log(` FHIR Version: ${cap.fhirVersion}`);
|
|
54
|
+
console.log(` Software: ${cap.software?.name}`);
|
|
55
|
+
console.log(` Status: ${cap.status}\n`);
|
|
56
|
+
} catch (e) {
|
|
57
|
+
console.log(` (FHIR metadata: ${e.message})\n`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ── 5. SMART Config ───────────────────────────────────────────────────────
|
|
61
|
+
console.log('5. SMART on FHIR Configuration...');
|
|
62
|
+
try {
|
|
63
|
+
const smart = await MyRxHealthClient.getSmartConfig();
|
|
64
|
+
console.log(` Authorization: ${smart.authorization_endpoint}`);
|
|
65
|
+
console.log(` Token: ${smart.token_endpoint}`);
|
|
66
|
+
console.log(` PKCE required: ${smart.code_challenge_methods_supported?.includes('S256')}\n`);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.log(` (SMART config: ${e.message})\n`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── 6. Contracts ──────────────────────────────────────────────────────────
|
|
72
|
+
console.log('6. Chain 8472 Contract Addresses:');
|
|
73
|
+
Object.entries(CONTRACTS_8472).forEach(([k, v]) => console.log(` ${k}: ${v}`));
|
|
74
|
+
|
|
75
|
+
console.log('\n=== @myrxwallet/sdk ready ===');
|
|
76
|
+
console.log('Install: npm install @myrxwallet/sdk');
|
|
77
|
+
console.log('Docs: https://myrxwallet.io/developer.html');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
main().catch(console.error);
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@myrxwallet/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official SDK for Chain 8472 (MyRx Chain) — MRT Token, FHIR R4 Health API, Multi-chain Bridge. Purpose-built for federally-mandated patient health infrastructure under the 21st Century Cures Act.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "types/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"types/",
|
|
10
|
+
"examples/",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"start": "node examples/quickstart.js",
|
|
15
|
+
"test": "node examples/quickstart.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"myrxwallet",
|
|
19
|
+
"chain-8472",
|
|
20
|
+
"mrt-token",
|
|
21
|
+
"healthcare",
|
|
22
|
+
"fhir",
|
|
23
|
+
"fhir-r4",
|
|
24
|
+
"smart-on-fhir",
|
|
25
|
+
"hipaa",
|
|
26
|
+
"blockchain",
|
|
27
|
+
"evm",
|
|
28
|
+
"web3",
|
|
29
|
+
"ethereum",
|
|
30
|
+
"21st-century-cures-act",
|
|
31
|
+
"onc",
|
|
32
|
+
"bridge",
|
|
33
|
+
"validator"
|
|
34
|
+
],
|
|
35
|
+
"author": "MyRxWallet North America Corporation <info@myrxwallet.io>",
|
|
36
|
+
"license": "Apache-2.0",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/MyRxWallet/myrx-sdk.git"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://myrxwallet.io/developer.html",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/MyRxWallet/myrx-sdk/issues"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"ethers": "^6.0.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"ethers": {
|
|
50
|
+
"optional": true
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/bridge.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { BRIDGE_CHAINS, BRIDGE_ABI, API_BASE } = require('./constants');
|
|
4
|
+
const { getEthersSigner } = require('./chain');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* MRTBridge — Multi-chain bridge for MRT tokens.
|
|
8
|
+
* Deployed across 5 EVM networks: Base (primary), Arbitrum, Polygon, Ethereum, BSC.
|
|
9
|
+
* Protocols: Across, Hop, Stargate, deBridge.
|
|
10
|
+
*/
|
|
11
|
+
class MRTBridge {
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} bridgeContractAddress MRTBridgeMint address on current chain
|
|
14
|
+
* @param {string} rpcUrl RPC for current chain
|
|
15
|
+
*/
|
|
16
|
+
constructor(bridgeContractAddress, rpcUrl) {
|
|
17
|
+
this.bridgeContractAddress = bridgeContractAddress;
|
|
18
|
+
this.rpcUrl = rpcUrl;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_contract(signer) {
|
|
22
|
+
const { Contract } = require('ethers');
|
|
23
|
+
return new Contract(this.bridgeContractAddress, BRIDGE_ABI, signer);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Bridge MRT to another chain.
|
|
28
|
+
* @param {string} privateKey
|
|
29
|
+
* @param {number} targetChainId Chain ID of destination (see BRIDGE_CHAINS)
|
|
30
|
+
* @param {string} recipient Destination address
|
|
31
|
+
* @param {string|number} amount MRT amount (not wei)
|
|
32
|
+
*/
|
|
33
|
+
async bridgeTo(privateKey, targetChainId, recipient, amount) {
|
|
34
|
+
if (!BRIDGE_CHAINS[targetChainId]) {
|
|
35
|
+
throw new Error(`Unsupported target chain: ${targetChainId}. Supported: ${Object.keys(BRIDGE_CHAINS).join(', ')}`);
|
|
36
|
+
}
|
|
37
|
+
const { parseUnits } = require('ethers');
|
|
38
|
+
const signer = getEthersSigner(privateKey, this.rpcUrl);
|
|
39
|
+
const contract = this._contract(signer);
|
|
40
|
+
const amountWei = parseUnits(String(amount), 18);
|
|
41
|
+
const fee = await contract.getBridgeFee(targetChainId, amountWei);
|
|
42
|
+
const tx = await contract.bridgeTo(targetChainId, recipient, amountWei, { value: fee });
|
|
43
|
+
return { txHash: tx.hash, receipt: await tx.wait() };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Get bridge fee for a given amount to a target chain. Returns fee in native gas token. */
|
|
47
|
+
async getBridgeFee(targetChainId, amount) {
|
|
48
|
+
const { parseUnits, formatEther } = require('ethers');
|
|
49
|
+
const { getEthersProvider } = require('./chain');
|
|
50
|
+
const provider = getEthersProvider(this.rpcUrl);
|
|
51
|
+
const { Contract } = require('ethers');
|
|
52
|
+
const contract = new Contract(this.bridgeContractAddress, BRIDGE_ABI, provider);
|
|
53
|
+
const amountWei = parseUnits(String(amount), 18);
|
|
54
|
+
const fee = await contract.getBridgeFee(targetChainId, amountWei);
|
|
55
|
+
return formatEther(fee);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** List all supported bridge chains. */
|
|
59
|
+
static supportedChains() {
|
|
60
|
+
return Object.entries(BRIDGE_CHAINS).map(([id, info]) => ({
|
|
61
|
+
chainId: Number(id),
|
|
62
|
+
...info,
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = { MRTBridge, BRIDGE_CHAINS };
|
package/src/chain.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { CHAIN_8472, CONTRACTS_8472, ERC20_ABI } = require('./constants');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Chain8472Provider — lightweight wrapper around JSON-RPC for Chain 8472.
|
|
7
|
+
* Uses ethers.js v6 if available; falls back to raw fetch for environments
|
|
8
|
+
* where ethers is not bundled.
|
|
9
|
+
*/
|
|
10
|
+
class Chain8472Provider {
|
|
11
|
+
constructor(rpcUrl = CHAIN_8472.rpcUrl) {
|
|
12
|
+
this.rpcUrl = rpcUrl;
|
|
13
|
+
this.chainId = CHAIN_8472.chainId;
|
|
14
|
+
this._id = 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async _rpc(method, params = []) {
|
|
18
|
+
const res = await fetch(this.rpcUrl, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: { 'Content-Type': 'application/json' },
|
|
21
|
+
body: JSON.stringify({ jsonrpc: '2.0', id: ++this._id, method, params }),
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) throw new Error(`RPC HTTP ${res.status}`);
|
|
24
|
+
const { result, error } = await res.json();
|
|
25
|
+
if (error) throw new Error(error.message || JSON.stringify(error));
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Get native MRT balance for an address (returns BigInt in wei). */
|
|
30
|
+
async getBalance(address) {
|
|
31
|
+
const hex = await this._rpc('eth_getBalance', [address, 'latest']);
|
|
32
|
+
return BigInt(hex);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Get MRT balance formatted in ether units. */
|
|
36
|
+
async getBalanceMRT(address) {
|
|
37
|
+
const wei = await this.getBalance(address);
|
|
38
|
+
return Number(wei) / 1e18;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Get current block number. */
|
|
42
|
+
async getBlockNumber() {
|
|
43
|
+
const hex = await this._rpc('eth_blockNumber');
|
|
44
|
+
return parseInt(hex, 16);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Get gas price in wei. */
|
|
48
|
+
async getGasPrice() {
|
|
49
|
+
const hex = await this._rpc('eth_gasPrice');
|
|
50
|
+
return BigInt(hex);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Get transaction count (nonce) for address. */
|
|
54
|
+
async getTransactionCount(address) {
|
|
55
|
+
const hex = await this._rpc('eth_getTransactionCount', [address, 'latest']);
|
|
56
|
+
return parseInt(hex, 16);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Get transaction by hash. */
|
|
60
|
+
async getTransaction(txHash) {
|
|
61
|
+
return this._rpc('eth_getTransactionByHash', [txHash]);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Get transaction receipt. */
|
|
65
|
+
async getTransactionReceipt(txHash) {
|
|
66
|
+
return this._rpc('eth_getTransactionReceipt', [txHash]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Send a signed raw transaction. Returns tx hash. */
|
|
70
|
+
async sendRawTransaction(signedTx) {
|
|
71
|
+
return this._rpc('eth_sendRawTransaction', [signedTx]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Read a contract (eth_call). */
|
|
75
|
+
async call(to, data) {
|
|
76
|
+
return this._rpc('eth_call', [{ to, data }, 'latest']);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Get network info. */
|
|
80
|
+
async getNetwork() {
|
|
81
|
+
const chainIdHex = await this._rpc('eth_chainId');
|
|
82
|
+
return { chainId: parseInt(chainIdHex, 16), name: CHAIN_8472.name };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Check that we're connected to Chain 8472. */
|
|
86
|
+
async verify() {
|
|
87
|
+
const { chainId } = await this.getNetwork();
|
|
88
|
+
if (chainId !== this.chainId) {
|
|
89
|
+
throw new Error(`Wrong chain: expected ${this.chainId}, got ${chainId}`);
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get an ethers.js Provider for Chain 8472 (requires ethers v6 installed).
|
|
97
|
+
* @param {string} [rpcUrl]
|
|
98
|
+
*/
|
|
99
|
+
function getEthersProvider(rpcUrl = CHAIN_8472.rpcUrl) {
|
|
100
|
+
try {
|
|
101
|
+
const { JsonRpcProvider } = require('ethers');
|
|
102
|
+
return new JsonRpcProvider(rpcUrl, {
|
|
103
|
+
chainId: CHAIN_8472.chainId,
|
|
104
|
+
name: CHAIN_8472.name,
|
|
105
|
+
});
|
|
106
|
+
} catch {
|
|
107
|
+
throw new Error('ethers.js v6 not installed. Run: npm install ethers');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get an ethers.js Signer connected to Chain 8472.
|
|
113
|
+
* @param {string} privateKey
|
|
114
|
+
* @param {string} [rpcUrl]
|
|
115
|
+
*/
|
|
116
|
+
function getEthersSigner(privateKey, rpcUrl = CHAIN_8472.rpcUrl) {
|
|
117
|
+
const { Wallet } = require('ethers');
|
|
118
|
+
const provider = getEthersProvider(rpcUrl);
|
|
119
|
+
return new Wallet(privateKey, provider);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = { Chain8472Provider, getEthersProvider, getEthersSigner, CHAIN_8472, CONTRACTS_8472 };
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ── Chain 8472 — MyRx Chain ────────────────────────────────────────────────
|
|
4
|
+
const CHAIN_8472 = {
|
|
5
|
+
chainId: 8472,
|
|
6
|
+
name: 'MyRx Chain',
|
|
7
|
+
symbol: 'MRT',
|
|
8
|
+
decimals: 18,
|
|
9
|
+
rpcUrl: 'https://rpc.myrxwallet.io',
|
|
10
|
+
explorerUrl: 'https://explorer.myrxwallet.io',
|
|
11
|
+
infoUrl: 'https://myrxwallet.io',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// ── Native token + Chain 8472 contracts ───────────────────────────────────
|
|
15
|
+
const CONTRACTS_8472 = {
|
|
16
|
+
wrappedMRT: '0x00e69754c21090d69D29a2abe3B6CF153D3F1dF7',
|
|
17
|
+
wrappedBTC: '0xC8604C8FcF96cEc581e8275A2CDf04e7F7348849',
|
|
18
|
+
myRxUSD: '0x8d86EA71F0621ffb47A5a40ab92409A022Dd30F7',
|
|
19
|
+
nftRegistry: '0x8Bfb23155f35b0cC7Ee232dC3aBB925391f90da3',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// ── Bridge chains — MRTBridgeMint deployed ────────────────────────────────
|
|
23
|
+
const BRIDGE_CHAINS = {
|
|
24
|
+
1: { name: 'Ethereum Mainnet', role: 'Institutional settlement' },
|
|
25
|
+
8453: { name: 'Base', role: 'Primary bridge hub (Across Protocol)' },
|
|
26
|
+
42161: { name: 'Arbitrum One', role: 'L2 settlement layer' },
|
|
27
|
+
137: { name: 'Polygon', role: 'High-throughput transactions' },
|
|
28
|
+
56: { name: 'BNB Smart Chain', role: 'Global accessibility' },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// ── MyRxWallet API ─────────────────────────────────────────────────────────
|
|
32
|
+
const API_BASE = 'https://ehr.myrxwallet.io/api/v1';
|
|
33
|
+
const BRIDGE_API = 'https://wallet.myrxwallet.io';
|
|
34
|
+
|
|
35
|
+
// ── ERC-20 minimal ABI ────────────────────────────────────────────────────
|
|
36
|
+
const ERC20_ABI = [
|
|
37
|
+
'function name() view returns (string)',
|
|
38
|
+
'function symbol() view returns (string)',
|
|
39
|
+
'function decimals() view returns (uint8)',
|
|
40
|
+
'function totalSupply() view returns (uint256)',
|
|
41
|
+
'function balanceOf(address) view returns (uint256)',
|
|
42
|
+
'function transfer(address to, uint256 amount) returns (bool)',
|
|
43
|
+
'function approve(address spender, uint256 amount) returns (bool)',
|
|
44
|
+
'function allowance(address owner, address spender) view returns (uint256)',
|
|
45
|
+
'event Transfer(address indexed from, address indexed to, uint256 value)',
|
|
46
|
+
'event Approval(address indexed owner, address indexed spender, uint256 value)',
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
// ── MRTBridgeMint ABI ─────────────────────────────────────────────────────
|
|
50
|
+
const BRIDGE_ABI = [
|
|
51
|
+
'function mint(address to, uint256 amount) external',
|
|
52
|
+
'function burn(address from, uint256 amount) external',
|
|
53
|
+
'function bridgeTo(uint256 targetChainId, address recipient, uint256 amount) external payable',
|
|
54
|
+
'function getBridgeFee(uint256 targetChainId, uint256 amount) view returns (uint256)',
|
|
55
|
+
'event BridgeInitiated(address indexed sender, uint256 indexed targetChainId, address recipient, uint256 amount)',
|
|
56
|
+
'event BridgeCompleted(address indexed recipient, uint256 indexed sourceChainId, uint256 amount)',
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
CHAIN_8472,
|
|
61
|
+
CONTRACTS_8472,
|
|
62
|
+
BRIDGE_CHAINS,
|
|
63
|
+
API_BASE,
|
|
64
|
+
BRIDGE_API,
|
|
65
|
+
ERC20_ABI,
|
|
66
|
+
BRIDGE_ABI,
|
|
67
|
+
};
|
package/src/health.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { API_BASE } = require('./constants');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* MyRxHealthClient — FHIR R4 + MyRxWallet EHR API client.
|
|
7
|
+
*
|
|
8
|
+
* All endpoints require a Bearer token (obtained via SMART on FHIR OAuth 2.0 + PKCE).
|
|
9
|
+
* Standards: HL7 FHIR R4, US Core 6.1.0, SMART App Launch 2.0.0.
|
|
10
|
+
* Live: https://ehr.myrxwallet.io/api/v1/fhir/r4/metadata
|
|
11
|
+
*/
|
|
12
|
+
class MyRxHealthClient {
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} bearerToken JWT from SMART auth flow
|
|
15
|
+
* @param {string} [baseUrl] API base (default: production)
|
|
16
|
+
*/
|
|
17
|
+
constructor(bearerToken, baseUrl = API_BASE) {
|
|
18
|
+
this.token = bearerToken;
|
|
19
|
+
this.base = baseUrl.replace(/\/$/, '');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_headers() {
|
|
23
|
+
return {
|
|
24
|
+
'Authorization': `Bearer ${this.token}`,
|
|
25
|
+
'Content-Type': 'application/fhir+json',
|
|
26
|
+
'Accept': 'application/fhir+json',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async _get(path) {
|
|
31
|
+
const res = await fetch(`${this.base}${path}`, { headers: this._headers() });
|
|
32
|
+
if (!res.ok) throw new Error(`${res.status} ${res.statusText} — GET ${path}`);
|
|
33
|
+
return res.json();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async _post(path, body) {
|
|
37
|
+
const res = await fetch(`${this.base}${path}`, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: this._headers(),
|
|
40
|
+
body: JSON.stringify(body),
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
const text = await res.text();
|
|
44
|
+
throw new Error(`${res.status} — POST ${path}: ${text}`);
|
|
45
|
+
}
|
|
46
|
+
return res.json();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── FHIR Capability Statement ────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
/** Get FHIR R4 CapabilityStatement (no auth required). */
|
|
52
|
+
static async getCapabilityStatement(baseUrl = API_BASE) {
|
|
53
|
+
const res = await fetch(`${baseUrl}/fhir/r4/metadata`, {
|
|
54
|
+
headers: { 'Accept': 'application/fhir+json' },
|
|
55
|
+
});
|
|
56
|
+
return res.json();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Get SMART configuration (no auth required). */
|
|
60
|
+
static async getSmartConfig(baseUrl = 'https://ehr.myrxwallet.io') {
|
|
61
|
+
const res = await fetch(`${baseUrl}/.well-known/smart-configuration`);
|
|
62
|
+
return res.json();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ── Patient ──────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
/** Get FHIR Patient resource. */
|
|
68
|
+
async getPatient(patientId) {
|
|
69
|
+
return this._get(`/fhir/r4/Patient/${patientId}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── Medications ──────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
/** List MedicationRequest resources for a patient. */
|
|
75
|
+
async getMedications(patientId) {
|
|
76
|
+
return this._get(`/fhir/r4/MedicationRequest?patient=${patientId}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ── Conditions ───────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/** List Condition resources (diagnoses) for a patient. */
|
|
82
|
+
async getConditions(patientId) {
|
|
83
|
+
return this._get(`/fhir/r4/Condition?patient=${patientId}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Observations / Vitals ────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
/** List Observation resources (vitals, labs) for a patient. */
|
|
89
|
+
async getObservations(patientId, category = null) {
|
|
90
|
+
const cat = category ? `&category=${category}` : '';
|
|
91
|
+
return this._get(`/fhir/r4/Observation?patient=${patientId}${cat}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── Appointments ─────────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
/** Get patient appointments. */
|
|
97
|
+
async getAppointments(patientId) {
|
|
98
|
+
return this._get(`/appointments/my/${patientId}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Book an appointment. */
|
|
102
|
+
async bookAppointment(body) {
|
|
103
|
+
return this._post('/appointments/book', body);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ── NFT Assets ───────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
/** Get all NFTs owned by a patient (prescription, lab, insurance, etc.). */
|
|
109
|
+
async getNFTs(patientId) {
|
|
110
|
+
return this._get(`/nft/patient/${patientId}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Get MRT wallet balance and recent transactions. */
|
|
114
|
+
async getMRTBalance(patientId) {
|
|
115
|
+
const [balance, txs] = await Promise.all([
|
|
116
|
+
this._get(`/gas/balance/${patientId}`),
|
|
117
|
+
this._get(`/gas/transactions/${patientId}`),
|
|
118
|
+
]);
|
|
119
|
+
return { ...balance, transactions: txs };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ── MyRx Score ───────────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
/** Get patient's MyRx Health Score (300–850 scale). */
|
|
125
|
+
async getMyRxScore(patientId) {
|
|
126
|
+
return this._get(`/score/patient/${patientId}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ── Prescription NFTs ────────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
/** Get all prescription NFTs for a patient. Token format: RX-{SHA256_12}. */
|
|
132
|
+
async getPrescriptionNFTs(patientId) {
|
|
133
|
+
return this._get(`/rx/patient/${patientId}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ── Lab NFTs ─────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
/** Get lab result NFTs for a patient. Token format: LAB-{PID6}-{SEQ6}. */
|
|
139
|
+
async getLabNFTs(patientId) {
|
|
140
|
+
return this._get(`/lab/my-orders`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ── Consent ──────────────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
/** Get consent grants and audit trail for a patient. */
|
|
146
|
+
async getConsentAudit(patientId) {
|
|
147
|
+
return this._get(`/consent/audit/${patientId}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Get a shareable health summary card. */
|
|
151
|
+
async getHealthCard(patientId) {
|
|
152
|
+
return this._get(`/mycard/${patientId}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── SMART Auth helpers ───────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Build the SMART authorization URL (PKCE flow).
|
|
159
|
+
* @param {object} opts
|
|
160
|
+
* @param {string} opts.clientId
|
|
161
|
+
* @param {string} opts.redirectUri
|
|
162
|
+
* @param {string} opts.codeChallenge SHA-256 of code_verifier, base64url-encoded
|
|
163
|
+
* @param {string} [opts.scope] default: 'patient/*.read openid fhirUser'
|
|
164
|
+
* @param {string} [opts.state]
|
|
165
|
+
*/
|
|
166
|
+
static buildAuthUrl(opts, baseUrl = 'https://ehr.myrxwallet.io') {
|
|
167
|
+
const scope = opts.scope || 'patient/*.read openid fhirUser';
|
|
168
|
+
const state = opts.state || Math.random().toString(36).slice(2);
|
|
169
|
+
const params = new URLSearchParams({
|
|
170
|
+
response_type: 'code',
|
|
171
|
+
client_id: opts.clientId,
|
|
172
|
+
redirect_uri: opts.redirectUri,
|
|
173
|
+
scope,
|
|
174
|
+
state,
|
|
175
|
+
code_challenge: opts.codeChallenge,
|
|
176
|
+
code_challenge_method: 'S256',
|
|
177
|
+
});
|
|
178
|
+
return `${baseUrl}/oauth/authorize?${params}`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Exchange authorization code for access token.
|
|
183
|
+
* @param {object} opts
|
|
184
|
+
* @param {string} opts.code
|
|
185
|
+
* @param {string} opts.clientId
|
|
186
|
+
* @param {string} opts.redirectUri
|
|
187
|
+
* @param {string} opts.codeVerifier
|
|
188
|
+
*/
|
|
189
|
+
static async exchangeCode(opts, baseUrl = 'https://ehr.myrxwallet.io') {
|
|
190
|
+
const body = new URLSearchParams({
|
|
191
|
+
grant_type: 'authorization_code',
|
|
192
|
+
code: opts.code,
|
|
193
|
+
client_id: opts.clientId,
|
|
194
|
+
redirect_uri: opts.redirectUri,
|
|
195
|
+
code_verifier: opts.codeVerifier,
|
|
196
|
+
});
|
|
197
|
+
const res = await fetch(`${baseUrl}/oauth/token`, {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
200
|
+
body,
|
|
201
|
+
});
|
|
202
|
+
if (!res.ok) throw new Error(`Token exchange failed: ${res.status}`);
|
|
203
|
+
return res.json();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
module.exports = { MyRxHealthClient };
|
package/src/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @myrxwallet/sdk — Official SDK for MyRxWallet North America Corporation
|
|
5
|
+
*
|
|
6
|
+
* Chain 8472 (MyRx Chain) — EVM-compatible blockchain for federally-mandated
|
|
7
|
+
* patient health data infrastructure pursuant to the 21st Century Cures Act.
|
|
8
|
+
*
|
|
9
|
+
* @see https://myrxwallet.io
|
|
10
|
+
* @see https://ehr.myrxwallet.io/api/v1/fhir/r4/metadata
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { Chain8472Provider, getEthersProvider, getEthersSigner } = require('./chain');
|
|
14
|
+
const { MRTToken } = require('./token');
|
|
15
|
+
const { MRTBridge, BRIDGE_CHAINS } = require('./bridge');
|
|
16
|
+
const { MyRxHealthClient } = require('./health');
|
|
17
|
+
const constants = require('./constants');
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
CHAIN_8472,
|
|
21
|
+
CONTRACTS_8472,
|
|
22
|
+
API_BASE,
|
|
23
|
+
BRIDGE_API,
|
|
24
|
+
ERC20_ABI,
|
|
25
|
+
BRIDGE_ABI,
|
|
26
|
+
} = constants;
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
// ── Chain 8472 ────────────────────────────────────────────────────────────
|
|
30
|
+
Chain8472Provider,
|
|
31
|
+
getEthersProvider,
|
|
32
|
+
getEthersSigner,
|
|
33
|
+
|
|
34
|
+
// ── MRT Token ─────────────────────────────────────────────────────────────
|
|
35
|
+
MRTToken,
|
|
36
|
+
|
|
37
|
+
// ── Bridge ────────────────────────────────────────────────────────────────
|
|
38
|
+
MRTBridge,
|
|
39
|
+
BRIDGE_CHAINS,
|
|
40
|
+
|
|
41
|
+
// ── Healthcare API ────────────────────────────────────────────────────────
|
|
42
|
+
MyRxHealthClient,
|
|
43
|
+
|
|
44
|
+
// ── Constants ─────────────────────────────────────────────────────────────
|
|
45
|
+
CHAIN_8472,
|
|
46
|
+
CONTRACTS_8472,
|
|
47
|
+
API_BASE,
|
|
48
|
+
BRIDGE_API,
|
|
49
|
+
ERC20_ABI,
|
|
50
|
+
BRIDGE_ABI,
|
|
51
|
+
};
|
package/src/token.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { CONTRACTS_8472, ERC20_ABI } = require('./constants');
|
|
4
|
+
const { getEthersProvider, getEthersSigner } = require('./chain');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* MRTToken — ERC-20 interface for the MRT (MyRxWallet Reward Token).
|
|
8
|
+
* MRT is the native gas + governance + validator compensation token on Chain 8472.
|
|
9
|
+
*
|
|
10
|
+
* Regulatory note: MRT rewards are infrastructure compensation for active validator
|
|
11
|
+
* work — not investment yield. Howey Test Prongs 3 & 4 are not satisfied.
|
|
12
|
+
* See: https://myrxwallet.io/compliance.html#staking-validators
|
|
13
|
+
*/
|
|
14
|
+
class MRTToken {
|
|
15
|
+
constructor(rpcUrl) {
|
|
16
|
+
this._provider = getEthersProvider(rpcUrl);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_contract(signerOrProvider) {
|
|
20
|
+
const { Contract } = require('ethers');
|
|
21
|
+
return new Contract(CONTRACTS_8472.wrappedMRT, ERC20_ABI, signerOrProvider || this._provider);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Get MRT balance for an address (returns formatted string, e.g. "100.0"). */
|
|
25
|
+
async balanceOf(address) {
|
|
26
|
+
const { formatUnits } = require('ethers');
|
|
27
|
+
const bal = await this._contract().balanceOf(address);
|
|
28
|
+
return formatUnits(bal, 18);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Get total MRT supply in circulation. */
|
|
32
|
+
async totalSupply() {
|
|
33
|
+
const { formatUnits } = require('ethers');
|
|
34
|
+
const sup = await this._contract().totalSupply();
|
|
35
|
+
return formatUnits(sup, 18);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Transfer MRT tokens.
|
|
40
|
+
* @param {string} privateKey Sender private key
|
|
41
|
+
* @param {string} to Recipient address
|
|
42
|
+
* @param {string|number} amount Amount in MRT (not wei)
|
|
43
|
+
*/
|
|
44
|
+
async transfer(privateKey, to, amount) {
|
|
45
|
+
const { parseUnits } = require('ethers');
|
|
46
|
+
const signer = getEthersSigner(privateKey);
|
|
47
|
+
const contract = this._contract(signer);
|
|
48
|
+
const amountWei = parseUnits(String(amount), 18);
|
|
49
|
+
const tx = await contract.transfer(to, amountWei);
|
|
50
|
+
return tx.wait();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Approve a spender (e.g. bridge contract) to spend MRT.
|
|
55
|
+
* @param {string} privateKey
|
|
56
|
+
* @param {string} spender
|
|
57
|
+
* @param {string|number} amount
|
|
58
|
+
*/
|
|
59
|
+
async approve(privateKey, spender, amount) {
|
|
60
|
+
const { parseUnits } = require('ethers');
|
|
61
|
+
const signer = getEthersSigner(privateKey);
|
|
62
|
+
const contract = this._contract(signer);
|
|
63
|
+
const amountWei = parseUnits(String(amount), 18);
|
|
64
|
+
const tx = await contract.approve(spender, amountWei);
|
|
65
|
+
return tx.wait();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Get allowance in formatted MRT. */
|
|
69
|
+
async allowance(owner, spender) {
|
|
70
|
+
const { formatUnits } = require('ethers');
|
|
71
|
+
const val = await this._contract().allowance(owner, spender);
|
|
72
|
+
return formatUnits(val, 18);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Get token metadata. */
|
|
76
|
+
async metadata() {
|
|
77
|
+
const c = this._contract();
|
|
78
|
+
const [name, symbol, decimals, supply] = await Promise.all([
|
|
79
|
+
c.name(), c.symbol(), c.decimals(), c.totalSupply(),
|
|
80
|
+
]);
|
|
81
|
+
const { formatUnits } = require('ethers');
|
|
82
|
+
return { name, symbol, decimals: Number(decimals), totalSupply: formatUnits(supply, 18) };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = { MRTToken };
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// @myrxwallet/sdk — TypeScript Definitions
|
|
2
|
+
// Chain 8472 (MyRx Chain) — FHIR R4 — MRT Token — Multi-chain Bridge
|
|
3
|
+
|
|
4
|
+
export interface ChainConfig {
|
|
5
|
+
chainId: number;
|
|
6
|
+
name: string;
|
|
7
|
+
symbol: string;
|
|
8
|
+
decimals: number;
|
|
9
|
+
rpcUrl: string;
|
|
10
|
+
explorerUrl: string;
|
|
11
|
+
infoUrl: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Contracts8472 {
|
|
15
|
+
wrappedMRT: string;
|
|
16
|
+
wrappedBTC: string;
|
|
17
|
+
myRxUSD: string;
|
|
18
|
+
nftRegistry: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface BridgeChainInfo {
|
|
22
|
+
chainId: number;
|
|
23
|
+
name: string;
|
|
24
|
+
role: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface BridgeResult {
|
|
28
|
+
txHash: string;
|
|
29
|
+
receipt: object;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface TokenMetadata {
|
|
33
|
+
name: string;
|
|
34
|
+
symbol: string;
|
|
35
|
+
decimals: number;
|
|
36
|
+
totalSupply: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SmartAuthOptions {
|
|
40
|
+
clientId: string;
|
|
41
|
+
redirectUri: string;
|
|
42
|
+
codeChallenge: string;
|
|
43
|
+
scope?: string;
|
|
44
|
+
state?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface CodeExchangeOptions {
|
|
48
|
+
code: string;
|
|
49
|
+
clientId: string;
|
|
50
|
+
redirectUri: string;
|
|
51
|
+
codeVerifier: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── Chain8472Provider ─────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
export class Chain8472Provider {
|
|
57
|
+
constructor(rpcUrl?: string);
|
|
58
|
+
getBalance(address: string): Promise<bigint>;
|
|
59
|
+
getBalanceMRT(address: string): Promise<number>;
|
|
60
|
+
getBlockNumber(): Promise<number>;
|
|
61
|
+
getGasPrice(): Promise<bigint>;
|
|
62
|
+
getTransactionCount(address: string): Promise<number>;
|
|
63
|
+
getTransaction(txHash: string): Promise<object>;
|
|
64
|
+
getTransactionReceipt(txHash: string): Promise<object>;
|
|
65
|
+
sendRawTransaction(signedTx: string): Promise<string>;
|
|
66
|
+
call(to: string, data: string): Promise<string>;
|
|
67
|
+
getNetwork(): Promise<{ chainId: number; name: string }>;
|
|
68
|
+
verify(): Promise<boolean>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function getEthersProvider(rpcUrl?: string): object;
|
|
72
|
+
export function getEthersSigner(privateKey: string, rpcUrl?: string): object;
|
|
73
|
+
|
|
74
|
+
// ── MRTToken ──────────────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
export class MRTToken {
|
|
77
|
+
constructor(rpcUrl?: string);
|
|
78
|
+
balanceOf(address: string): Promise<string>;
|
|
79
|
+
totalSupply(): Promise<string>;
|
|
80
|
+
transfer(privateKey: string, to: string, amount: string | number): Promise<object>;
|
|
81
|
+
approve(privateKey: string, spender: string, amount: string | number): Promise<object>;
|
|
82
|
+
allowance(owner: string, spender: string): Promise<string>;
|
|
83
|
+
metadata(): Promise<TokenMetadata>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── MRTBridge ─────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
export class MRTBridge {
|
|
89
|
+
constructor(bridgeContractAddress: string, rpcUrl: string);
|
|
90
|
+
bridgeTo(privateKey: string, targetChainId: number, recipient: string, amount: string | number): Promise<BridgeResult>;
|
|
91
|
+
getBridgeFee(targetChainId: number, amount: string | number): Promise<string>;
|
|
92
|
+
static supportedChains(): BridgeChainInfo[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── MyRxHealthClient ──────────────────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
export class MyRxHealthClient {
|
|
98
|
+
constructor(bearerToken: string, baseUrl?: string);
|
|
99
|
+
getPatient(patientId: string): Promise<object>;
|
|
100
|
+
getMedications(patientId: string): Promise<object>;
|
|
101
|
+
getConditions(patientId: string): Promise<object>;
|
|
102
|
+
getObservations(patientId: string, category?: string): Promise<object>;
|
|
103
|
+
getAppointments(patientId: string): Promise<object>;
|
|
104
|
+
bookAppointment(body: object): Promise<object>;
|
|
105
|
+
getNFTs(patientId: string): Promise<object>;
|
|
106
|
+
getMRTBalance(patientId: string): Promise<object>;
|
|
107
|
+
getMyRxScore(patientId: string): Promise<object>;
|
|
108
|
+
getPrescriptionNFTs(patientId: string): Promise<object>;
|
|
109
|
+
getLabNFTs(patientId: string): Promise<object>;
|
|
110
|
+
getConsentAudit(patientId: string): Promise<object>;
|
|
111
|
+
getHealthCard(patientId: string): Promise<object>;
|
|
112
|
+
static getCapabilityStatement(baseUrl?: string): Promise<object>;
|
|
113
|
+
static getSmartConfig(baseUrl?: string): Promise<object>;
|
|
114
|
+
static buildAuthUrl(opts: SmartAuthOptions, baseUrl?: string): string;
|
|
115
|
+
static exchangeCode(opts: CodeExchangeOptions, baseUrl?: string): Promise<object>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── Constants ─────────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
export const CHAIN_8472: ChainConfig;
|
|
121
|
+
export const CONTRACTS_8472: Contracts8472;
|
|
122
|
+
export const API_BASE: string;
|
|
123
|
+
export const BRIDGE_API: string;
|
|
124
|
+
export const ERC20_ABI: string[];
|
|
125
|
+
export const BRIDGE_ABI: string[];
|
|
126
|
+
export const BRIDGE_CHAINS: Record<number, { name: string; role: string }>;
|