@phantom/server-sdk 0.0.2

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/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # Server SDK
2
+
3
+ This package provides integration with @phantom/openapi-wallet-service for secure wallet management and transaction signing.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @phantom/server-sdk
9
+ ```
10
+
11
+ ## Configuration
12
+
13
+ The SDK requires the following configuration:
14
+
15
+ - `apiPrivateKey`: Your signing key for authentication (base58 encoded)
16
+ - `organizationId`: Your organization ID from Phantom
17
+ - `apiBaseUrl`: The wallet API endpoint URL
18
+
19
+ ```typescript
20
+ import { ServerSDK } from '@phantom/server-sdk';
21
+
22
+ const sdk = new ServerSDK({
23
+ apiPrivateKey: 'your-signing-key-base58',
24
+ organizationId: 'your-org-id',
25
+ apiBaseUrl: 'https://api.phantom.app/v1'
26
+ });
27
+ ```
28
+
29
+ ## Network Identifiers
30
+
31
+ The SDK provides user-friendly enums for CAIP-2 network identifiers:
32
+
33
+ ```typescript
34
+ import { NetworkId } from '@phantom/server-sdk';
35
+
36
+ // Use the NetworkId enum for easy access to CAIP-2 identifiers
37
+ const solanaMainnet = NetworkId.SOLANA_MAINNET; // 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'
38
+ const ethMainnet = NetworkId.ETHEREUM_MAINNET; // 'eip155:1'
39
+ const polygonMainnet = NetworkId.POLYGON_MAINNET; // 'eip155:137'
40
+
41
+ // Example usage with SDK methods
42
+ const result = await sdk.signAndSendTransaction(
43
+ walletId,
44
+ transaction,
45
+ NetworkId.SOLANA_MAINNET // Instead of hardcoding 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'
46
+ );
47
+
48
+ // Sign a message on Ethereum
49
+ const signature = await sdk.signMessage(
50
+ walletId,
51
+ 'Hello World',
52
+ NetworkId.ETHEREUM_MAINNET
53
+ );
54
+
55
+
56
+ ```
57
+
58
+ ### Available Networks
59
+
60
+ | Network | Enum Value | CAIP-2 ID |
61
+ |---------|-----------|-----------|
62
+ | **Solana** | | |
63
+ | Mainnet | `NetworkId.SOLANA_MAINNET` | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` |
64
+ | Devnet | `NetworkId.SOLANA_DEVNET` | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` |
65
+ | Testnet | `NetworkId.SOLANA_TESTNET` | `solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z` |
66
+ | **Ethereum** | | |
67
+ | Mainnet | `NetworkId.ETHEREUM_MAINNET` | `eip155:1` |
68
+ | Goerli | `NetworkId.ETHEREUM_GOERLI` | `eip155:5` |
69
+ | Sepolia | `NetworkId.ETHEREUM_SEPOLIA` | `eip155:11155111` |
70
+ | **Polygon** | | |
71
+ | Mainnet | `NetworkId.POLYGON_MAINNET` | `eip155:137` |
72
+ | Mumbai | `NetworkId.POLYGON_MUMBAI` | `eip155:80001` |
73
+ | **Arbitrum** | | |
74
+ | One | `NetworkId.ARBITRUM_ONE` | `eip155:42161` |
75
+ | Goerli | `NetworkId.ARBITRUM_GOERLI` | `eip155:421613` |
76
+ | **Base** | | |
77
+ | Mainnet | `NetworkId.BASE_MAINNET` | `eip155:8453` |
78
+ | Sepolia | `NetworkId.BASE_SEPOLIA` | `eip155:84532` |
79
+
80
+ ## CAIP-2 Network Identifiers
81
+
82
+ This SDK uses the CAIP-2 (Chain Agnostic Improvement Proposal 2) standard for network identifiers. CAIP-2 provides a standardized way to identify blockchain networks across different ecosystems.
83
+
84
+ ### Format
85
+ CAIP-2 identifiers follow the format: `namespace:reference`
86
+
87
+ ### Common Network IDs
88
+ - **Solana Mainnet**: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`
89
+ - **Solana Devnet**: `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`
90
+ - **Ethereum Mainnet**: `eip155:1`
91
+ - **Polygon Mainnet**: `eip155:137`
92
+ - **Arbitrum One**: `eip155:42161`
93
+ - **Base Mainnet**: `eip155:8453`
94
+
95
+ ## Methods
96
+
97
+ ### createWallet(walletName?: string)
98
+ Creates a new wallet with an optional name. If no name is provided, a default name with timestamp is used.
99
+ After creation, it retrieves the public key by signing an empty payload.
100
+
101
+ ```typescript
102
+ const wallet = await sdk.createWallet('My Main Wallet');
103
+ // Returns: {
104
+ // walletId: 'wallet-uuid',
105
+ // addresses: [{ addressType: 'Solana', address: 'public-key' }]
106
+ // }
107
+ ```
108
+
109
+ ### signAndSendTransaction(walletId: string, transaction: Uint8Array, networkId: string)
110
+ Signs a transaction using the wallet service. The transaction should be provided as a Uint8Array and will be encoded as base64 before sending to the KMS.
111
+
112
+ The SDK automatically derives the submission configuration from the CAIP-2 network ID. If the network supports transaction submission, Phantom will submit the transaction to the blockchain after signing.
113
+
114
+ **Note:** This method returns only the signed transaction data. To get the transaction hash/signature, you need to extract it from the signed transaction.
115
+
116
+ ```typescript
117
+ import { NetworkId } from '@phantom/server-sdk';
118
+
119
+ const transactionBuffer = new Uint8Array([...]); // Your serialized transaction
120
+ const result = await sdk.signAndSendTransaction(
121
+ 'wallet-id',
122
+ transactionBuffer,
123
+ NetworkId.SOLANA_MAINNET // Using enum - submission config automatically derived
124
+ );
125
+
126
+ // Returns: {
127
+ // rawTransaction: 'base64-signed-transaction'
128
+ // }
129
+
130
+ // Extract the transaction signature (hash)
131
+ // Note: requires 'import bs58 from "bs58"'
132
+ const signedTx = Transaction.from(Buffer.from(result.rawTransaction, 'base64'));
133
+ const signature = signedTx.signature
134
+ ? bs58.encode(signedTx.signature)
135
+ : bs58.encode(signedTx.signatures[0].signature);
136
+ ```
137
+
138
+ ### signMessage(walletId: string, message: string, networkId: string)
139
+ Signs a message with the specified wallet using the signRawPayload method.
140
+
141
+ ```typescript
142
+ const signature = await sdk.signMessage(
143
+ 'wallet-id',
144
+ 'Hello World',
145
+ NetworkId.SOLANA_MAINNET // Using enum for CAIP-2 network ID
146
+ );
147
+ // Returns: base64 encoded signature
148
+ ```
149
+
150
+ ## CAIP-2 Utility Functions
151
+
152
+ The SDK exports several utility functions for working with CAIP-2 network identifiers:
153
+
154
+ ```typescript
155
+ import {
156
+ deriveSubmissionConfig,
157
+ supportsTransactionSubmission,
158
+ getNetworkDescription,
159
+ getSupportedNetworkIds,
160
+ getNetworkIdsByChain
161
+ } from '@phantom/server-sdk';
162
+
163
+ // Check if a network supports transaction submission
164
+ if (supportsTransactionSubmission('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')) {
165
+ // Network supports automatic transaction submission
166
+ }
167
+
168
+ // Get human-readable network description
169
+ const description = getNetworkDescription('eip155:137'); // "Polygon Mainnet"
170
+
171
+ // List all supported networks
172
+ const allNetworks = getSupportedNetworkIds();
173
+
174
+ // Get networks for a specific chain
175
+ const solanaNetworks = getNetworkIdsByChain('solana');
176
+ // ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', ...]
177
+ ```
178
+
179
+ ## Implementation Details
180
+
181
+ This SDK uses the @phantom/openapi-wallet-service package which provides:
182
+ - `createWallet` - Creates a new wallet and retrieves its public key via signRawPayload
183
+ - `signTransaction` - Signs transactions with the wallet's private key
184
+ - `signRawPayload` - Signs raw payloads/messages and returns signature with public key
185
+
186
+ The SDK handles:
187
+ - Network-specific algorithms and curves automatically
188
+ - Standard derivation paths for each blockchain
189
+ - Base64 encoding for transaction data
190
+ - Authentication via Ed25519 signatures
191
+ - CAIP-2 network ID parsing and submission config derivation
192
+
193
+ ## Authentication
194
+
195
+ The SDK authenticates requests using Ed25519 signatures:
196
+ - Each request is signed with your organization's private key
197
+ - The signature, public key, and timestamp are added as headers
198
+ - This ensures secure communication with the Phantom wallet service
199
+
200
+
201
+ ## Notes
202
+
203
+ - The wallet ID is a UUID assigned by the service when creating the wallet
204
+ - Public keys are retrieved using the signRawPayload method with an empty payload
205
+ - Transaction hashes are not returned by the signing service - they're generated after blockchain submission
206
+ - The service returns the public key that signed the transaction in the signature field
207
+ - Default wallet names include a timestamp to ensure uniqueness
208
+ - Message signing supports both Solana (Ed25519) and Ethereum (Secp256k1) networks
package/dist/auth.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import nacl from 'tweetnacl';
3
+ /**
4
+ * Creates an authenticated axios instance that signs requests with Ed25519
5
+ */
6
+ export declare function createAuthenticatedAxiosInstance(signingKeypair: nacl.SignKeyPair): AxiosInstance;
package/dist/auth.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createAuthenticatedAxiosInstance = createAuthenticatedAxiosInstance;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
9
+ /**
10
+ * Creates an authenticated axios instance that signs requests with Ed25519
11
+ */
12
+ function createAuthenticatedAxiosInstance(signingKeypair) {
13
+ const instance = axios_1.default.create();
14
+ instance.interceptors.request.use((config) => {
15
+ // Sign the message
16
+ const requestBody = typeof config.data === "string" ? config.data : JSON.stringify(config.data);
17
+ const dataUtf8 = Buffer.from(requestBody, "utf8");
18
+ const signature = tweetnacl_1.default.sign.detached(dataUtf8, signingKeypair.secretKey);
19
+ config.headers["X-Phantom-Sig"] = Buffer.from(signature).toString("base64");
20
+ return config;
21
+ });
22
+ return instance;
23
+ }
@@ -0,0 +1,59 @@
1
+ interface SubmissionConfig {
2
+ chain: string;
3
+ network: string;
4
+ }
5
+ /**
6
+ * User-friendly enum for CAIP-2 network identifiers
7
+ * Use these constants instead of hardcoding network IDs
8
+ */
9
+ export declare enum NetworkId {
10
+ SOLANA_MAINNET = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
11
+ SOLANA_DEVNET = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
12
+ SOLANA_TESTNET = "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z",
13
+ ETHEREUM_MAINNET = "eip155:1",
14
+ ETHEREUM_GOERLI = "eip155:5",
15
+ ETHEREUM_SEPOLIA = "eip155:11155111",
16
+ POLYGON_MAINNET = "eip155:137",
17
+ POLYGON_MUMBAI = "eip155:80001",
18
+ OPTIMISM_MAINNET = "eip155:10",
19
+ OPTIMISM_GOERLI = "eip155:420",
20
+ ARBITRUM_ONE = "eip155:42161",
21
+ ARBITRUM_GOERLI = "eip155:421613",
22
+ BASE_MAINNET = "eip155:8453",
23
+ BASE_GOERLI = "eip155:84531",
24
+ BASE_SEPOLIA = "eip155:84532",
25
+ BITCOIN_MAINNET = "bip122:000000000019d6689c085ae165831e93",
26
+ BITCOIN_TESTNET = "bip122:000000000933ea01ad0ee984209779ba",
27
+ SUI_MAINNET = "sui:35834a8a",
28
+ SUI_TESTNET = "sui:4c78adac"
29
+ }
30
+ /**
31
+ * Derive SubmissionConfig from a CAIP-2 network ID
32
+ * @param networkId - CAIP-2 compliant network ID (e.g., 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
33
+ * @returns SubmissionConfig if network supports transaction submission, undefined otherwise
34
+ */
35
+ export declare function deriveSubmissionConfig(networkId: string): SubmissionConfig | undefined;
36
+ /**
37
+ * Check if a network ID supports transaction submission
38
+ * @param networkId - CAIP-2 compliant network ID
39
+ * @returns true if the network supports transaction submission
40
+ */
41
+ export declare function supportsTransactionSubmission(networkId: string): boolean;
42
+ /**
43
+ * Get network description for a CAIP-2 network ID
44
+ * @param networkId - CAIP-2 compliant network ID
45
+ * @returns Network description or undefined if not found
46
+ */
47
+ export declare function getNetworkDescription(networkId: string): string | undefined;
48
+ /**
49
+ * List all supported CAIP-2 network IDs
50
+ * @returns Array of supported network IDs
51
+ */
52
+ export declare function getSupportedNetworkIds(): string[];
53
+ /**
54
+ * Get all networks for a specific chain
55
+ * @param chain - Chain name (e.g., 'solana', 'ethereum')
56
+ * @returns Array of network IDs for the specified chain
57
+ */
58
+ export declare function getNetworkIdsByChain(chain: string): string[];
59
+ export {};
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NetworkId = void 0;
4
+ exports.deriveSubmissionConfig = deriveSubmissionConfig;
5
+ exports.supportsTransactionSubmission = supportsTransactionSubmission;
6
+ exports.getNetworkDescription = getNetworkDescription;
7
+ exports.getSupportedNetworkIds = getSupportedNetworkIds;
8
+ exports.getNetworkIdsByChain = getNetworkIdsByChain;
9
+ /**
10
+ * User-friendly enum for CAIP-2 network identifiers
11
+ * Use these constants instead of hardcoding network IDs
12
+ */
13
+ var NetworkId;
14
+ (function (NetworkId) {
15
+ // Solana Networks
16
+ NetworkId["SOLANA_MAINNET"] = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
17
+ NetworkId["SOLANA_DEVNET"] = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
18
+ NetworkId["SOLANA_TESTNET"] = "solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z";
19
+ // Ethereum Networks
20
+ NetworkId["ETHEREUM_MAINNET"] = "eip155:1";
21
+ NetworkId["ETHEREUM_GOERLI"] = "eip155:5";
22
+ NetworkId["ETHEREUM_SEPOLIA"] = "eip155:11155111";
23
+ // Polygon Networks
24
+ NetworkId["POLYGON_MAINNET"] = "eip155:137";
25
+ NetworkId["POLYGON_MUMBAI"] = "eip155:80001";
26
+ // Optimism Networks
27
+ NetworkId["OPTIMISM_MAINNET"] = "eip155:10";
28
+ NetworkId["OPTIMISM_GOERLI"] = "eip155:420";
29
+ // Arbitrum Networks
30
+ NetworkId["ARBITRUM_ONE"] = "eip155:42161";
31
+ NetworkId["ARBITRUM_GOERLI"] = "eip155:421613";
32
+ // Base Networks
33
+ NetworkId["BASE_MAINNET"] = "eip155:8453";
34
+ NetworkId["BASE_GOERLI"] = "eip155:84531";
35
+ NetworkId["BASE_SEPOLIA"] = "eip155:84532";
36
+ // Bitcoin Networks (for future support)
37
+ NetworkId["BITCOIN_MAINNET"] = "bip122:000000000019d6689c085ae165831e93";
38
+ NetworkId["BITCOIN_TESTNET"] = "bip122:000000000933ea01ad0ee984209779ba";
39
+ // Sui Networks (for future support)
40
+ NetworkId["SUI_MAINNET"] = "sui:35834a8a";
41
+ NetworkId["SUI_TESTNET"] = "sui:4c78adac";
42
+ })(NetworkId || (exports.NetworkId = NetworkId = {}));
43
+ const CAIP2_NETWORK_MAPPINGS = {
44
+ // Solana networks
45
+ 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': {
46
+ chain: 'solana',
47
+ network: 'mainnet',
48
+ description: 'Solana Mainnet-Beta'
49
+ },
50
+ 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': {
51
+ chain: 'solana',
52
+ network: 'devnet',
53
+ description: 'Solana Devnet'
54
+ },
55
+ 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z': {
56
+ chain: 'solana',
57
+ network: 'testnet',
58
+ description: 'Solana Testnet'
59
+ },
60
+ // Ethereum/EVM networks
61
+ 'eip155:1': {
62
+ chain: 'ethereum',
63
+ network: 'mainnet',
64
+ description: 'Ethereum Mainnet'
65
+ },
66
+ 'eip155:5': {
67
+ chain: 'ethereum',
68
+ network: 'goerli',
69
+ description: 'Goerli Testnet'
70
+ },
71
+ 'eip155:11155111': {
72
+ chain: 'ethereum',
73
+ network: 'sepolia',
74
+ description: 'Sepolia Testnet'
75
+ },
76
+ 'eip155:137': {
77
+ chain: 'polygon',
78
+ network: 'mainnet',
79
+ description: 'Polygon Mainnet'
80
+ },
81
+ 'eip155:80001': {
82
+ chain: 'polygon',
83
+ network: 'mumbai',
84
+ description: 'Polygon Mumbai Testnet'
85
+ },
86
+ 'eip155:10': {
87
+ chain: 'optimism',
88
+ network: 'mainnet',
89
+ description: 'Optimism Mainnet'
90
+ },
91
+ 'eip155:420': {
92
+ chain: 'optimism',
93
+ network: 'goerli',
94
+ description: 'Optimism Goerli Testnet'
95
+ },
96
+ 'eip155:42161': {
97
+ chain: 'arbitrum',
98
+ network: 'mainnet',
99
+ description: 'Arbitrum One'
100
+ },
101
+ 'eip155:421613': {
102
+ chain: 'arbitrum',
103
+ network: 'goerli',
104
+ description: 'Arbitrum Goerli'
105
+ },
106
+ 'eip155:8453': {
107
+ chain: 'base',
108
+ network: 'mainnet',
109
+ description: 'Base Mainnet'
110
+ },
111
+ 'eip155:84531': {
112
+ chain: 'base',
113
+ network: 'goerli',
114
+ description: 'Base Goerli Testnet'
115
+ },
116
+ 'eip155:84532': {
117
+ chain: 'base',
118
+ network: 'sepolia',
119
+ description: 'Base Sepolia Testnet'
120
+ },
121
+ // Bitcoin networks (for future support)
122
+ 'bip122:000000000019d6689c085ae165831e93': {
123
+ chain: 'bitcoin',
124
+ network: 'mainnet',
125
+ description: 'Bitcoin Mainnet'
126
+ },
127
+ 'bip122:000000000933ea01ad0ee984209779ba': {
128
+ chain: 'bitcoin',
129
+ network: 'testnet',
130
+ description: 'Bitcoin Testnet'
131
+ },
132
+ // Sui networks (for future support)
133
+ 'sui:35834a8a': {
134
+ chain: 'sui',
135
+ network: 'mainnet',
136
+ description: 'Sui Mainnet'
137
+ },
138
+ 'sui:4c78adac': {
139
+ chain: 'sui',
140
+ network: 'testnet',
141
+ description: 'Sui Testnet'
142
+ },
143
+ };
144
+ /**
145
+ * Derive SubmissionConfig from a CAIP-2 network ID
146
+ * @param networkId - CAIP-2 compliant network ID (e.g., 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
147
+ * @returns SubmissionConfig if network supports transaction submission, undefined otherwise
148
+ */
149
+ function deriveSubmissionConfig(networkId) {
150
+ const mapping = CAIP2_NETWORK_MAPPINGS[networkId];
151
+ if (!mapping) {
152
+ // Network not found in mappings - cannot derive submission config
153
+ return undefined;
154
+ }
155
+ return {
156
+ chain: mapping.chain,
157
+ network: mapping.network
158
+ };
159
+ }
160
+ /**
161
+ * Check if a network ID supports transaction submission
162
+ * @param networkId - CAIP-2 compliant network ID
163
+ * @returns true if the network supports transaction submission
164
+ */
165
+ function supportsTransactionSubmission(networkId) {
166
+ return networkId in CAIP2_NETWORK_MAPPINGS;
167
+ }
168
+ /**
169
+ * Get network description for a CAIP-2 network ID
170
+ * @param networkId - CAIP-2 compliant network ID
171
+ * @returns Network description or undefined if not found
172
+ */
173
+ function getNetworkDescription(networkId) {
174
+ return CAIP2_NETWORK_MAPPINGS[networkId]?.description;
175
+ }
176
+ /**
177
+ * List all supported CAIP-2 network IDs
178
+ * @returns Array of supported network IDs
179
+ */
180
+ function getSupportedNetworkIds() {
181
+ return Object.keys(CAIP2_NETWORK_MAPPINGS);
182
+ }
183
+ /**
184
+ * Get all networks for a specific chain
185
+ * @param chain - Chain name (e.g., 'solana', 'ethereum')
186
+ * @returns Array of network IDs for the specified chain
187
+ */
188
+ function getNetworkIdsByChain(chain) {
189
+ return Object.entries(CAIP2_NETWORK_MAPPINGS)
190
+ .filter(([_, mapping]) => mapping.chain.toLowerCase() === chain.toLowerCase())
191
+ .map(([networkId]) => networkId);
192
+ }
@@ -0,0 +1,27 @@
1
+ import { DerivationInfoCurveEnum, DerivationInfoAddressFormatEnum, Algorithm } from '@phantom/openapi-wallet-service';
2
+ /**
3
+ * Default derivation paths for different blockchain networks
4
+ */
5
+ export declare enum DerivationPath {
6
+ Solana = "m/44'/501'/0'/0'",
7
+ Ethereum = "m/44'/60'/0'/0",
8
+ Bitcoin = "m/84'/0'/0'/0",
9
+ Sui = "m/44'/784'/0'/0'/0'"
10
+ }
11
+ /**
12
+ * Helper function to get derivation path based on network ID
13
+ */
14
+ export declare function getDerivationPathForNetwork(networkId: string): string;
15
+ /**
16
+ * Network configuration
17
+ */
18
+ export interface NetworkConfig {
19
+ derivationPath: string;
20
+ curve: DerivationInfoCurveEnum;
21
+ algorithm: Algorithm;
22
+ addressFormat: DerivationInfoAddressFormatEnum;
23
+ }
24
+ /**
25
+ * Get complete network configuration
26
+ */
27
+ export declare function getNetworkConfig(networkId: string): NetworkConfig;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DerivationPath = void 0;
4
+ exports.getDerivationPathForNetwork = getDerivationPathForNetwork;
5
+ exports.getNetworkConfig = getNetworkConfig;
6
+ const openapi_wallet_service_1 = require("@phantom/openapi-wallet-service");
7
+ /**
8
+ * Default derivation paths for different blockchain networks
9
+ */
10
+ var DerivationPath;
11
+ (function (DerivationPath) {
12
+ // Solana - BIP44 standard for Solana (coin type 501)
13
+ DerivationPath["Solana"] = "m/44'/501'/0'/0'";
14
+ // Ethereum - BIP44 standard for Ethereum and all EVM-compatible chains (coin type 60)
15
+ DerivationPath["Ethereum"] = "m/44'/60'/0'/0";
16
+ // Bitcoin - BIP44 standard for Bitcoin (coin type 0)
17
+ DerivationPath["Bitcoin"] = "m/84'/0'/0'/0";
18
+ // Sui - BIP44 standard for Sui (coin type 784)
19
+ DerivationPath["Sui"] = "m/44'/784'/0'/0'/0'";
20
+ })(DerivationPath || (exports.DerivationPath = DerivationPath = {}));
21
+ /**
22
+ * Helper function to get derivation path based on network ID
23
+ */
24
+ function getDerivationPathForNetwork(networkId) {
25
+ // Extract the chain name from network ID format (e.g., "solana:mainnet" -> "solana")
26
+ const network = networkId.split(':')[0].toLowerCase();
27
+ switch (network) {
28
+ case 'solana':
29
+ return DerivationPath.Solana;
30
+ case 'sui':
31
+ return DerivationPath.Sui;
32
+ case 'bitcoin':
33
+ case 'btc':
34
+ return DerivationPath.Bitcoin;
35
+ case 'eip155': // EVM chains use eip155 prefix
36
+ case 'ethereum':
37
+ case 'eth':
38
+ default:
39
+ // Default to Ethereum path for all EVM-compatible chains
40
+ return DerivationPath.Ethereum;
41
+ }
42
+ }
43
+ /**
44
+ * Get complete network configuration
45
+ */
46
+ function getNetworkConfig(networkId) {
47
+ const network = networkId.split(':')[0].toLowerCase();
48
+ switch (network) {
49
+ case 'solana':
50
+ return {
51
+ derivationPath: DerivationPath.Solana,
52
+ curve: openapi_wallet_service_1.DerivationInfoCurveEnum.ed25519,
53
+ algorithm: openapi_wallet_service_1.Algorithm.ed25519,
54
+ addressFormat: openapi_wallet_service_1.DerivationInfoAddressFormatEnum.solana
55
+ };
56
+ case 'sui':
57
+ return {
58
+ derivationPath: DerivationPath.Sui,
59
+ curve: openapi_wallet_service_1.DerivationInfoCurveEnum.ed25519,
60
+ algorithm: openapi_wallet_service_1.Algorithm.ed25519,
61
+ addressFormat: openapi_wallet_service_1.DerivationInfoAddressFormatEnum.sui,
62
+ };
63
+ case 'bitcoin':
64
+ case 'btc':
65
+ return {
66
+ derivationPath: DerivationPath.Bitcoin,
67
+ curve: openapi_wallet_service_1.DerivationInfoCurveEnum.secp256k1,
68
+ algorithm: openapi_wallet_service_1.Algorithm.secp256k1,
69
+ addressFormat: openapi_wallet_service_1.DerivationInfoAddressFormatEnum.bitcoinSegwit // Bitcoin uses a different format, but for SDK consistency we use Ethereum format
70
+ };
71
+ default:
72
+ // All EVM-compatible chains (Ethereum, Polygon, BSC, Arbitrum, etc.)
73
+ return {
74
+ derivationPath: DerivationPath.Ethereum,
75
+ curve: openapi_wallet_service_1.DerivationInfoCurveEnum.secp256k1,
76
+ algorithm: openapi_wallet_service_1.Algorithm.secp256k1,
77
+ addressFormat: openapi_wallet_service_1.DerivationInfoAddressFormatEnum.ethereum // EVM chains use Ethereum address format
78
+ };
79
+ }
80
+ }
@@ -0,0 +1,20 @@
1
+ import { ServerSDKConfig, CreateWalletResult, Transaction, SignedTransaction } from "./types";
2
+ export interface SubmissionConfig {
3
+ chain: string;
4
+ network: string;
5
+ }
6
+ export { NetworkId, deriveSubmissionConfig, supportsTransactionSubmission, getNetworkDescription, getSupportedNetworkIds, getNetworkIdsByChain } from "./caip2-mappings";
7
+ export declare class ServerSDK {
8
+ private config;
9
+ private kmsApi;
10
+ private signingKeypair;
11
+ constructor(config: ServerSDKConfig);
12
+ createWallet(walletName?: string): Promise<CreateWalletResult>;
13
+ signAndSendTransaction(walletId: string, transaction: Transaction, networkId: string): Promise<SignedTransaction>;
14
+ getWalletAddresses(walletId: string, derivationPaths?: string[]): Promise<{
15
+ addressType: string;
16
+ address: string;
17
+ }[]>;
18
+ signMessage(walletId: string, message: string, networkId: string): Promise<string>;
19
+ }
20
+ export * from "./types";
package/dist/index.js ADDED
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.ServerSDK = exports.getNetworkIdsByChain = exports.getSupportedNetworkIds = exports.getNetworkDescription = exports.supportsTransactionSubmission = exports.deriveSubmissionConfig = exports.NetworkId = void 0;
21
+ const auth_1 = require("./auth");
22
+ const constants_1 = require("./constants");
23
+ const caip2_mappings_1 = require("./caip2-mappings");
24
+ const bs58_1 = __importDefault(require("bs58"));
25
+ const openapi_wallet_service_1 = require("@phantom/openapi-wallet-service");
26
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
27
+ // Export CAIP-2 utilities and enums
28
+ var caip2_mappings_2 = require("./caip2-mappings");
29
+ Object.defineProperty(exports, "NetworkId", { enumerable: true, get: function () { return caip2_mappings_2.NetworkId; } });
30
+ Object.defineProperty(exports, "deriveSubmissionConfig", { enumerable: true, get: function () { return caip2_mappings_2.deriveSubmissionConfig; } });
31
+ Object.defineProperty(exports, "supportsTransactionSubmission", { enumerable: true, get: function () { return caip2_mappings_2.supportsTransactionSubmission; } });
32
+ Object.defineProperty(exports, "getNetworkDescription", { enumerable: true, get: function () { return caip2_mappings_2.getNetworkDescription; } });
33
+ Object.defineProperty(exports, "getSupportedNetworkIds", { enumerable: true, get: function () { return caip2_mappings_2.getSupportedNetworkIds; } });
34
+ Object.defineProperty(exports, "getNetworkIdsByChain", { enumerable: true, get: function () { return caip2_mappings_2.getNetworkIdsByChain; } });
35
+ class ServerSDK {
36
+ constructor(config) {
37
+ this.config = config;
38
+ if (!config.organizationId || !config.apiBaseUrl) {
39
+ throw new Error("organizationId and apiBaseUrl are required");
40
+ }
41
+ // Decode the private key from base58
42
+ const privateKeyBytes = bs58_1.default.decode(config.apiPrivateKey);
43
+ this.signingKeypair = tweetnacl_1.default.sign.keyPair.fromSecretKey(privateKeyBytes);
44
+ // Create authenticated axios instance
45
+ const authenticatedAxios = (0, auth_1.createAuthenticatedAxiosInstance)(this.signingKeypair);
46
+ // Configure the KMS API client with authentication
47
+ const configuration = new openapi_wallet_service_1.Configuration({
48
+ basePath: config.apiBaseUrl,
49
+ });
50
+ // Pass the authenticated axios instance to the KMS API
51
+ this.kmsApi = new openapi_wallet_service_1.KMSRPCApi(configuration, config.apiBaseUrl, authenticatedAxios);
52
+ }
53
+ async createWallet(walletName) {
54
+ try {
55
+ // Create wallet request
56
+ const walletRequest = {
57
+ organizationId: this.config.organizationId,
58
+ walletName: walletName || `Wallet ${Date.now()}`,
59
+ accounts: [constants_1.DerivationPath.Solana, constants_1.DerivationPath.Ethereum, constants_1.DerivationPath.Bitcoin, constants_1.DerivationPath.Sui],
60
+ };
61
+ console.log("Creating wallet with request:", walletRequest);
62
+ const request = {
63
+ method: openapi_wallet_service_1.CreateWalletMethodEnum.createWallet,
64
+ params: walletRequest,
65
+ timestampMs: Date.now(),
66
+ };
67
+ const response = await this.kmsApi.postKmsRpc(request);
68
+ const walletResult = response.data.result;
69
+ console.log("Wallet created successfully:", walletResult);
70
+ // Fetch the accounts
71
+ const requestAccounts = {
72
+ method: openapi_wallet_service_1.GetAccountsMethodEnum.getAccounts,
73
+ params: {
74
+ accounts: [constants_1.DerivationPath.Solana, constants_1.DerivationPath.Ethereum, constants_1.DerivationPath.Bitcoin, constants_1.DerivationPath.Sui],
75
+ organizationId: this.config.organizationId,
76
+ walletId: walletResult.walletId,
77
+ },
78
+ timestampMs: Date.now(),
79
+ };
80
+ console.log("Fetching accounts for wallet:", walletResult.walletId);
81
+ const accountsResponse = await this.kmsApi.postKmsRpc(requestAccounts);
82
+ console.log("Accounts fetched successfully:", accountsResponse.data.result);
83
+ const accountsResult = accountsResponse.data.result;
84
+ return {
85
+ walletId: walletResult.walletId,
86
+ addresses: accountsResult.map(account => ({
87
+ addressType: account.addressFormat,
88
+ address: account.publicKey,
89
+ })),
90
+ };
91
+ }
92
+ catch (error) {
93
+ console.error("Failed to create wallet:", error.response?.data || error.message);
94
+ throw new Error(`Failed to create wallet: ${error.response?.data?.message || error.message}`);
95
+ }
96
+ }
97
+ async signAndSendTransaction(walletId, transaction, networkId) {
98
+ try {
99
+ // Encode the Uint8Array as a base64 string
100
+ const encodedTransaction = Buffer.from(transaction).toString('base64');
101
+ const submissionConfig = (0, caip2_mappings_1.deriveSubmissionConfig)(networkId);
102
+ // If we don't have a submission config, the transaction will only be signed, not submitted
103
+ if (!submissionConfig) {
104
+ console.warn(`No submission config available for network ${networkId}. Transaction will be signed but not submitted.`);
105
+ }
106
+ // For Solana transactions
107
+ if (networkId.startsWith("solana:")) {
108
+ // Get network configuration
109
+ const networkConfig = (0, constants_1.getNetworkConfig)(networkId);
110
+ const derivationInfo = {
111
+ derivationPath: networkConfig.derivationPath,
112
+ curve: networkConfig.curve,
113
+ addressFormat: networkConfig.addressFormat,
114
+ };
115
+ // Sign transaction request - only include submissionConfig if available
116
+ const signRequest = {
117
+ organizationId: this.config.organizationId,
118
+ walletId: walletId,
119
+ transaction: encodedTransaction,
120
+ derivationInfo: derivationInfo,
121
+ };
122
+ // Add submission config if available
123
+ if (submissionConfig) {
124
+ signRequest.submissionConfig = submissionConfig;
125
+ }
126
+ const request = {
127
+ method: openapi_wallet_service_1.SignTransactionMethodEnum.signTransaction,
128
+ params: signRequest,
129
+ timestampMs: Date.now(),
130
+ };
131
+ const response = await this.kmsApi.postKmsRpc(request);
132
+ const result = response.data.result;
133
+ return {
134
+ rawTransaction: result.transaction, // Base64 encoded signed transaction
135
+ };
136
+ }
137
+ else {
138
+ // For EVM chains (future implementation)
139
+ throw new Error("EVM transaction signing not yet implemented");
140
+ }
141
+ }
142
+ catch (error) {
143
+ console.error("Failed to sign and send transaction:", error.response?.data || error.message);
144
+ throw new Error(`Failed to sign and send transaction: ${error.response?.data?.message || error.message}`);
145
+ }
146
+ }
147
+ async getWalletAddresses(walletId, derivationPaths) {
148
+ try {
149
+ const paths = derivationPaths || [
150
+ constants_1.DerivationPath.Solana,
151
+ constants_1.DerivationPath.Ethereum,
152
+ constants_1.DerivationPath.Bitcoin,
153
+ constants_1.DerivationPath.Sui,
154
+ ];
155
+ const requestAccounts = {
156
+ method: openapi_wallet_service_1.GetAccountsMethodEnum.getAccounts,
157
+ params: {
158
+ accounts: paths,
159
+ organizationId: this.config.organizationId,
160
+ walletId: walletId,
161
+ },
162
+ timestampMs: Date.now(),
163
+ };
164
+ const accountsResponse = await this.kmsApi.postKmsRpc(requestAccounts);
165
+ const accountsResult = accountsResponse.data.result;
166
+ return accountsResult.map(account => ({
167
+ addressType: account.addressFormat,
168
+ address: account.publicKey,
169
+ }));
170
+ }
171
+ catch (error) {
172
+ console.error("Failed to get wallet addresses:", error.response?.data || error.message);
173
+ throw new Error(`Failed to get wallet addresses: ${error.response?.data?.message || error.message}`);
174
+ }
175
+ }
176
+ async signMessage(walletId, message, networkId) {
177
+ try {
178
+ // Convert message to byte array
179
+ const messageBytes = Array.from(Buffer.from(message, "utf8"));
180
+ // Get network configuration
181
+ const networkConfig = (0, constants_1.getNetworkConfig)(networkId);
182
+ const derivationInfo = {
183
+ derivationPath: networkConfig.derivationPath,
184
+ curve: networkConfig.curve,
185
+ addressFormat: networkConfig.addressFormat,
186
+ };
187
+ const signRequest = {
188
+ organizationId: this.config.organizationId,
189
+ walletId: walletId,
190
+ payload: messageBytes,
191
+ algorithm: networkConfig.algorithm,
192
+ derivationInfo: derivationInfo,
193
+ };
194
+ const request = {
195
+ method: openapi_wallet_service_1.SignRawPayloadMethodEnum.signRawPayload,
196
+ params: signRequest,
197
+ timestampMs: Date.now(),
198
+ };
199
+ const response = await this.kmsApi.postKmsRpc(request);
200
+ const result = response.data.result;
201
+ // Return the base64 encoded signature
202
+ return result.signature;
203
+ }
204
+ catch (error) {
205
+ console.error("Failed to sign message:", error.response?.data || error.message);
206
+ throw new Error(`Failed to sign message: ${error.response?.data?.message || error.message}`);
207
+ }
208
+ }
209
+ }
210
+ exports.ServerSDK = ServerSDK;
211
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,19 @@
1
+ import { DerivationInfoAddressFormatEnum } from "@phantom/openapi-wallet-service";
2
+ export interface ServerSDKConfig {
3
+ apiPrivateKey: string;
4
+ organizationId: string;
5
+ apiBaseUrl: string;
6
+ solanaRpcUrl?: string;
7
+ }
8
+ export interface WalletAddress {
9
+ addressType: DerivationInfoAddressFormatEnum;
10
+ address: string;
11
+ }
12
+ export interface CreateWalletResult {
13
+ walletId: string;
14
+ addresses: WalletAddress[];
15
+ }
16
+ export type Transaction = Uint8Array;
17
+ export interface SignedTransaction {
18
+ rawTransaction: string;
19
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@phantom/server-sdk",
3
+ "version": "0.0.2",
4
+ "description": "Server SDK for Phantom Wallet",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "dev": "tsc --watch",
10
+ "clean": "rm -rf dist",
11
+ "test": "jest",
12
+ "test:watch": "jest --watch"
13
+ },
14
+ "devDependencies": {
15
+ "@types/jest": "^29.5.12",
16
+ "@types/node": "^20.11.0",
17
+ "dotenv": "^16.4.1",
18
+ "jest": "^29.7.0",
19
+ "ts-jest": "^29.1.2",
20
+ "typescript": "^5.0.4"
21
+ },
22
+ "dependencies": {
23
+ "@phantom/openapi-wallet-service": "^0.1.5",
24
+ "axios": "^1.10.0",
25
+ "bs58": "^6.0.0",
26
+ "tweetnacl": "^1.0.3"
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ]
31
+ }