toss-expo-sdk 0.1.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 +20 -0
- package/README.md +292 -0
- package/lib/module/ble.js +103 -0
- package/lib/module/ble.js.map +1 -0
- package/lib/module/client/TossClient.js +324 -0
- package/lib/module/client/TossClient.js.map +1 -0
- package/lib/module/client/index.js +4 -0
- package/lib/module/client/index.js.map +1 -0
- package/lib/module/contexts/WalletContext.js +99 -0
- package/lib/module/contexts/WalletContext.js.map +1 -0
- package/lib/module/discovery.js +434 -0
- package/lib/module/discovery.js.map +1 -0
- package/lib/module/errors.js +47 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/examples/offlinePaymentFlow.js +234 -0
- package/lib/module/examples/offlinePaymentFlow.js.map +1 -0
- package/lib/module/index.js +32 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/intent.js +223 -0
- package/lib/module/intent.js.map +1 -0
- package/lib/module/intentManager.js +145 -0
- package/lib/module/intentManager.js.map +1 -0
- package/lib/module/internal/arciumHelper.js +50 -0
- package/lib/module/internal/arciumHelper.js.map +1 -0
- package/lib/module/nfc.js +54 -0
- package/lib/module/nfc.js.map +1 -0
- package/lib/module/noise.js +14 -0
- package/lib/module/noise.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/qr.js +57 -0
- package/lib/module/qr.js.map +1 -0
- package/lib/module/reconciliation.js +329 -0
- package/lib/module/reconciliation.js.map +1 -0
- package/lib/module/services/authService.js +205 -0
- package/lib/module/services/authService.js.map +1 -0
- package/lib/module/storage/secureStorage.js +89 -0
- package/lib/module/storage/secureStorage.js.map +1 -0
- package/lib/module/storage.js +16 -0
- package/lib/module/storage.js.map +1 -0
- package/lib/module/sync.js +64 -0
- package/lib/module/sync.js.map +1 -0
- package/lib/module/types/tossUser.js +41 -0
- package/lib/module/types/tossUser.js.map +1 -0
- package/lib/module/utils/nonceUtils.js +38 -0
- package/lib/module/utils/nonceUtils.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/__tests__/index.test.d.ts +1 -0
- package/lib/typescript/src/__tests__/index.test.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/reconciliation.test.d.ts +6 -0
- package/lib/typescript/src/__tests__/reconciliation.test.d.ts.map +1 -0
- package/lib/typescript/src/ble.d.ts +10 -0
- package/lib/typescript/src/ble.d.ts.map +1 -0
- package/lib/typescript/src/client/TossClient.d.ts +110 -0
- package/lib/typescript/src/client/TossClient.d.ts.map +1 -0
- package/lib/typescript/src/client/index.d.ts +3 -0
- package/lib/typescript/src/client/index.d.ts.map +1 -0
- package/lib/typescript/src/contexts/WalletContext.d.ts +20 -0
- package/lib/typescript/src/contexts/WalletContext.d.ts.map +1 -0
- package/lib/typescript/src/discovery.d.ts +188 -0
- package/lib/typescript/src/discovery.d.ts.map +1 -0
- package/lib/typescript/src/errors.d.ts +27 -0
- package/lib/typescript/src/errors.d.ts.map +1 -0
- package/lib/typescript/src/examples/offlinePaymentFlow.d.ts +48 -0
- package/lib/typescript/src/examples/offlinePaymentFlow.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +13 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/intent.d.ts +84 -0
- package/lib/typescript/src/intent.d.ts.map +1 -0
- package/lib/typescript/src/intentManager.d.ts +46 -0
- package/lib/typescript/src/intentManager.d.ts.map +1 -0
- package/lib/typescript/src/internal/arciumHelper.d.ts +19 -0
- package/lib/typescript/src/internal/arciumHelper.d.ts.map +1 -0
- package/lib/typescript/src/nfc.d.ts +7 -0
- package/lib/typescript/src/nfc.d.ts.map +1 -0
- package/lib/typescript/src/noise.d.ts +5 -0
- package/lib/typescript/src/noise.d.ts.map +1 -0
- package/lib/typescript/src/qr.d.ts +6 -0
- package/lib/typescript/src/qr.d.ts.map +1 -0
- package/lib/typescript/src/reconciliation.d.ts +65 -0
- package/lib/typescript/src/reconciliation.d.ts.map +1 -0
- package/lib/typescript/src/services/authService.d.ts +55 -0
- package/lib/typescript/src/services/authService.d.ts.map +1 -0
- package/lib/typescript/src/storage/secureStorage.d.ts +7 -0
- package/lib/typescript/src/storage/secureStorage.d.ts.map +1 -0
- package/lib/typescript/src/storage.d.ts +4 -0
- package/lib/typescript/src/storage.d.ts.map +1 -0
- package/lib/typescript/src/sync.d.ts +40 -0
- package/lib/typescript/src/sync.d.ts.map +1 -0
- package/lib/typescript/src/types/tossUser.d.ts +39 -0
- package/lib/typescript/src/types/tossUser.d.ts.map +1 -0
- package/lib/typescript/src/utils/nonceUtils.d.ts +8 -0
- package/lib/typescript/src/utils/nonceUtils.d.ts.map +1 -0
- package/package.json +176 -0
- package/src/__tests__/index.test.tsx +1 -0
- package/src/__tests__/reconciliation.test.tsx +361 -0
- package/src/ble.ts +138 -0
- package/src/client/TossClient.ts +435 -0
- package/src/client/index.ts +2 -0
- package/src/contexts/WalletContext.tsx +127 -0
- package/src/discovery.ts +542 -0
- package/src/errors.ts +51 -0
- package/src/examples/offlinePaymentFlow.ts +331 -0
- package/src/index.tsx +61 -0
- package/src/intent.ts +328 -0
- package/src/intentManager.ts +164 -0
- package/src/internal/arciumHelper.ts +58 -0
- package/src/nfc.ts +57 -0
- package/src/noise.ts +9 -0
- package/src/qr.tsx +65 -0
- package/src/reconciliation.ts +421 -0
- package/src/services/authService.ts +238 -0
- package/src/storage/secureStorage.ts +100 -0
- package/src/storage.ts +17 -0
- package/src/sync.ts +101 -0
- package/src/types/tossUser.ts +81 -0
- package/src/utils/nonceUtils.ts +56 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as SecureStore from 'expo-secure-store';
|
|
2
|
+
import { StorageError } from '../errors';
|
|
3
|
+
import type { SolanaIntent } from '../intent';
|
|
4
|
+
|
|
5
|
+
const STORAGE_PREFIX = 'toss_intent_';
|
|
6
|
+
|
|
7
|
+
// Helper function to get all keys
|
|
8
|
+
async function getAllKeys(): Promise<string[]> {
|
|
9
|
+
// expo-secure-store doesn't have a direct way to get all keys,
|
|
10
|
+
// so we'll need to track them manually
|
|
11
|
+
const keys = await SecureStore.getItemAsync(`${STORAGE_PREFIX}_keys`);
|
|
12
|
+
return keys ? JSON.parse(keys) : [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Helper function to save all keys
|
|
16
|
+
async function saveKeys(keys: string[]): Promise<void> {
|
|
17
|
+
await SecureStore.setItemAsync(
|
|
18
|
+
`${STORAGE_PREFIX}_keys`,
|
|
19
|
+
JSON.stringify(keys)
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function secureStoreIntent(intent: SolanaIntent): Promise<void> {
|
|
24
|
+
try {
|
|
25
|
+
const key = `${STORAGE_PREFIX}${intent.id}`;
|
|
26
|
+
await SecureStore.setItemAsync(key, JSON.stringify(intent));
|
|
27
|
+
|
|
28
|
+
// Update the keys list
|
|
29
|
+
const keys = await getAllKeys();
|
|
30
|
+
if (!keys.includes(key)) {
|
|
31
|
+
keys.push(key);
|
|
32
|
+
await saveKeys(keys);
|
|
33
|
+
}
|
|
34
|
+
} catch (error) {
|
|
35
|
+
throw new StorageError('Failed to store intent securely', {
|
|
36
|
+
cause: error,
|
|
37
|
+
intentId: intent.id,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function getSecureIntent(
|
|
43
|
+
intentId: string
|
|
44
|
+
): Promise<SolanaIntent | null> {
|
|
45
|
+
try {
|
|
46
|
+
const value = await SecureStore.getItemAsync(
|
|
47
|
+
`${STORAGE_PREFIX}${intentId}`
|
|
48
|
+
);
|
|
49
|
+
return value ? JSON.parse(value) : null;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new StorageError('Failed to retrieve intent', {
|
|
52
|
+
cause: error,
|
|
53
|
+
intentId,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function getAllSecureIntents(): Promise<SolanaIntent[]> {
|
|
59
|
+
try {
|
|
60
|
+
const keys = await getAllKeys();
|
|
61
|
+
const intents = await Promise.all(
|
|
62
|
+
keys.map(async (key: string) => {
|
|
63
|
+
const value = await SecureStore.getItemAsync(key);
|
|
64
|
+
return value ? JSON.parse(value) : null;
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
return intents.filter(Boolean);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
throw new StorageError('Failed to retrieve all intents', { cause: error });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function removeSecureIntent(intentId: string): Promise<void> {
|
|
74
|
+
try {
|
|
75
|
+
const key = `${STORAGE_PREFIX}${intentId}`;
|
|
76
|
+
await SecureStore.deleteItemAsync(key);
|
|
77
|
+
|
|
78
|
+
// Update the keys list
|
|
79
|
+
const keys = await getAllKeys();
|
|
80
|
+
const updatedKeys = keys.filter(k => k !== key);
|
|
81
|
+
await saveKeys(updatedKeys);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
throw new StorageError('Failed to remove intent', {
|
|
84
|
+
cause: error,
|
|
85
|
+
intentId,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function clearAllSecureIntents(): Promise<void> {
|
|
91
|
+
try {
|
|
92
|
+
const keys = await getAllKeys();
|
|
93
|
+
await Promise.all(
|
|
94
|
+
keys.map((key: string) => SecureStore.deleteItemAsync(key))
|
|
95
|
+
);
|
|
96
|
+
await saveKeys([]);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw new StorageError('Failed to clear all intents', { cause: error });
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
2
|
+
|
|
3
|
+
const INTENTS_KEY = "TOSS_PENDING_INTENTS";
|
|
4
|
+
|
|
5
|
+
export async function storePendingIntent(intent: any) {
|
|
6
|
+
const current = JSON.parse((await AsyncStorage.getItem(INTENTS_KEY)) || "[]");
|
|
7
|
+
current.push(intent);
|
|
8
|
+
await AsyncStorage.setItem(INTENTS_KEY, JSON.stringify(current));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function getPendingIntents() {
|
|
12
|
+
return JSON.parse((await AsyncStorage.getItem(INTENTS_KEY)) || "[]");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function clearPendingIntents() {
|
|
16
|
+
await AsyncStorage.removeItem(INTENTS_KEY);
|
|
17
|
+
}
|
package/src/sync.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronisation with Solana Blockchain
|
|
3
|
+
*
|
|
4
|
+
* Implements Section 9 of the TOSS Technical Paper:
|
|
5
|
+
* Upon regaining connectivity, devices initiate reconciliation with onchain state.
|
|
6
|
+
* All offline artifacts are verified onchain and settled with deterministic outcomes.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
10
|
+
import {
|
|
11
|
+
reconcilePendingIntents,
|
|
12
|
+
detectConflicts,
|
|
13
|
+
getReconciliationState,
|
|
14
|
+
type SettlementResult,
|
|
15
|
+
type ReconciliationState,
|
|
16
|
+
} from './reconciliation';
|
|
17
|
+
import { NetworkError } from './errors';
|
|
18
|
+
|
|
19
|
+
export interface SyncResult {
|
|
20
|
+
// Intents that were successfully settled onchain
|
|
21
|
+
successfulSettlements: SettlementResult[];
|
|
22
|
+
// Intents that were rejected or failed
|
|
23
|
+
failedSettlements: SettlementResult[];
|
|
24
|
+
// Conflicts detected during reconciliation
|
|
25
|
+
detectedConflicts: { intentId: string; conflict: string }[];
|
|
26
|
+
// Overall reconciliation state
|
|
27
|
+
reconciliationState: ReconciliationState;
|
|
28
|
+
// Timestamp of sync
|
|
29
|
+
syncTimestamp: number;
|
|
30
|
+
// Whether sync was successful (all intents processed)
|
|
31
|
+
isComplete: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Full sync and reconciliation with the Solana blockchain
|
|
36
|
+
*
|
|
37
|
+
* This is the primary function for TOSS settlement. When a device regains
|
|
38
|
+
* connectivity, it calls this to:
|
|
39
|
+
* 1. Detect any conflicts with onchain state
|
|
40
|
+
* 2. Settle all pending intents
|
|
41
|
+
* 3. Update local state with results
|
|
42
|
+
*
|
|
43
|
+
* @param connection Connection to Solana RPC
|
|
44
|
+
* @param feePayer Optional fee payer keypair public key
|
|
45
|
+
* @returns Detailed sync results including conflicts and settlements
|
|
46
|
+
*/
|
|
47
|
+
export async function syncToChain(
|
|
48
|
+
connection: Connection,
|
|
49
|
+
feePayer?: PublicKey
|
|
50
|
+
): Promise<SyncResult> {
|
|
51
|
+
const syncTimestamp = Math.floor(Date.now() / 1000);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Step 1: Detect any conflicts with onchain state
|
|
55
|
+
const detectedConflicts = await detectConflicts(connection);
|
|
56
|
+
|
|
57
|
+
// Step 2: Reconcile and settle all pending intents
|
|
58
|
+
const allSettlementResults = await reconcilePendingIntents(
|
|
59
|
+
connection,
|
|
60
|
+
feePayer
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Step 3: Separate successful and failed settlements
|
|
64
|
+
const successfulSettlements = allSettlementResults.filter(
|
|
65
|
+
(r) => r.status === 'success'
|
|
66
|
+
);
|
|
67
|
+
const failedSettlements = allSettlementResults.filter(
|
|
68
|
+
(r) => r.status !== 'success'
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Step 4: Get final reconciliation state
|
|
72
|
+
const reconciliationState = await getReconciliationState(connection);
|
|
73
|
+
|
|
74
|
+
const isComplete =
|
|
75
|
+
failedSettlements.length === 0 && detectedConflicts.length === 0;
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
successfulSettlements,
|
|
79
|
+
failedSettlements,
|
|
80
|
+
detectedConflicts,
|
|
81
|
+
reconciliationState,
|
|
82
|
+
syncTimestamp,
|
|
83
|
+
isComplete,
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
throw new NetworkError(
|
|
87
|
+
`Sync to chain failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
88
|
+
{ cause: error }
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Lightweight sync to check status without settling
|
|
95
|
+
* Useful for monitoring or UI updates without committing to settlements
|
|
96
|
+
*/
|
|
97
|
+
export async function checkSyncStatus(
|
|
98
|
+
connection: Connection
|
|
99
|
+
): Promise<ReconciliationState> {
|
|
100
|
+
return getReconciliationState(connection);
|
|
101
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a TOSS wallet user in the ecosystem
|
|
5
|
+
*/
|
|
6
|
+
export type TossUser = {
|
|
7
|
+
// Core Identity
|
|
8
|
+
userId: string; // TOSS internal ID (e.g., 'toss_123')
|
|
9
|
+
username: string; // @handle format (e.g., '@alice')
|
|
10
|
+
displayName?: string; // Optional display name
|
|
11
|
+
|
|
12
|
+
// TOSS Wallet
|
|
13
|
+
wallet: {
|
|
14
|
+
publicKey: PublicKey; // Main wallet address
|
|
15
|
+
isVerified: boolean; // KYC/verification status
|
|
16
|
+
createdAt: string; // ISO timestamp
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Device & Session
|
|
20
|
+
device: {
|
|
21
|
+
id: string; // Unique device ID
|
|
22
|
+
name?: string; // User-defined device name
|
|
23
|
+
lastActive: string; // ISO timestamp
|
|
24
|
+
client: 'mobile' | 'web' | 'desktop';
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Status
|
|
28
|
+
status: 'active' | 'inactive' | 'restricted';
|
|
29
|
+
lastSeen: string; // ISO timestamp
|
|
30
|
+
|
|
31
|
+
// TOSS-specific
|
|
32
|
+
tossFeatures: {
|
|
33
|
+
canSend: boolean;
|
|
34
|
+
canReceive: boolean;
|
|
35
|
+
isPrivateTxEnabled: boolean;
|
|
36
|
+
maxTransactionAmount: number; // In lamports
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Timestamps
|
|
40
|
+
createdAt: string;
|
|
41
|
+
updatedAt: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Minimal user info for transaction context
|
|
46
|
+
*/
|
|
47
|
+
export type TossUserContext = Pick<
|
|
48
|
+
TossUser,
|
|
49
|
+
'userId' | 'username' | 'wallet' | 'status'
|
|
50
|
+
> & {
|
|
51
|
+
deviceId: string;
|
|
52
|
+
sessionId: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Example usage
|
|
56
|
+
export const exampleTossUser: TossUser = {
|
|
57
|
+
userId: 'toss_abc123',
|
|
58
|
+
username: '@alice',
|
|
59
|
+
displayName: 'Alice',
|
|
60
|
+
wallet: {
|
|
61
|
+
publicKey: new PublicKey('11111111111111111111111111111111'), // Example key
|
|
62
|
+
isVerified: true,
|
|
63
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
64
|
+
},
|
|
65
|
+
device: {
|
|
66
|
+
id: 'dev_xyz789',
|
|
67
|
+
name: 'Alice iPhone',
|
|
68
|
+
lastActive: new Date().toISOString(),
|
|
69
|
+
client: 'mobile',
|
|
70
|
+
},
|
|
71
|
+
status: 'active',
|
|
72
|
+
lastSeen: new Date().toISOString(),
|
|
73
|
+
tossFeatures: {
|
|
74
|
+
canSend: true,
|
|
75
|
+
canReceive: true,
|
|
76
|
+
isPrivateTxEnabled: true,
|
|
77
|
+
maxTransactionAmount: 1000000000, // 1 SOL in lamports
|
|
78
|
+
},
|
|
79
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
80
|
+
updatedAt: new Date().toISOString(),
|
|
81
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SystemProgram,
|
|
3
|
+
PublicKey,
|
|
4
|
+
Transaction,
|
|
5
|
+
Connection,
|
|
6
|
+
Keypair,
|
|
7
|
+
LAMPORTS_PER_SOL,
|
|
8
|
+
} from '@solana/web3.js';
|
|
9
|
+
|
|
10
|
+
export async function createNonceAccount(
|
|
11
|
+
connection: Connection,
|
|
12
|
+
feePayer: Keypair,
|
|
13
|
+
nonceAccount: Keypair = Keypair.generate(),
|
|
14
|
+
amount = 1 * LAMPORTS_PER_SOL // 1 SOL should be enough for many transactions
|
|
15
|
+
): Promise<{ nonceAccount: Keypair; nonceAuth: PublicKey }> {
|
|
16
|
+
const nonceAuth = feePayer.publicKey;
|
|
17
|
+
const tx = new Transaction().add(
|
|
18
|
+
SystemProgram.createAccount({
|
|
19
|
+
fromPubkey: feePayer.publicKey,
|
|
20
|
+
newAccountPubkey: nonceAccount.publicKey,
|
|
21
|
+
lamports: amount,
|
|
22
|
+
space: 80, // Size of nonce account
|
|
23
|
+
programId: SystemProgram.programId,
|
|
24
|
+
}),
|
|
25
|
+
SystemProgram.nonceInitialize({
|
|
26
|
+
noncePubkey: nonceAccount.publicKey,
|
|
27
|
+
authorizedPubkey: nonceAuth,
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
|
|
32
|
+
tx.feePayer = feePayer.publicKey;
|
|
33
|
+
tx.sign(feePayer, nonceAccount);
|
|
34
|
+
|
|
35
|
+
await connection.sendRawTransaction(tx.serialize());
|
|
36
|
+
return { nonceAccount, nonceAuth };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function getNonce(
|
|
40
|
+
connection: Connection,
|
|
41
|
+
nonceAccount: PublicKey
|
|
42
|
+
): Promise<string> {
|
|
43
|
+
const accountInfo = await connection.getAccountInfo(nonceAccount);
|
|
44
|
+
if (!accountInfo) throw new Error('Nonce account not found');
|
|
45
|
+
return accountInfo.data.slice(32, 64).toString('hex');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createNonceAdvanceInstruction(
|
|
49
|
+
noncePubkey: PublicKey,
|
|
50
|
+
authorizedPubkey: PublicKey
|
|
51
|
+
) {
|
|
52
|
+
return SystemProgram.nonceAdvance({
|
|
53
|
+
noncePubkey,
|
|
54
|
+
authorizedPubkey,
|
|
55
|
+
});
|
|
56
|
+
}
|