emblem-vault-sdk 2.3.6 → 3.0.0-experimental
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/.traces/blockchain-provider-abstraction-plan.md +302 -0
- package/.traces/notes.md +43 -0
- package/.traces/readme-verification-trace.md +988 -0
- package/.traces/test-migration-status.md +227 -0
- package/.traces/tests-consolidated-trace.md +667 -0
- package/dist/abi/abi.json +53 -0
- package/dist/bundle.js +21602 -17419
- package/dist/clients/emblemVaultSolanaWalletClient.d.ts +74 -0
- package/dist/clients/emblemVaultSolanaWalletClient.js +149 -0
- package/dist/clients/emblemVaultSolanaWalletClient.js.map +1 -0
- package/dist/clients/emblemVaultWalletClient.d.ts +52 -0
- package/dist/clients/emblemVaultWalletClient.js +110 -0
- package/dist/clients/emblemVaultWalletClient.js.map +1 -0
- package/dist/derive.js +7 -0
- package/dist/derive.js.map +1 -0
- package/dist/index.js +319 -114
- package/dist/index.js.map +1 -0
- package/dist/providers/ProviderManager.d.ts +57 -0
- package/dist/providers/ProviderManager.js +283 -0
- package/dist/providers/ProviderManager.js.map +1 -0
- package/dist/providers.d.ts +101 -0
- package/dist/providers.js +96 -0
- package/dist/providers.js.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.js +61 -58
- package/dist/utils.js.map +1 -0
- package/docs/bundle.js +21602 -17419
- package/docs/index.html +150 -13
- package/docs/local.html +385 -0
- package/docs/steps.html +420 -53
- package/package.json +22 -13
- package/readme.md +795 -21
- package/src/abi/abi.json +54 -1
- package/src/clients/emblemVaultSolanaWalletClient.ts +257 -0
- package/src/clients/emblemVaultWalletClient.ts +159 -0
- package/src/derive.ts +5 -5
- package/src/index.ts +320 -102
- package/src/providers/ProviderManager.ts +254 -0
- package/src/providers.ts +163 -0
- package/src/types.ts +50 -0
- package/src/utils.ts +63 -62
- package/test/.mocharc.js +8 -0
- package/test/README.md +212 -0
- package/test/fixtures/ethscriptions/balance-with-native-first.json +24 -0
- package/test/fixtures/ethscriptions/balance-with-native.json +23 -0
- package/test/fixtures/ethscriptions/balance.json +18 -0
- package/test/helpers/sdkLoader.js +88 -0
- package/test/helpers/setup.js +55 -0
- package/test/integration/ApiOperations.spec.js +102 -0
- package/test/integration/VaultAI.spec.js +57 -0
- package/test/integration/VaultCreation.spec.js +95 -0
- package/test/mocks.js +127 -0
- package/test/tsconfig.json +25 -0
- package/test/unit/AllowedBells.spec.js +53 -0
- package/test/unit/AllowedBitcoinDeGods.spec.js +53 -0
- package/test/unit/AllowedBitcoinOrdinals.spec.js +46 -0
- package/test/unit/AllowedCounterparty.spec.js +66 -0
- package/test/unit/AllowedCursedOrdinals.spec.js +68 -0
- package/test/unit/AllowedEmbells.spec.js +11 -0
- package/test/unit/AllowedEmbels.spec.js +11 -0
- package/test/unit/AllowedEmblemOpen.spec.js +20 -0
- package/test/unit/AllowedEthscriptions.spec.js +53 -0
- package/test/unit/AllowedHardcodedNfts.spec.js +77 -0
- package/test/unit/AllowedNamecoin.spec.js +33 -0
- package/test/unit/AllowedOrdi.spec.js +46 -0
- package/test/unit/AllowedOxbt.spec.js +46 -0
- package/test/unit/AllowedProjectCollection.spec.js +51 -0
- package/test/unit/AllowedProtocolCollection.spec.js +44 -0
- package/test/unit/AllowedStamps.spec.js +78 -0
- package/test/unit/DarkfarmsMetadata.spec.js +10 -0
- package/test/unit/EmblemVaultSdk.spec.js +188 -0
- package/test/unit/Providers.spec.js +290 -0
- package/test/unit/ResourceMonitor.spec.js +111 -0
- package/test/unit/SDKMemoryLeaks.spec.js +176 -0
- package/test/unit/Signing.spec.js +321 -0
- package/test/unit/VaultAI.spec.js +140 -0
- package/test/unit/clients/EmblemVaultSolanaWalletClient.spec.js +296 -0
- package/test/unit/clients/EmblemVaultWalletClient.spec.js +246 -0
- package/test/utils/ResourceMonitor.js +169 -0
- package/test/windsurf-rules.md +68 -0
- package/tsconfig.json +7 -3
- package/types/derive.d.ts +0 -5
- package/types/index.d.ts +152 -32
- package/types/types.d.ts +43 -0
- package/types/utils.d.ts +7 -1
- package/dist/abi/quote.js +0 -29
- package/dist/abi/quote.json +0 -26
- package/jest.config.js +0 -6
- package/tests/AllowedBells.test.ts +0 -53
- package/tests/AllowedBitcoinDeGods.test.ts +0 -53
- package/tests/AllowedBitcoinOrdinals.test.ts +0 -46
- package/tests/AllowedCounterparty.test.ts +0 -45
- package/tests/AllowedCursedOrdinals.test.ts +0 -68
- package/tests/AllowedEmbells.test.ts +0 -12
- package/tests/AllowedEmbels.test.ts +0 -16
- package/tests/AllowedEmblemOpen.test.ts +0 -20
- package/tests/AllowedEthscriptions.test.ts +0 -39
- package/tests/AllowedHardcodedNfts.test.ts +0 -78
- package/tests/AllowedNamecoin.test.ts +0 -33
- package/tests/AllowedOrdi.test.ts +0 -47
- package/tests/AllowedOxbt.test.ts +0 -47
- package/tests/AllowedProjectlCollection.test.ts +0 -51
- package/tests/AllowedProtocolCollection.test.ts +0 -44
- package/tests/AllowedStamps.test.ts +0 -73
- package/tests/DarkfarmsMetadata.test.ts +0 -10
- package/tests/EmblemVaultSdk.test.ts +0 -124
- package/tests/fixtures/embels/balance.json +0 -10
- package/tests/fixtures/ethscriptions/balance-with-native-first.json +0 -69
- package/tests/fixtures/ethscriptions/balance-with-native.json +0 -37
- package/tests/fixtures/ethscriptions/balance.json +0 -64
- /package/{tests → test}/fixtures/bells/balance-with-non-bell-first.json +0 -0
- /package/{tests → test}/fixtures/bells/balance-with-non-bell.json +0 -0
- /package/{tests → test}/fixtures/bells/balance.json +0 -0
- /package/{tests → test}/fixtures/bitcoin-degods/balance-with-non-degods-first.json +0 -0
- /package/{tests → test}/fixtures/bitcoin-degods/balance-with-non-degods.json +0 -0
- /package/{tests → test}/fixtures/bitcoin-degods/balance.json +0 -0
- /package/{tests → test}/fixtures/bitcoin-ordinals/balance-with-native-first.json +0 -0
- /package/{tests → test}/fixtures/bitcoin-ordinals/balance-with-only-native.json +0 -0
- /package/{tests → test}/fixtures/bitcoin-ordinals/balance.json +0 -0
- /package/{tests → test}/fixtures/counterparty/balance-with-multiple.json +0 -0
- /package/{tests → test}/fixtures/counterparty/balance.json +0 -0
- /package/{tests → test}/fixtures/cursed-ordinals/balance-with-native-first.json +0 -0
- /package/{tests → test}/fixtures/cursed-ordinals/balance-with-native.json +0 -0
- /package/{tests → test}/fixtures/cursed-ordinals/balance.json +0 -0
- /package/{tests → test}/fixtures/dogeparty/balance-with-non-dogeparty-first.json +0 -0
- /package/{tests → test}/fixtures/dogeparty/balance-with-non-dogeparty.json +0 -0
- /package/{tests → test}/fixtures/dogeparty/balance.json +0 -0
- /package/{tests → test}/fixtures/emblem-open/balance.json +0 -0
- /package/{tests → test}/fixtures/hardcoded-nfts/balance-witn-non-hardcoded-first.json +0 -0
- /package/{tests → test}/fixtures/hardcoded-nfts/balance-witn-non-hardcoded.json +0 -0
- /package/{tests → test}/fixtures/hardcoded-nfts/balance.json +0 -0
- /package/{tests → test}/fixtures/megapunks/balance-with-non-megapunk-first.json +0 -0
- /package/{tests → test}/fixtures/megapunks/balance-with-non-megapunk.json +0 -0
- /package/{tests → test}/fixtures/megapunks/balance.json +0 -0
- /package/{tests → test}/fixtures/namecoin/balance-with-native-first.json +0 -0
- /package/{tests → test}/fixtures/namecoin/balance-with-native.json +0 -0
- /package/{tests → test}/fixtures/namecoin/balance.json +0 -0
- /package/{tests → test}/fixtures/ordi/balance-with-native-first.json +0 -0
- /package/{tests → test}/fixtures/ordi/balance-with-native.json +0 -0
- /package/{tests → test}/fixtures/ordi/balance.json +0 -0
- /package/{tests → test}/fixtures/oxbt/balance-with-native-first.json +0 -0
- /package/{tests → test}/fixtures/oxbt/balance-with-native.json +0 -0
- /package/{tests → test}/fixtures/oxbt/balance.json +0 -0
- /package/{tests → test}/fixtures/stamps/balance-with-non-stamps-first.json +0 -0
- /package/{tests → test}/fixtures/stamps/balance-with-non-stamps.json +0 -0
- /package/{tests → test}/fixtures/stamps/balance.json +0 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
3
|
+
const { EmblemVaultSDK } = require('../../../dist/index.js');
|
|
4
|
+
const { expect } = require('chai');
|
|
5
|
+
const sinon = require('sinon');
|
|
6
|
+
const { createEmblemVaultSolanaWalletClient } = require('../../../dist/clients/emblemVaultSolanaWalletClient.js');
|
|
7
|
+
const {
|
|
8
|
+
Transaction,
|
|
9
|
+
VersionedTransaction,
|
|
10
|
+
PublicKey,
|
|
11
|
+
Connection,
|
|
12
|
+
Keypair,
|
|
13
|
+
SystemProgram,
|
|
14
|
+
LAMPORTS_PER_SOL,
|
|
15
|
+
MessageV0
|
|
16
|
+
} = require('@solana/web3.js');
|
|
17
|
+
|
|
18
|
+
// Mock SDK
|
|
19
|
+
const mockApiKey = 'mock-api-key';
|
|
20
|
+
class MockEmblemVaultSDK extends EmblemVaultSDK {
|
|
21
|
+
constructor(apiKey) {
|
|
22
|
+
super(apiKey);
|
|
23
|
+
// Override methods if necessary for testing setup
|
|
24
|
+
}
|
|
25
|
+
// Mock any methods needed by the client creation or its methods, if they are called internally
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe('EmblemVaultSolanaWalletClient', () => {
|
|
29
|
+
let sdk;
|
|
30
|
+
let walletClient;
|
|
31
|
+
let mockConnection;
|
|
32
|
+
const testWalletId = 'test-solana-wallet-001';
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
sdk = new MockEmblemVaultSDK(mockApiKey);
|
|
36
|
+
mockConnection = new Connection('http://localhost:8899', 'confirmed');
|
|
37
|
+
walletClient = createEmblemVaultSolanaWalletClient({
|
|
38
|
+
sdk: sdk,
|
|
39
|
+
walletId: testWalletId,
|
|
40
|
+
connection: mockConnection
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
// Restore sinon spies/stubs after each test
|
|
46
|
+
sinon.restore();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should create a client instance', () => {
|
|
50
|
+
expect(walletClient).to.exist;
|
|
51
|
+
expect(walletClient.type).to.equal('emblemVaultSolanaWalletClient');
|
|
52
|
+
expect(walletClient.walletId).to.equal(testWalletId);
|
|
53
|
+
expect(walletClient.sdk).to.equal(sdk);
|
|
54
|
+
expect(walletClient.connection).to.equal(mockConnection);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should have the expected methods', () => {
|
|
58
|
+
expect(walletClient.getPublicKey).to.be.a('function');
|
|
59
|
+
expect(walletClient.signMessage).to.be.a('function');
|
|
60
|
+
expect(walletClient.signTransaction).to.be.a('function');
|
|
61
|
+
expect(walletClient.signVersionedTransaction).to.be.a('function');
|
|
62
|
+
expect(walletClient.sendTransaction).to.be.a('function');
|
|
63
|
+
expect(walletClient.sendVersionedTransaction).to.be.a('function');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('getPublicKey', () => {
|
|
67
|
+
it('should return a PublicKey instance', async () => {
|
|
68
|
+
const publicKey = await walletClient.getPublicKey();
|
|
69
|
+
expect(publicKey).to.be.instanceOf(PublicKey);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should cache the public key after first retrieval', async () => {
|
|
73
|
+
// First call should set the cached public key
|
|
74
|
+
const publicKey1 = await walletClient.getPublicKey();
|
|
75
|
+
expect(walletClient.publicKey).to.equal(publicKey1);
|
|
76
|
+
|
|
77
|
+
// Spy on the getPublicKey method
|
|
78
|
+
const getPublicKeySpy = sinon.spy(walletClient, 'getPublicKey');
|
|
79
|
+
|
|
80
|
+
// Second call should return the same public key
|
|
81
|
+
const publicKey2 = await walletClient.getPublicKey();
|
|
82
|
+
expect(publicKey2).to.deep.equal(publicKey1);
|
|
83
|
+
|
|
84
|
+
// Verify the method was called
|
|
85
|
+
expect(getPublicKeySpy.calledOnce).to.be.true;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should use provided public key if available', async () => {
|
|
89
|
+
const providedPublicKey = new PublicKey('11111111111111111111111111111111');
|
|
90
|
+
const clientWithPublicKey = createEmblemVaultSolanaWalletClient({
|
|
91
|
+
sdk: sdk,
|
|
92
|
+
walletId: testWalletId,
|
|
93
|
+
publicKey: providedPublicKey
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const publicKey = await clientWithPublicKey.getPublicKey();
|
|
97
|
+
expect(publicKey).to.deep.equal(providedPublicKey);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('signMessage', () => {
|
|
102
|
+
it('should sign a string message', async () => {
|
|
103
|
+
const message = 'Hello, Solana!';
|
|
104
|
+
const signature = await walletClient.signMessage(message);
|
|
105
|
+
|
|
106
|
+
expect(signature).to.be.a('string');
|
|
107
|
+
// Base64 encoded signature
|
|
108
|
+
expect(signature).to.match(/^[A-Za-z0-9+/=]+$/);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should sign a Uint8Array message', async () => {
|
|
112
|
+
const message = new TextEncoder().encode('Hello, Solana!');
|
|
113
|
+
const signature = await walletClient.signMessage(message);
|
|
114
|
+
|
|
115
|
+
expect(signature).to.be.a('string');
|
|
116
|
+
// Base64 encoded signature
|
|
117
|
+
expect(signature).to.match(/^[A-Za-z0-9+/=]+$/);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should produce different signatures for different messages', async () => {
|
|
121
|
+
const message1 = 'Hello, Solana!';
|
|
122
|
+
const message2 = 'Different message';
|
|
123
|
+
|
|
124
|
+
const signature1 = await walletClient.signMessage(message1);
|
|
125
|
+
const signature2 = await walletClient.signMessage(message2);
|
|
126
|
+
|
|
127
|
+
// They should be different
|
|
128
|
+
expect(signature1).to.not.equal(signature2);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('signTransaction', () => {
|
|
133
|
+
it('should sign a transaction', async () => {
|
|
134
|
+
// Get the public key first
|
|
135
|
+
const publicKey = await walletClient.getPublicKey();
|
|
136
|
+
|
|
137
|
+
// Create a simple transaction
|
|
138
|
+
const transaction = new Transaction().add(
|
|
139
|
+
SystemProgram.transfer({
|
|
140
|
+
fromPubkey: publicKey,
|
|
141
|
+
toPubkey: new PublicKey('11111111111111111111111111111111'),
|
|
142
|
+
lamports: LAMPORTS_PER_SOL * 0.01
|
|
143
|
+
})
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// Set recent blockhash
|
|
147
|
+
transaction.recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k';
|
|
148
|
+
transaction.feePayer = publicKey;
|
|
149
|
+
|
|
150
|
+
// Sign the transaction
|
|
151
|
+
const signedTx = await walletClient.signTransaction(transaction);
|
|
152
|
+
|
|
153
|
+
// Verify the transaction has signatures
|
|
154
|
+
expect(signedTx.signatures.length).to.be.greaterThan(0);
|
|
155
|
+
expect(signedTx.signatures[0].publicKey.toBase58()).to.equal(publicKey.toBase58());
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should get the public key if not already cached', async () => {
|
|
159
|
+
// Create a client without a public key
|
|
160
|
+
const newClient = createEmblemVaultSolanaWalletClient({
|
|
161
|
+
sdk: sdk,
|
|
162
|
+
walletId: testWalletId,
|
|
163
|
+
connection: mockConnection
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Spy on the getPublicKey method
|
|
167
|
+
const getPublicKeySpy = sinon.spy(newClient, 'getPublicKey');
|
|
168
|
+
|
|
169
|
+
// Create a simple transaction
|
|
170
|
+
const transaction = new Transaction();
|
|
171
|
+
|
|
172
|
+
// Sign the transaction - this should call getPublicKey internally
|
|
173
|
+
await newClient.signTransaction(transaction);
|
|
174
|
+
|
|
175
|
+
// Verify getPublicKey was called
|
|
176
|
+
expect(getPublicKeySpy.calledOnce).to.be.true;
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('signVersionedTransaction', () => {
|
|
181
|
+
it('should sign a versioned transaction', async () => {
|
|
182
|
+
// Get the public key first
|
|
183
|
+
const publicKey = await walletClient.getPublicKey();
|
|
184
|
+
|
|
185
|
+
// Create a mock versioned transaction
|
|
186
|
+
const mockVersionedTransaction = {
|
|
187
|
+
message: {
|
|
188
|
+
serialize: () => Buffer.from('mock-serialized-message')
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Sign the transaction
|
|
193
|
+
const signedTx = await walletClient.signVersionedTransaction(mockVersionedTransaction);
|
|
194
|
+
|
|
195
|
+
// In our mock implementation, we're just returning the original transaction
|
|
196
|
+
expect(signedTx).to.equal(mockVersionedTransaction);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('sendTransaction', () => {
|
|
201
|
+
it('should throw if no connection is provided', async () => {
|
|
202
|
+
// Create a client without a connection
|
|
203
|
+
const clientWithoutConnection = createEmblemVaultSolanaWalletClient({
|
|
204
|
+
sdk: sdk,
|
|
205
|
+
walletId: testWalletId
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Create a simple transaction
|
|
209
|
+
const transaction = new Transaction();
|
|
210
|
+
|
|
211
|
+
// Attempt to send the transaction
|
|
212
|
+
try {
|
|
213
|
+
await clientWithoutConnection.sendTransaction(transaction);
|
|
214
|
+
// If it doesn't throw, fail the test
|
|
215
|
+
expect.fail('sendTransaction should have thrown without a connection');
|
|
216
|
+
} catch (error) {
|
|
217
|
+
expect(error).to.be.instanceOf(Error);
|
|
218
|
+
expect(error.message).to.equal('Connection is required to send transactions');
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should sign and send a transaction', async () => {
|
|
223
|
+
// Get the public key first
|
|
224
|
+
const publicKey = await walletClient.getPublicKey();
|
|
225
|
+
|
|
226
|
+
// Create a simple transaction
|
|
227
|
+
const transaction = new Transaction().add(
|
|
228
|
+
SystemProgram.transfer({
|
|
229
|
+
fromPubkey: publicKey,
|
|
230
|
+
toPubkey: new PublicKey('11111111111111111111111111111111'),
|
|
231
|
+
lamports: LAMPORTS_PER_SOL * 0.01
|
|
232
|
+
})
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
// Set recent blockhash
|
|
236
|
+
transaction.recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k';
|
|
237
|
+
transaction.feePayer = publicKey;
|
|
238
|
+
|
|
239
|
+
// Send the transaction
|
|
240
|
+
const signature = await walletClient.sendTransaction(transaction);
|
|
241
|
+
|
|
242
|
+
// Verify a signature was returned
|
|
243
|
+
expect(signature).to.be.a('string');
|
|
244
|
+
expect(signature).to.include('mock_tx_signature');
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
describe('sendVersionedTransaction', () => {
|
|
249
|
+
it('should throw if no connection is provided', async () => {
|
|
250
|
+
// Create a client without a connection
|
|
251
|
+
const clientWithoutConnection = createEmblemVaultSolanaWalletClient({
|
|
252
|
+
sdk: sdk,
|
|
253
|
+
walletId: testWalletId
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Get the public key first
|
|
257
|
+
const publicKey = await clientWithoutConnection.getPublicKey();
|
|
258
|
+
|
|
259
|
+
// Create a mock versioned transaction
|
|
260
|
+
const mockVersionedTransaction = {
|
|
261
|
+
message: {
|
|
262
|
+
serialize: () => Buffer.from('mock-serialized-message')
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// Attempt to send the transaction
|
|
267
|
+
try {
|
|
268
|
+
await clientWithoutConnection.sendVersionedTransaction(mockVersionedTransaction);
|
|
269
|
+
// If it doesn't throw, fail the test
|
|
270
|
+
expect.fail('sendVersionedTransaction should have thrown without a connection');
|
|
271
|
+
} catch (error) {
|
|
272
|
+
expect(error).to.be.instanceOf(Error);
|
|
273
|
+
expect(error.message).to.equal('Connection is required to send transactions');
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should sign and send a versioned transaction', async () => {
|
|
278
|
+
// Get the public key first
|
|
279
|
+
const publicKey = await walletClient.getPublicKey();
|
|
280
|
+
|
|
281
|
+
// Create a mock versioned transaction
|
|
282
|
+
const mockVersionedTransaction = {
|
|
283
|
+
message: {
|
|
284
|
+
serialize: () => Buffer.from('mock-serialized-message')
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Send the transaction
|
|
289
|
+
const signature = await walletClient.sendVersionedTransaction(mockVersionedTransaction);
|
|
290
|
+
|
|
291
|
+
// Verify a signature was returned
|
|
292
|
+
expect(signature).to.be.a('string');
|
|
293
|
+
expect(signature).to.include('mock_tx_signature');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
});
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
3
|
+
const { EmblemVaultSDK } = require('../../../dist/index.js');
|
|
4
|
+
const { expect } = require('chai');
|
|
5
|
+
const sinon = require('sinon');
|
|
6
|
+
const { createEmblemVaultWalletClient } = require('../../../dist/clients/emblemVaultWalletClient.js');
|
|
7
|
+
const { parseEther } = require('viem');
|
|
8
|
+
|
|
9
|
+
// Mock SDK
|
|
10
|
+
const mockApiKey = 'mock-api-key';
|
|
11
|
+
class MockEmblemVaultSDK extends EmblemVaultSDK {
|
|
12
|
+
constructor(apiKey) {
|
|
13
|
+
super(apiKey);
|
|
14
|
+
// Override methods if necessary for testing setup
|
|
15
|
+
}
|
|
16
|
+
// Mock any methods needed by the client creation or its methods, if they are called internally
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('EmblemVaultWalletClient', () => {
|
|
20
|
+
let sdk;
|
|
21
|
+
let walletClient;
|
|
22
|
+
const testWalletId = 'test-wallet-001';
|
|
23
|
+
const mockAccountAddress = '0xMockAddressFor' + testWalletId; // Consistent mock address
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
sdk = new MockEmblemVaultSDK(mockApiKey);
|
|
27
|
+
walletClient = createEmblemVaultWalletClient({
|
|
28
|
+
sdk: sdk,
|
|
29
|
+
walletId: testWalletId,
|
|
30
|
+
// Optionally provide a mock account here if needed for default tests
|
|
31
|
+
// account: { address: mockAccountAddress, type: 'json-rpc'} // type is required by viem Account
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
// Restore sinon spies/stubs after each test
|
|
37
|
+
sinon.restore();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should create a client instance', () => {
|
|
41
|
+
expect(walletClient).to.exist;
|
|
42
|
+
expect(walletClient.type).to.equal('emblemVaultWalletClient');
|
|
43
|
+
expect(walletClient.walletId).to.equal(testWalletId);
|
|
44
|
+
expect(walletClient.sdk).to.equal(sdk);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should have the expected methods', () => {
|
|
48
|
+
expect(walletClient.getAddresses).to.be.a('function');
|
|
49
|
+
expect(walletClient.signMessage).to.be.a('function');
|
|
50
|
+
expect(walletClient.signTypedData).to.be.a('function');
|
|
51
|
+
expect(walletClient.sendTransaction).to.be.a('function');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('getAddresses', () => {
|
|
55
|
+
it('should return the mock address derived from walletId when no account is configured', async () => {
|
|
56
|
+
const addresses = await walletClient.getAddresses();
|
|
57
|
+
expect(addresses).to.be.an('array').with.lengthOf(1);
|
|
58
|
+
expect(addresses[0]).to.equal(mockAccountAddress);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should return the configured account address if provided', async () => {
|
|
62
|
+
const configuredAddress = '0xConfiguredAccountAddress001';
|
|
63
|
+
const clientWithAccount = createEmblemVaultWalletClient({
|
|
64
|
+
sdk: sdk,
|
|
65
|
+
walletId: testWalletId,
|
|
66
|
+
account: { address: configuredAddress, type: 'local',
|
|
67
|
+
publicKey: '0x', // Added mock publicKey
|
|
68
|
+
source: 'custom', // Added mock source
|
|
69
|
+
signMessage: async () => '0x',
|
|
70
|
+
signTransaction: async () => '0x',
|
|
71
|
+
signTypedData: async () => '0x' }
|
|
72
|
+
});
|
|
73
|
+
const addresses = await clientWithAccount.getAddresses();
|
|
74
|
+
expect(addresses).to.be.an('array').with.lengthOf(1);
|
|
75
|
+
expect(addresses[0]).to.equal(configuredAddress);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should return the configured account address from Account object', async () => {
|
|
79
|
+
const configuredAddress = '0xConfiguredAccountObjectAddress002';
|
|
80
|
+
const clientWithAccount = createEmblemVaultWalletClient({
|
|
81
|
+
sdk: sdk,
|
|
82
|
+
walletId: testWalletId,
|
|
83
|
+
account: { address: configuredAddress, type: 'local',
|
|
84
|
+
publicKey: '0x', // Added mock publicKey
|
|
85
|
+
source: 'custom', // Added mock source
|
|
86
|
+
signMessage: async () => '0x',
|
|
87
|
+
signTransaction: async () => '0x',
|
|
88
|
+
signTypedData: async () => '0x' }
|
|
89
|
+
});
|
|
90
|
+
const addresses = await clientWithAccount.getAddresses();
|
|
91
|
+
expect(addresses).to.be.an('array').with.lengthOf(1);
|
|
92
|
+
expect(addresses[0]).to.equal(configuredAddress);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('signMessage', () => {
|
|
97
|
+
it('should return a mock signature string', async () => {
|
|
98
|
+
const message = 'Hello, Emblem!';
|
|
99
|
+
const signature = await walletClient.signMessage({ message, account: mockAccountAddress });
|
|
100
|
+
|
|
101
|
+
expect(signature).to.be.a('string');
|
|
102
|
+
expect(signature).to.match(/^0x[a-f0-9]+$/); // Check for hex format
|
|
103
|
+
expect(signature).to.include(Buffer.from(`mock_signature_for_${testWalletId}`).toString('hex'));
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should use the account provided in parameters', async () => {
|
|
107
|
+
const specificAccount = '0xSpecificAccountForMsg003';
|
|
108
|
+
// Spy on the signMessage method directly
|
|
109
|
+
const signMessageSpy = sinon.spy(walletClient, 'signMessage');
|
|
110
|
+
await walletClient.signMessage({ message: 'Hello, specific account!', account: specificAccount });
|
|
111
|
+
// Verify the method was called with the specific account
|
|
112
|
+
expect(signMessageSpy.calledWith(sinon.match({
|
|
113
|
+
message: 'Hello, specific account!',
|
|
114
|
+
account: specificAccount
|
|
115
|
+
}))).to.be.true;
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('signTypedData', () => {
|
|
120
|
+
// EIP712 Domain definition
|
|
121
|
+
const domain = {
|
|
122
|
+
name: 'Ether Mail',
|
|
123
|
+
version: '1',
|
|
124
|
+
chainId: 1,
|
|
125
|
+
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// The named type definitions
|
|
129
|
+
const types = {
|
|
130
|
+
Person: [
|
|
131
|
+
{ name: 'name', type: 'string' },
|
|
132
|
+
{ name: 'wallet', type: 'address' },
|
|
133
|
+
],
|
|
134
|
+
Mail: [
|
|
135
|
+
{ name: 'from', type: 'Person' },
|
|
136
|
+
{ name: 'to', type: 'Person' },
|
|
137
|
+
{ name: 'contents', type: 'string' },
|
|
138
|
+
],
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// The data to sign
|
|
142
|
+
const message = {
|
|
143
|
+
from: {
|
|
144
|
+
name: 'Alice',
|
|
145
|
+
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
|
|
146
|
+
},
|
|
147
|
+
to: {
|
|
148
|
+
name: 'Bob',
|
|
149
|
+
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
|
|
150
|
+
},
|
|
151
|
+
contents: 'Hello, Bob!',
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
it('should return a mock signature string for typed data', async () => {
|
|
155
|
+
const signature = await walletClient.signTypedData({
|
|
156
|
+
domain,
|
|
157
|
+
types,
|
|
158
|
+
primaryType: 'Mail',
|
|
159
|
+
message,
|
|
160
|
+
account: mockAccountAddress
|
|
161
|
+
});
|
|
162
|
+
expect(signature).to.be.a('string');
|
|
163
|
+
expect(signature).to.match(/^0x[a-f0-9]+$/);
|
|
164
|
+
expect(signature).to.include(Buffer.from(`mock_signature_for_${testWalletId}_typed_Mail`).toString('hex'));
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should use the account provided in parameters for typed data', async () => {
|
|
168
|
+
const specificAccount = '0xSpecificAccountForTypedData004';
|
|
169
|
+
// Spy on the signTypedData method directly
|
|
170
|
+
const signTypedDataSpy = sinon.spy(walletClient, 'signTypedData');
|
|
171
|
+
await walletClient.signTypedData({
|
|
172
|
+
domain,
|
|
173
|
+
types,
|
|
174
|
+
primaryType: 'Mail',
|
|
175
|
+
message,
|
|
176
|
+
account: specificAccount
|
|
177
|
+
});
|
|
178
|
+
// Verify the method was called with the specific account
|
|
179
|
+
expect(signTypedDataSpy.calledWith(sinon.match({
|
|
180
|
+
domain,
|
|
181
|
+
types,
|
|
182
|
+
primaryType: 'Mail',
|
|
183
|
+
message,
|
|
184
|
+
account: specificAccount
|
|
185
|
+
}))).to.be.true;
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe('sendTransaction', () => {
|
|
190
|
+
it('should return a mock transaction hash', async () => {
|
|
191
|
+
const txParams = {
|
|
192
|
+
account: mockAccountAddress, // Provide the account needed for sendTransaction
|
|
193
|
+
to: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
|
|
194
|
+
value: parseEther('0.01'),
|
|
195
|
+
chain: null // Explicitly provide chain: null when account is specified
|
|
196
|
+
};
|
|
197
|
+
// Client needs an account configured or passed for sendTransaction
|
|
198
|
+
const clientWithAccount = createEmblemVaultWalletClient({
|
|
199
|
+
sdk: sdk,
|
|
200
|
+
walletId: testWalletId,
|
|
201
|
+
account: mockAccountAddress
|
|
202
|
+
});
|
|
203
|
+
const txHash = await clientWithAccount.sendTransaction(txParams);
|
|
204
|
+
expect(txHash).to.be.a('string');
|
|
205
|
+
expect(txHash).to.match(/^0x[a-f0-9]{64}$/); // Check for 64 hex chars
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should use the account provided in parameters for transaction', async () => {
|
|
209
|
+
const specificAccount = '0xSpecificAccountForTx005';
|
|
210
|
+
const txParams = {
|
|
211
|
+
account: specificAccount, // Pass account in tx params
|
|
212
|
+
to: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
|
|
213
|
+
value: parseEther('0.01'),
|
|
214
|
+
chain: null // Explicitly provide chain: null when account is specified in params
|
|
215
|
+
};
|
|
216
|
+
// Spy on the sendTransaction method directly
|
|
217
|
+
const sendTransactionSpy = sinon.spy(walletClient, 'sendTransaction');
|
|
218
|
+
await walletClient.sendTransaction(txParams); // Can use default client as account is in params
|
|
219
|
+
// Verify the method was called with the specific account
|
|
220
|
+
expect(sendTransactionSpy.calledWith(sinon.match({
|
|
221
|
+
account: specificAccount,
|
|
222
|
+
to: txParams.to,
|
|
223
|
+
value: txParams.value,
|
|
224
|
+
chain: null
|
|
225
|
+
}))).to.be.true;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should throw if no account is available', async () => {
|
|
229
|
+
const txParams = {
|
|
230
|
+
to: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
|
|
231
|
+
value: parseEther('0.01'),
|
|
232
|
+
};
|
|
233
|
+
// We need to provide an account, even if it's just the mock one, to hit the logic path being tested
|
|
234
|
+
// The implementation should check for account presence *before* this call is made in real scenarios
|
|
235
|
+
// However, the type requires it here. The check inside the method is what prevents the action.
|
|
236
|
+
try {
|
|
237
|
+
await walletClient.sendTransaction({ ...txParams, account: mockAccountAddress, chain: null }); // Added chain: null
|
|
238
|
+
// If it doesn't throw, fail the test
|
|
239
|
+
expect.fail('Cannot send transaction without an account specified.');
|
|
240
|
+
} catch (error) {
|
|
241
|
+
expect(error).to.be.instanceOf(Error);
|
|
242
|
+
expect(error.message).to.equal('Cannot send transaction without an account specified.');
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|