Skip to content

Commit cd30fa3

Browse files
Merge pull request #12 from lazor-kit/feat/support-kora-client-sdk
Feat/support kora client sdk
2 parents 384932e + 1c029d7 commit cd30fa3

File tree

17 files changed

+324
-486
lines changed

17 files changed

+324
-486
lines changed

README.md

Lines changed: 60 additions & 363 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lazorkit/wallet-mobile-adapter",
3-
"version": "1.3.74",
3+
"version": "1.4.0",
44
"main": "dist/index.js",
55
"module": "dist/index.esm.js",
66
"types": "dist/index.d.ts",
@@ -42,10 +42,11 @@
4242
"url": "https://github.com/lazorkit/wallet-mobile-adapter/issues"
4343
},
4444
"engines": {
45-
"node": ">=16.0.0"
45+
"node": ">=18.0.0"
4646
},
4747
"devDependencies": {
4848
"@eslint/js": "9.33.0",
49+
"@rollup/plugin-commonjs": "28.0.6",
4950
"@rollup/plugin-json": "6.1.0",
5051
"@rollup/plugin-node-resolve": "16.0.1",
5152
"@types/bn.js": "^5.2.0",
@@ -54,6 +55,7 @@
5455
"eslint": "9.33.0",
5556
"eslint-plugin-react": "7.37.5",
5657
"globals": "16.3.0",
58+
"react-native": ">=0.70.0",
5759
"rollup": "4.46.0",
5860
"rollup-plugin-dts": "6.2.1",
5961
"rollup-plugin-peer-deps-external": "2.2.4",
@@ -63,13 +65,16 @@
6365
},
6466
"dependencies": {
6567
"@coral-xyz/anchor": "0.31.1",
66-
"@react-native-async-storage/async-storage": "2.2.0",
67-
"@rollup/plugin-commonjs": "28.0.6",
68+
"@react-native-async-storage/async-storage": "^2.2.0",
6869
"buffer": "6.0.3",
70+
"expo-crypto": "^15.0.8",
6971
"expo-web-browser": "^14.2.0",
7072
"js-sha256": "0.11.1",
71-
"react-native": "^0.82.1",
7273
"react-native-get-random-values": "^1.11.0",
7374
"zustand": "^5.0.7"
75+
},
76+
"peerDependencies": {
77+
"react": ">=18.0.0",
78+
"react-native": ">=0.70.0"
7479
}
7580
}

scripts/prepublish-check.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,22 +66,22 @@ function checkFileSize(filePath, maxSizeKB, description) {
6666
function checkPackageJson() {
6767
return check('Package.json validation', () => {
6868
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
69-
69+
7070
const requiredFields = [
7171
'name', 'version', 'main', 'module', 'types', 'files',
7272
'author', 'license', 'description', 'repository'
7373
];
74-
74+
7575
for (const field of requiredFields) {
7676
if (!pkg[field]) {
7777
throw new Error(`Missing required field: ${field}`);
7878
}
7979
}
80-
80+
8181
if (!pkg.name.startsWith('@lazorkit/')) {
8282
throw new Error('Package name must start with @lazorkit/');
8383
}
84-
84+
8585
if (pkg.license !== 'MIT') {
8686
throw new Error('License must be MIT');
8787
}
@@ -103,20 +103,20 @@ function checkTypes() {
103103
function checkDistFiles() {
104104
const distFiles = [
105105
'dist/index.js',
106-
'dist/index.esm.js',
106+
'dist/index.esm.js',
107107
'dist/index.d.ts'
108108
];
109-
109+
110110
const results = [];
111111
for (const file of distFiles) {
112112
results.push(checkFileExists(file, `Dist file exists: ${file}`));
113113
}
114-
114+
115115
// Check file sizes
116116
results.push(checkFileSize('dist/index.js', 500, 'Main bundle size check'));
117117
results.push(checkFileSize('dist/index.esm.js', 500, 'ESM bundle size check'));
118118
results.push(checkFileSize('dist/index.d.ts', 200, 'Types file size check'));
119-
119+
120120
return results;
121121
}
122122

@@ -125,29 +125,29 @@ function checkDocumentation() {
125125
'README.md',
126126
'SECURITY.md'
127127
];
128-
128+
129129
const results = [];
130130
for (const doc of docs) {
131131
results.push(checkFileExists(doc, `Documentation exists: ${doc}`));
132132
}
133-
133+
134134
return results;
135135
}
136136

137137
function checkExports() {
138138
return check('Export verification', () => {
139139
const distIndex = fs.readFileSync('dist/index.d.ts', 'utf8');
140-
140+
141141
const requiredExports = [
142142
'LazorKitProvider',
143-
'useLazorWallet',
143+
'useWallet',
144144
'useWalletStore',
145145
'WalletInfo',
146146
'ConnectOptions',
147147
'SignOptions',
148148
'LazorKitError'
149149
];
150-
150+
151151
for (const exportName of requiredExports) {
152152
if (!distIndex.includes(exportName)) {
153153
throw new Error(`Missing export: ${exportName}`);
@@ -158,7 +158,7 @@ function checkExports() {
158158

159159
function main() {
160160
log('🚀 Starting pre-publish checks...', colors.bold + colors.blue);
161-
161+
162162
const checks = [
163163
checkPackageJson(),
164164
checkSecurity(),
@@ -168,9 +168,9 @@ function main() {
168168
...checkDocumentation(),
169169
checkExports()
170170
];
171-
171+
172172
const failed = checks.filter(check => !check.success);
173-
173+
174174
if (failed.length > 0) {
175175
log('\n❌ Pre-publish checks failed!', colors.bold + colors.red);
176176
log('Please fix the issues above before publishing.', colors.red);

src/actions.ts

Lines changed: 107 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
import { asCredentialHash, LazorkitClient, getBlockchainTimestamp, SmartWalletAction } from './contract';
2323
import { getFeePayer } from './core/paymaster';
2424
import { sha256 } from 'js-sha256';
25+
import { SignAndSendTransactionPayload } from './types';
2526

2627
/**
2728
* Connects to the wallet
@@ -46,7 +47,7 @@ export const connectAction = async (
4647

4748
try {
4849
const redirectUrl = options.redirectUrl;
49-
const connectUrl = `${config.ipfsUrl}/${API_ENDPOINTS.CONNECT
50+
const connectUrl = `${config.portalUrl}/${API_ENDPOINTS.CONNECT
5051
}&redirect_url=${encodeURIComponent(redirectUrl)}`;
5152

5253
const resultUrl = await openBrowser(connectUrl, redirectUrl);
@@ -105,7 +106,7 @@ export const disconnectAction = async (set: (state: Partial<WalletStateClient>)
105106
export const signAndExecuteTransaction = async (
106107
get: () => WalletStateClient,
107108
set: (state: Partial<WalletStateClient>) => void,
108-
instructions: anchor.web3.TransactionInstruction[],
109+
payload: SignAndSendTransactionPayload,
109110
options: SignOptions
110111
) => {
111112
const { isSigning, connection, wallet, config } = get();
@@ -134,20 +135,20 @@ export const signAndExecuteTransaction = async (
134135

135136
const feePayer = await getFeePayer(config.configPaymaster.paymasterUrl, config.configPaymaster.apiKey);
136137

137-
const timestamp = await getBlockchainTimestamp(connection);
138+
const timestamp = new anchor.BN(await getBlockchainTimestamp(connection));
138139

139140
const message = await lazorProgram.buildAuthorizationMessage({
140141
action: {
141142
type: SmartWalletAction.CreateChunk,
142143
args: {
143144
policyInstruction: null,
144-
cpiInstructions: instructions,
145+
cpiInstructions: payload.instructions,
145146
}
146147
},
147148
payer: feePayer,
148149
smartWallet: new anchor.web3.PublicKey(wallet.smartWallet),
149150
passkeyPublicKey: wallet.passkeyPubkey,
150-
timestamp: new anchor.BN(timestamp),
151+
timestamp,
151152
credentialHash: asCredentialHash(
152153
Array.from(
153154
new Uint8Array(
@@ -162,11 +163,23 @@ export const signAndExecuteTransaction = async (
162163
.replace(/\+/g, '-')
163164
.replace(/\//g, '_')
164165
.replace(/=+$/, '');
166+
const latestBlockhash = await connection.getLatestBlockhash();
167+
const messageV0 = new anchor.web3.TransactionMessage({
168+
payerKey: feePayer, // PublicKey
169+
recentBlockhash: latestBlockhash.blockhash,
170+
instructions: payload.instructions,
171+
}).compileToV0Message();
165172

173+
const versionedTx = new anchor.web3.VersionedTransaction(messageV0);
174+
const base64Tx = Buffer.from(versionedTx.serialize()).toString("base64");
166175
const redirectUrl = options.redirectUrl;
167-
const signUrl = `${config.ipfsUrl}/${API_ENDPOINTS.SIGN}&message=${encodeURIComponent(
176+
let signUrl = `${config.portalUrl}/${API_ENDPOINTS.SIGN}&message=${encodeURIComponent(
168177
encodedChallenge
169-
)}&redirect_url=${encodeURIComponent(redirectUrl)}`;
178+
)}&credentialId=${encodeURIComponent(wallet.credentialId)}&transaction=${encodeURIComponent(base64Tx)}&redirect_url=${encodeURIComponent(redirectUrl)}`;
179+
180+
if (payload.transactionOptions?.clusterSimulation) {
181+
signUrl += `&clusterSimulation=${payload.transactionOptions.clusterSimulation}`;
182+
}
170183

171184
await openSignBrowser(
172185
signUrl,
@@ -188,11 +201,12 @@ export const signAndExecuteTransaction = async (
188201
type: SmartWalletAction.CreateChunk,
189202
args: {
190203
policyInstruction: null,
191-
cpiInstructions: instructions,
204+
cpiInstructions: payload.instructions,
192205
}
193206
},
194207
browserResult,
195-
options
208+
options,
209+
payload.transactionOptions
196210
);
197211
options?.onSuccess?.(txnSignature);
198212
} catch (error) {
@@ -220,3 +234,87 @@ export const signAndExecuteTransaction = async (
220234
set({ isSigning: false });
221235
}
222236
};
237+
238+
/**
239+
* Sign a message (arbitrary string or bytes)
240+
*
241+
* @param get - Zustand state getter function
242+
* @param set - Zustand state setter function
243+
* @param message - Message to sign (string)
244+
* @param options - Signing options with callbacks
245+
*/
246+
export const signMessageAction = async (
247+
get: () => WalletStateClient,
248+
set: (state: Partial<WalletStateClient>) => void,
249+
message: string,
250+
options: SignOptions
251+
) => {
252+
const { isSigning, wallet, config } = get();
253+
if (isSigning) {
254+
return;
255+
}
256+
257+
if (!wallet) {
258+
const error = new SigningError('No wallet connected');
259+
logger.error('Sign message failed: No wallet connected');
260+
options?.onFail?.(error);
261+
return;
262+
}
263+
264+
set({ isSigning: true, error: null });
265+
266+
try {
267+
const redirectUrl = options.redirectUrl;
268+
// For signMessage, we pass the message directly.
269+
// The portal will treat 'transaction' param as message if it's not a valid transaction or if action is 'sign'
270+
// But better to use a specific param or just rely on 'transaction' param being the message container as per portal logic
271+
// PortalCommunicator: transaction: urlParams.get('transaction')
272+
// TransactionReview: portalParams.transaction || portalParams.message
273+
// Let's use 'message' param for clarity if portal supports it, checking portal-communicator.ts:
274+
// message: urlParams.get('message') || ''
275+
// So we should use 'message' param.
276+
277+
// If message is not base64, we might want to encode it?
278+
// User passes string. Let's pass it as is, or base64 encoded?
279+
// Portal expects 'message' to be displayed. If we want it to be readable, pass as string.
280+
// If it's bytes, pass base64?
281+
// The type signature says `message: string`. Let's assume readable string.
282+
283+
const signUrl = `${config.portalUrl}/${API_ENDPOINTS.SIGN}&message=${encodeURIComponent(
284+
message
285+
)}&credentialId=${encodeURIComponent(wallet.credentialId)}&redirect_url=${encodeURIComponent(redirectUrl)}`;
286+
287+
await openSignBrowser(
288+
signUrl,
289+
redirectUrl,
290+
async (urlResult) => {
291+
try {
292+
const authResult = handleBrowserResult(urlResult);
293+
const signature = authResult.signature;
294+
const signedPayload = authResult.message;
295+
options?.onSuccess?.({ signature, signedPayload });
296+
} catch (error) {
297+
const err = error instanceof Error ? error : new Error(String(error));
298+
logger.error('Sign message browser result processing failed:', err, { urlResult });
299+
set({ error: err });
300+
options?.onFail?.(err);
301+
}
302+
},
303+
(error) => {
304+
logger.error('Sign message browser failed:', error, { signUrl, redirectUrl });
305+
set({ error });
306+
options?.onFail?.(error);
307+
}
308+
);
309+
} catch (error: unknown) {
310+
logger.error('Sign message action failed:', error, {
311+
smartWallet: wallet?.smartWallet,
312+
redirectUrl: options.redirectUrl,
313+
});
314+
const err = error instanceof Error ? error : new SigningError('Unknown error');
315+
set({ error: err });
316+
options?.onFail?.(err);
317+
} finally {
318+
set({ isSigning: false });
319+
}
320+
};

src/config/defaults.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const DEFAULTS = {
2-
IPFS_URL: 'https://portal.lazor.sh',
2+
PORTAL_URL: 'https://portal.lazor.sh',
33
PAYMASTER_URL: 'https://kora.devnet.lazorkit.com',
44
RPC_ENDPOINT: 'https://api.devnet.solana.com',
55
} as const;

src/contract/client/lazorkit.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ export class LazorkitClient {
405405
smartWallet: walletDevice.smartWallet,
406406
walletState: this.getWalletStatePubkey(walletDevice.smartWallet),
407407
walletDevice: account.pubkey,
408+
passkeyPubkey: walletDevice.passkeyPubkey,
408409
};
409410
}
410411
}

0 commit comments

Comments
 (0)