passkey-kit 0.6.1 → 0.7.1

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.
@@ -2,6 +2,8 @@
2
2
  "rust-analyzer.linkedProjects": [
3
3
  "./zephyr/Cargo.toml",
4
4
  "./contracts/Cargo.toml",
5
+ "./contracts/example-contract/Cargo.toml",
6
+ "./contracts/sample-policy/Cargo.toml",
5
7
  "./contracts/webauthn-factory/Cargo.toml",
6
8
  "./contracts/webauthn-wallet/Cargo.toml",
7
9
  ]
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Passkey Kit
2
2
 
3
+ > [!WARNING]
4
+ > Code in this repo is demo material only. It has not been audited. Do not use to hold, protect, or secure anything.
5
+
3
6
  Passkey kit is a basic TypeScript SDK for creating and managing Stellar smart wallets. It's intended to be used in tandem with [Launchtube](https://github.com/kalepail/launchtube) for submitting passkey signed transactions onchain however this is not a requirement. This is both a client and a server side library. `PasskeyKit` on the client and `PasskeyServer` on the server.
4
7
 
5
8
  Demo site: [passkey-kit-demo.pages.dev](https://passkey-kit-demo.pages.dev/)
package/cheatsheet CHANGED
@@ -4,13 +4,17 @@ npm publish --workspaces
4
4
  # Install passkey-kit
5
5
  pnpm publish --no-git-checks
6
6
 
7
+ # Stellar commands
8
+ stellar contract bindings rust --wasm target/wasm32-unknown-unknown/release/webauthn_wallet.wasm
9
+ stellar contract deploy --wasm target/wasm32-unknown-unknown/release/sample_policy.wasm --network testnet --source default
10
+
7
11
  # Mercury commands
8
12
  # https://test.mercurydata.app/
9
13
 
10
14
  export JWT=???
11
15
  mercury-cli --jwt $JWT --local false --mainnet false deploy
12
- mercury-cli --jwt $JWT --local false --mainnet false catchup --contracts "CDOWBLFYFIWXVUW46QILLAIYIWWCZ63CIRQBG3DK5PDBUVVJ4QVJX2IX" # don't forget to subscribe to the contract first
16
+ mercury-cli --jwt $JWT --local false --mainnet false catchup --project-name "smart-wallets-data-multi-signer-multi-sig" --contracts "CDONKSPO6DUH46JRRIAK4O5ZINA5C2RXHP57BMFHKVBGOQXAT3IW6QCO"
13
17
  curl -X GET https://api.mercurydata.app/catchups/4
14
- curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_signers_by_address", "arguments": "{\"address\": \"CCXIUFR243N7QWKXY44LZO3DVUXHAVBEEJWFGNGNVVB44VJXIYWVGNTR\"}"}}}'
18
+ curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_signers_by_address", "arguments": "{\"address\": \"CA4G3X75IGGNXNLXFIVFNYIGC6YAVLA7KSIFFDBSR7RQ7KEZMZWLXQBH\"}"}}}'
15
19
  curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_address_by_signer", "arguments": "{\"id\": [78,127,30,69,248,174,95,168,47,59,161,168,51,120,117,135,112,133,232,92]}"}}}'
16
- curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_events_by_address", "arguments": "{\"address\": \"CCXIUFR243N7QWKXY44LZO3DVUXHAVBEEJWFGNGNVVB44VJXIYWVGNTR\"}"}}}'
20
+ curl -X POST https://api.mercurydata.app/zephyr/execute -H "Authorization: Bearer $MERCURY_JWT" -H 'Content-Type: application/json' -d '{"mode":{"Function": {"fname": "get_events_by_address", "arguments": "{\"address\": \"CA4G3X75IGGNXNLXFIVFNYIGC6YAVLA7KSIFFDBSR7RQ7KEZMZWLXQBH\"}"}}}'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passkey-kit",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "A helper library for creating and using passkey accounts on the Stellar blockchain.",
5
5
  "author": "Tyler van der Hoeven",
6
6
  "license": "MIT",
@@ -10,16 +10,16 @@
10
10
  "dependencies": {
11
11
  "@darkedges/capacitor-native-webauthn": "^0.0.4",
12
12
  "@simplewebauthn/browser": "^10.0.0",
13
- "@stellar/stellar-sdk": "12.1.0",
13
+ "@stellar/stellar-sdk": "12.3.0",
14
14
  "base64url": "^3.0.1",
15
15
  "buffer": "^6.0.3",
16
- "passkey-kit-sdk": "0.2.1",
17
- "passkey-factory-sdk": "0.2.1",
16
+ "passkey-factory-sdk": "0.3.1",
17
+ "passkey-kit-sdk": "0.3.1",
18
18
  "sac-sdk": "0.1.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@simplewebauthn/types": "^10.0.0",
22
- "typescript": "^5.5.3"
22
+ "typescript": "^5.6.2"
23
23
  },
24
24
  "workspaces": [
25
25
  "packages/*"
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.2.1",
2
+ "version": "0.3.1",
3
3
  "name": "passkey-factory-sdk",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
@@ -10,9 +10,9 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "buffer": "6.0.3",
13
- "@stellar/stellar-sdk": "12.1.0"
13
+ "@stellar/stellar-sdk": "12.3.0"
14
14
  },
15
15
  "devDependencies": {
16
- "typescript": "5.5.3"
16
+ "typescript": "5.6.2"
17
17
  }
18
18
  }
@@ -1,4 +1,5 @@
1
1
  import { Buffer } from "buffer";
2
+ import { Address } from '@stellar/stellar-sdk';
2
3
  import {
3
4
  AssembledTransaction,
4
5
  Client as ContractClient,
@@ -6,21 +7,43 @@ import {
6
7
  Result,
7
8
  Spec as ContractSpec,
8
9
  } from '@stellar/stellar-sdk/contract';
10
+ import type {
11
+ u32,
12
+ i32,
13
+ u64,
14
+ i64,
15
+ u128,
16
+ i128,
17
+ u256,
18
+ i256,
19
+ Option,
20
+ Typepoint,
21
+ Duration,
22
+ } from '@stellar/stellar-sdk/contract';
9
23
 
10
24
  if (typeof window !== 'undefined') {
11
25
  //@ts-ignore Buffer exists
12
26
  window.Buffer = window.Buffer || Buffer;
13
27
  }
14
28
 
29
+
15
30
  export const networks = {
16
31
  testnet: {
17
32
  networkPassphrase: "Test SDF Network ; September 2015",
18
- contractId: "CCPLERXCJZB7LX2VOSOCBNRN754FRLHI6Y2AVOQBA5L7C2ZJX5RFVVET",
33
+ contractId: "CA3WONARSZHZQCCM5WF5HLD27MIP7RWCQJMID4TLZIWPHQYGJT2CIYWX",
19
34
  }
20
35
  } as const
21
36
 
37
+ export type SignerLimits = readonly [Map<string, Option<Array<SignerKey>>>];
38
+ export type SignerKey = { tag: "Policy", values: readonly [string] } | { tag: "Ed25519", values: readonly [Buffer] } | { tag: "Secp256r1", values: readonly [Buffer] };
39
+
40
+ export type SignerStorage = { tag: "Persistent", values: void } | { tag: "Temporary", values: void };
41
+
42
+ export type Signer = { tag: "Policy", values: readonly [string, SignerLimits, SignerStorage] } | { tag: "Ed25519", values: readonly [Buffer, SignerLimits, SignerStorage] } | { tag: "Secp256r1", values: readonly [Buffer, Buffer, SignerLimits, SignerStorage] };
43
+
22
44
  export const Errors = {
23
45
  1: { message: "NotInitialized" },
46
+
24
47
  2: { message: "AlreadyInitialized" }
25
48
  }
26
49
 
@@ -48,7 +71,7 @@ export interface Client {
48
71
  /**
49
72
  * Construct and simulate a deploy transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
50
73
  */
51
- deploy: ({ salt, id, pk }: { salt: Buffer, id: Buffer, pk: Buffer }, options?: {
74
+ deploy: ({ salt, signer }: { salt: Buffer, signer: Signer }, options?: {
52
75
  /**
53
76
  * The fee to pay for the transaction. Default: BASE_FEE
54
77
  */
@@ -64,13 +87,18 @@ export interface Client {
64
87
  */
65
88
  simulate?: boolean;
66
89
  }) => Promise<AssembledTransaction<Result<string>>>
90
+
67
91
  }
68
92
  export class Client extends ContractClient {
69
93
  constructor(public readonly options: ContractClientOptions) {
70
94
  super(
71
- new ContractSpec(["AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAAAgAAAAAAAAAOTm90SW5pdGlhbGl6ZWQAAAAAAAEAAAAAAAAAEkFscmVhZHlJbml0aWFsaXplZAAAAAAAAg==",
95
+ new ContractSpec(["AAAAAQAAAAAAAAAAAAAADFNpZ25lckxpbWl0cwAAAAEAAAAAAAAAATAAAAAAAAPsAAAAEwAAA+gAAAPqAAAH0AAAAAlTaWduZXJLZXkAAAA=",
96
+ "AAAAAgAAAAAAAAAAAAAACVNpZ25lcktleQAAAAAAAAMAAAABAAAAAAAAAAZQb2xpY3kAAAAAAAEAAAATAAAAAQAAAAAAAAAHRWQyNTUxOQAAAAABAAAD7gAAACAAAAABAAAAAAAAAAlTZWNwMjU2cjEAAAAAAAABAAAADg==",
97
+ "AAAAAgAAAAAAAAAAAAAADVNpZ25lclN0b3JhZ2UAAAAAAAACAAAAAAAAAAAAAAAKUGVyc2lzdGVudAAAAAAAAAAAAAAAAAAJVGVtcG9yYXJ5AAAA",
98
+ "AAAAAgAAAAAAAAAAAAAABlNpZ25lcgAAAAAAAwAAAAEAAAAAAAAABlBvbGljeQAAAAAAAwAAABMAAAfQAAAADFNpZ25lckxpbWl0cwAAB9AAAAANU2lnbmVyU3RvcmFnZQAAAAAAAAEAAAAAAAAAB0VkMjU1MTkAAAAAAwAAA+4AAAAgAAAH0AAAAAxTaWduZXJMaW1pdHMAAAfQAAAADVNpZ25lclN0b3JhZ2UAAAAAAAABAAAAAAAAAAlTZWNwMjU2cjEAAAAAAAAEAAAADgAAA+4AAABBAAAH0AAAAAxTaWduZXJMaW1pdHMAAAfQAAAADVNpZ25lclN0b3JhZ2UAAAA=",
99
+ "AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAAAgAAAAAAAAAOTm90SW5pdGlhbGl6ZWQAAAAAAAEAAAAAAAAAEkFscmVhZHlJbml0aWFsaXplZAAAAAAAAg==",
72
100
  "AAAAAAAAAAAAAAAEaW5pdAAAAAEAAAAAAAAACXdhc21faGFzaAAAAAAAA+4AAAAgAAAAAQAAA+kAAAPtAAAAAAAAAAM=",
73
- "AAAAAAAAAAAAAAAGZGVwbG95AAAAAAADAAAAAAAAAARzYWx0AAAD7gAAACAAAAAAAAAAAmlkAAAAAAAOAAAAAAAAAAJwawAAAAAD7gAAAEEAAAABAAAD6QAAABMAAAAD"]),
101
+ "AAAAAAAAAAAAAAAGZGVwbG95AAAAAAACAAAAAAAAAARzYWx0AAAD7gAAACAAAAAAAAAABnNpZ25lcgAAAAAH0AAAAAZTaWduZXIAAAAAAAEAAAPpAAAAEwAAAAM="]),
74
102
  options
75
103
  )
76
104
  }
@@ -1,11 +1,40 @@
1
1
  import { Buffer } from "buffer";
2
2
  import { AssembledTransaction, Client as ContractClient, ClientOptions as ContractClientOptions, Result } from '@stellar/stellar-sdk/contract';
3
+ import type { Option } from '@stellar/stellar-sdk/contract';
3
4
  export declare const networks: {
4
5
  readonly testnet: {
5
6
  readonly networkPassphrase: "Test SDF Network ; September 2015";
6
- readonly contractId: "CCPLERXCJZB7LX2VOSOCBNRN754FRLHI6Y2AVOQBA5L7C2ZJX5RFVVET";
7
+ readonly contractId: "CA3WONARSZHZQCCM5WF5HLD27MIP7RWCQJMID4TLZIWPHQYGJT2CIYWX";
7
8
  };
8
9
  };
10
+ export type SignerLimits = readonly [Map<string, Option<Array<SignerKey>>>];
11
+ export type SignerKey = {
12
+ tag: "Policy";
13
+ values: readonly [string];
14
+ } | {
15
+ tag: "Ed25519";
16
+ values: readonly [Buffer];
17
+ } | {
18
+ tag: "Secp256r1";
19
+ values: readonly [Buffer];
20
+ };
21
+ export type SignerStorage = {
22
+ tag: "Persistent";
23
+ values: void;
24
+ } | {
25
+ tag: "Temporary";
26
+ values: void;
27
+ };
28
+ export type Signer = {
29
+ tag: "Policy";
30
+ values: readonly [string, SignerLimits, SignerStorage];
31
+ } | {
32
+ tag: "Ed25519";
33
+ values: readonly [Buffer, SignerLimits, SignerStorage];
34
+ } | {
35
+ tag: "Secp256r1";
36
+ values: readonly [Buffer, Buffer, SignerLimits, SignerStorage];
37
+ };
9
38
  export declare const Errors: {
10
39
  1: {
11
40
  message: string;
@@ -37,10 +66,9 @@ export interface Client {
37
66
  /**
38
67
  * Construct and simulate a deploy transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
39
68
  */
40
- deploy: ({ salt, id, pk }: {
69
+ deploy: ({ salt, signer }: {
41
70
  salt: Buffer;
42
- id: Buffer;
43
- pk: Buffer;
71
+ signer: Signer;
44
72
  }, options?: {
45
73
  /**
46
74
  * The fee to pay for the transaction. Default: BASE_FEE
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.2.1",
2
+ "version": "0.3.1",
3
3
  "name": "passkey-kit-sdk",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
@@ -10,9 +10,9 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "buffer": "6.0.3",
13
- "@stellar/stellar-sdk": "12.1.0"
13
+ "@stellar/stellar-sdk": "12.3.0"
14
14
  },
15
15
  "devDependencies": {
16
- "typescript": "5.5.3"
16
+ "typescript": "5.6.2"
17
17
  }
18
18
  }
@@ -1,4 +1,5 @@
1
1
  import { Buffer } from "buffer";
2
+ import { Address } from '@stellar/stellar-sdk';
2
3
  import {
3
4
  AssembledTransaction,
4
5
  Client as ContractClient,
@@ -6,41 +7,72 @@ import {
6
7
  Result,
7
8
  Spec as ContractSpec,
8
9
  } from '@stellar/stellar-sdk/contract';
10
+ import type {
11
+ u32,
12
+ i32,
13
+ u64,
14
+ i64,
15
+ u128,
16
+ i128,
17
+ u256,
18
+ i256,
19
+ Option,
20
+ Typepoint,
21
+ Duration,
22
+ } from '@stellar/stellar-sdk/contract';
9
23
 
10
24
  if (typeof window !== 'undefined') {
11
25
  //@ts-ignore Buffer exists
12
26
  window.Buffer = window.Buffer || Buffer;
13
27
  }
14
28
 
29
+
15
30
  export const networks = {
16
31
  testnet: {
17
32
  networkPassphrase: "Test SDF Network ; September 2015",
18
- contractId: "CCPLERXCJZB7LX2VOSOCBNRN754FRLHI6Y2AVOQBA5L7C2ZJX5RFVVET",
33
+ contractId: "CA3WONARSZHZQCCM5WF5HLD27MIP7RWCQJMID4TLZIWPHQYGJT2CIYWX",
19
34
  }
20
35
  } as const
21
36
 
22
37
  export const Errors = {
23
38
  1: { message: "NotFound" },
24
- 2: { message: "NotPermitted" },
25
- 3: { message: "ClientDataJsonChallengeIncorrect" },
26
- 4: { message: "Secp256r1PublicKeyParse" },
27
- 5: { message: "Secp256r1SignatureParse" },
28
- 6: { message: "Secp256r1VerifyFailed" },
39
+
40
+ 2: { message: "MissingContext" },
41
+
42
+ 3: { message: "MissingSignerLimits" },
43
+
44
+ 4: { message: "FailedPolicySignerLimits" },
45
+
46
+ 5: { message: "SignatureKeyValueMismatch" },
47
+
48
+ 6: { message: "ClientDataJsonChallengeIncorrect" },
49
+
29
50
  7: { message: "JsonParseError" }
30
51
  }
52
+ export type SignerLimits = readonly [Map<string, Option<Array<SignerKey>>>];
53
+ export type SignerKey = { tag: "Policy", values: readonly [string] } | { tag: "Ed25519", values: readonly [Buffer] } | { tag: "Secp256r1", values: readonly [Buffer] };
31
54
 
32
- export interface Signature {
55
+ export type SignerVal = { tag: "Policy", values: readonly [SignerLimits] } | { tag: "Ed25519", values: readonly [SignerLimits] } | { tag: "Secp256r1", values: readonly [Buffer, SignerLimits] };
56
+
57
+ export type SignerStorage = { tag: "Persistent", values: void } | { tag: "Temporary", values: void };
58
+
59
+ export type Signer = { tag: "Policy", values: readonly [string, SignerLimits, SignerStorage] } | { tag: "Ed25519", values: readonly [Buffer, SignerLimits, SignerStorage] } | { tag: "Secp256r1", values: readonly [Buffer, Buffer, SignerLimits, SignerStorage] };
60
+
61
+
62
+ export interface Secp256r1Signature {
33
63
  authenticator_data: Buffer;
34
64
  client_data_json: Buffer;
35
- id: Buffer;
36
65
  signature: Buffer;
37
66
  }
38
67
 
68
+ export type Signature = { tag: "Ed25519", values: readonly [Buffer] } | { tag: "Secp256r1", values: readonly [Secp256r1Signature] };
69
+
70
+
39
71
  export interface Client {
40
72
  /**
41
73
  * Construct and simulate a add transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
42
74
  */
43
- add: ({ id, pk, admin }: { id: Buffer, pk: Buffer, admin: boolean }, options?: {
75
+ add: ({ signer }: { signer: Signer }, options?: {
44
76
  /**
45
77
  * The fee to pay for the transaction. Default: BASE_FEE
46
78
  */
@@ -60,7 +92,7 @@ export interface Client {
60
92
  /**
61
93
  * Construct and simulate a remove transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
62
94
  */
63
- remove: ({ id }: { id: Buffer }, options?: {
95
+ remove: ({ signer_key }: { signer_key: SignerKey }, options?: {
64
96
  /**
65
97
  * The fee to pay for the transaction. Default: BASE_FEE
66
98
  */
@@ -96,16 +128,23 @@ export interface Client {
96
128
  */
97
129
  simulate?: boolean;
98
130
  }) => Promise<AssembledTransaction<Result<void>>>
131
+
99
132
  }
100
133
  export class Client extends ContractClient {
101
134
  constructor(public readonly options: ContractClientOptions) {
102
135
  super(
103
- new ContractSpec(["AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAABwAAAAAAAAAITm90Rm91bmQAAAABAAAAAAAAAAxOb3RQZXJtaXR0ZWQAAAACAAAAAAAAACBDbGllbnREYXRhSnNvbkNoYWxsZW5nZUluY29ycmVjdAAAAAMAAAAAAAAAF1NlY3AyNTZyMVB1YmxpY0tleVBhcnNlAAAAAAQAAAAAAAAAF1NlY3AyNTZyMVNpZ25hdHVyZVBhcnNlAAAAAAUAAAAAAAAAFVNlY3AyNTZyMVZlcmlmeUZhaWxlZAAAAAAAAAYAAAAAAAAADkpzb25QYXJzZUVycm9yAAAAAAAH",
104
- "AAAAAAAAAAAAAAADYWRkAAAAAAMAAAAAAAAAAmlkAAAAAAAOAAAAAAAAAAJwawAAAAAD7gAAAEEAAAAAAAAABWFkbWluAAAAAAAAAQAAAAEAAAPpAAAD7QAAAAAAAAAD",
105
- "AAAAAAAAAAAAAAAGcmVtb3ZlAAAAAAABAAAAAAAAAAJpZAAAAAAADgAAAAEAAAPpAAAD7QAAAAAAAAAD",
136
+ new ContractSpec(["AAAABAAAAAAAAAAAAAAABUVycm9yAAAAAAAABwAAAAAAAAAITm90Rm91bmQAAAABAAAAAAAAAA5NaXNzaW5nQ29udGV4dAAAAAAAAgAAAAAAAAATTWlzc2luZ1NpZ25lckxpbWl0cwAAAAADAAAAAAAAABhGYWlsZWRQb2xpY3lTaWduZXJMaW1pdHMAAAAEAAAAAAAAABlTaWduYXR1cmVLZXlWYWx1ZU1pc21hdGNoAAAAAAAABQAAAAAAAAAgQ2xpZW50RGF0YUpzb25DaGFsbGVuZ2VJbmNvcnJlY3QAAAAGAAAAAAAAAA5Kc29uUGFyc2VFcnJvcgAAAAAABw==",
137
+ "AAAAAQAAAAAAAAAAAAAADFNpZ25lckxpbWl0cwAAAAEAAAAAAAAAATAAAAAAAAPsAAAAEwAAA+gAAAPqAAAH0AAAAAlTaWduZXJLZXkAAAA=",
138
+ "AAAAAgAAAAAAAAAAAAAACVNpZ25lcktleQAAAAAAAAMAAAABAAAAAAAAAAZQb2xpY3kAAAAAAAEAAAATAAAAAQAAAAAAAAAHRWQyNTUxOQAAAAABAAAD7gAAACAAAAABAAAAAAAAAAlTZWNwMjU2cjEAAAAAAAABAAAADg==",
139
+ "AAAAAgAAAAAAAAAAAAAACVNpZ25lclZhbAAAAAAAAAMAAAABAAAAAAAAAAZQb2xpY3kAAAAAAAEAAAfQAAAADFNpZ25lckxpbWl0cwAAAAEAAAAAAAAAB0VkMjU1MTkAAAAAAQAAB9AAAAAMU2lnbmVyTGltaXRzAAAAAQAAAAAAAAAJU2VjcDI1NnIxAAAAAAAAAgAAA+4AAABBAAAH0AAAAAxTaWduZXJMaW1pdHM=",
140
+ "AAAAAgAAAAAAAAAAAAAADVNpZ25lclN0b3JhZ2UAAAAAAAACAAAAAAAAAAAAAAAKUGVyc2lzdGVudAAAAAAAAAAAAAAAAAAJVGVtcG9yYXJ5AAAA",
141
+ "AAAAAgAAAAAAAAAAAAAABlNpZ25lcgAAAAAAAwAAAAEAAAAAAAAABlBvbGljeQAAAAAAAwAAABMAAAfQAAAADFNpZ25lckxpbWl0cwAAB9AAAAANU2lnbmVyU3RvcmFnZQAAAAAAAAEAAAAAAAAAB0VkMjU1MTkAAAAAAwAAA+4AAAAgAAAH0AAAAAxTaWduZXJMaW1pdHMAAAfQAAAADVNpZ25lclN0b3JhZ2UAAAAAAAABAAAAAAAAAAlTZWNwMjU2cjEAAAAAAAAEAAAADgAAA+4AAABBAAAH0AAAAAxTaWduZXJMaW1pdHMAAAfQAAAADVNpZ25lclN0b3JhZ2UAAAA=",
142
+ "AAAAAQAAAAAAAAAAAAAAElNlY3AyNTZyMVNpZ25hdHVyZQAAAAAAAwAAAAAAAAASYXV0aGVudGljYXRvcl9kYXRhAAAAAAAOAAAAAAAAABBjbGllbnRfZGF0YV9qc29uAAAADgAAAAAAAAAJc2lnbmF0dXJlAAAAAAAD7gAAAEA=",
143
+ "AAAAAgAAAAAAAAAAAAAACVNpZ25hdHVyZQAAAAAAAAIAAAABAAAAAAAAAAdFZDI1NTE5AAAAAAEAAAPuAAAAQAAAAAEAAAAAAAAACVNlY3AyNTZyMQAAAAAAAAEAAAfQAAAAElNlY3AyNTZyMVNpZ25hdHVyZQAA",
144
+ "AAAAAAAAAAAAAAADYWRkAAAAAAEAAAAAAAAABnNpZ25lcgAAAAAH0AAAAAZTaWduZXIAAAAAAAEAAAPpAAAD7QAAAAAAAAAD",
145
+ "AAAAAAAAAAAAAAAGcmVtb3ZlAAAAAAABAAAAAAAAAApzaWduZXJfa2V5AAAAAAfQAAAACVNpZ25lcktleQAAAAAAAAEAAAPpAAAD7QAAAAAAAAAD",
106
146
  "AAAAAAAAAAAAAAAGdXBkYXRlAAAAAAABAAAAAAAAAARoYXNoAAAD7gAAACAAAAABAAAD6QAAA+0AAAAAAAAAAw==",
107
- "AAAAAQAAAAAAAAAAAAAACVNpZ25hdHVyZQAAAAAAAAQAAAAAAAAAEmF1dGhlbnRpY2F0b3JfZGF0YQAAAAAADgAAAAAAAAAQY2xpZW50X2RhdGFfanNvbgAAAA4AAAAAAAAAAmlkAAAAAAAOAAAAAAAAAAlzaWduYXR1cmUAAAAAAAPuAAAAQA==",
108
- "AAAAAAAAAAAAAAAMX19jaGVja19hdXRoAAAAAwAAAAAAAAARc2lnbmF0dXJlX3BheWxvYWQAAAAAAAPuAAAAIAAAAAAAAAAJc2lnbmF0dXJlAAAAAAAH0AAAAAlTaWduYXR1cmUAAAAAAAAAAAAADWF1dGhfY29udGV4dHMAAAAAAAPqAAAH0AAAAAdDb250ZXh0AAAAAAEAAAPpAAAD7QAAAAAAAAAD"]),
147
+ "AAAAAAAAAAAAAAAMX19jaGVja19hdXRoAAAAAwAAAAAAAAARc2lnbmF0dXJlX3BheWxvYWQAAAAAAAPuAAAAIAAAAAAAAAAKc2lnbmF0dXJlcwAAAAAD7AAAB9AAAAAJU2lnbmVyS2V5AAAAAAAD6AAAB9AAAAAJU2lnbmF0dXJlAAAAAAAAAAAAAA1hdXRoX2NvbnRleHRzAAAAAAAD6gAAB9AAAAAHQ29udGV4dAAAAAABAAAD6QAAA+0AAAAAAAAAAw=="]),
109
148
  options
110
149
  )
111
150
  }
@@ -1,9 +1,10 @@
1
1
  import { Buffer } from "buffer";
2
2
  import { AssembledTransaction, Client as ContractClient, ClientOptions as ContractClientOptions, Result } from '@stellar/stellar-sdk/contract';
3
+ import type { Option } from '@stellar/stellar-sdk/contract';
3
4
  export declare const networks: {
4
5
  readonly testnet: {
5
6
  readonly networkPassphrase: "Test SDF Network ; September 2015";
6
- readonly contractId: "CCPLERXCJZB7LX2VOSOCBNRN754FRLHI6Y2AVOQBA5L7C2ZJX5RFVVET";
7
+ readonly contractId: "CA3WONARSZHZQCCM5WF5HLD27MIP7RWCQJMID4TLZIWPHQYGJT2CIYWX";
7
8
  };
8
9
  };
9
10
  export declare const Errors: {
@@ -29,20 +30,62 @@ export declare const Errors: {
29
30
  message: string;
30
31
  };
31
32
  };
32
- export interface Signature {
33
+ export type SignerLimits = readonly [Map<string, Option<Array<SignerKey>>>];
34
+ export type SignerKey = {
35
+ tag: "Policy";
36
+ values: readonly [string];
37
+ } | {
38
+ tag: "Ed25519";
39
+ values: readonly [Buffer];
40
+ } | {
41
+ tag: "Secp256r1";
42
+ values: readonly [Buffer];
43
+ };
44
+ export type SignerVal = {
45
+ tag: "Policy";
46
+ values: readonly [SignerLimits];
47
+ } | {
48
+ tag: "Ed25519";
49
+ values: readonly [SignerLimits];
50
+ } | {
51
+ tag: "Secp256r1";
52
+ values: readonly [Buffer, SignerLimits];
53
+ };
54
+ export type SignerStorage = {
55
+ tag: "Persistent";
56
+ values: void;
57
+ } | {
58
+ tag: "Temporary";
59
+ values: void;
60
+ };
61
+ export type Signer = {
62
+ tag: "Policy";
63
+ values: readonly [string, SignerLimits, SignerStorage];
64
+ } | {
65
+ tag: "Ed25519";
66
+ values: readonly [Buffer, SignerLimits, SignerStorage];
67
+ } | {
68
+ tag: "Secp256r1";
69
+ values: readonly [Buffer, Buffer, SignerLimits, SignerStorage];
70
+ };
71
+ export interface Secp256r1Signature {
33
72
  authenticator_data: Buffer;
34
73
  client_data_json: Buffer;
35
- id: Buffer;
36
74
  signature: Buffer;
37
75
  }
76
+ export type Signature = {
77
+ tag: "Ed25519";
78
+ values: readonly [Buffer];
79
+ } | {
80
+ tag: "Secp256r1";
81
+ values: readonly [Secp256r1Signature];
82
+ };
38
83
  export interface Client {
39
84
  /**
40
85
  * Construct and simulate a add transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
41
86
  */
42
- add: ({ id, pk, admin }: {
43
- id: Buffer;
44
- pk: Buffer;
45
- admin: boolean;
87
+ add: ({ signer }: {
88
+ signer: Signer;
46
89
  }, options?: {
47
90
  /**
48
91
  * The fee to pay for the transaction. Default: BASE_FEE
@@ -60,8 +103,8 @@ export interface Client {
60
103
  /**
61
104
  * Construct and simulate a remove transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object.
62
105
  */
63
- remove: ({ id }: {
64
- id: Buffer;
106
+ remove: ({ signer_key }: {
107
+ signer_key: SignerKey;
65
108
  }, options?: {
66
109
  /**
67
110
  * The fee to pay for the transaction. Default: BASE_FEE
@@ -10,9 +10,9 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "buffer": "6.0.3",
13
- "@stellar/stellar-sdk": "12.1.0"
13
+ "@stellar/stellar-sdk": "12.3.0"
14
14
  },
15
15
  "devDependencies": {
16
- "typescript": "5.5.3"
16
+ "typescript": "5.6.2"
17
17
  }
18
18
  }
@@ -1,13 +1,24 @@
1
1
  import { Buffer } from "buffer";
2
+ import { Address } from '@stellar/stellar-sdk';
2
3
  import {
3
4
  AssembledTransaction,
4
5
  Client as ContractClient,
5
6
  ClientOptions as ContractClientOptions,
7
+ Result,
6
8
  Spec as ContractSpec,
7
9
  } from '@stellar/stellar-sdk/contract';
8
10
  import type {
9
11
  u32,
12
+ i32,
13
+ u64,
14
+ i64,
15
+ u128,
10
16
  i128,
17
+ u256,
18
+ i256,
19
+ Option,
20
+ Typepoint,
21
+ Duration,
11
22
  } from '@stellar/stellar-sdk/contract';
12
23
 
13
24
  if (typeof window !== 'undefined') {
@@ -15,6 +26,7 @@ if (typeof window !== 'undefined') {
15
26
  window.Buffer = window.Buffer || Buffer;
16
27
  }
17
28
 
29
+
18
30
  export const networks = {
19
31
  testnet: {
20
32
  networkPassphrase: "Test SDF Network ; September 2015",
@@ -529,6 +541,7 @@ export interface Client {
529
541
  */
530
542
  simulate?: boolean;
531
543
  }) => Promise<AssembledTransaction<null>>
544
+
532
545
  }
533
546
  export class Client extends ContractClient {
534
547
  constructor(public readonly options: ContractClientOptions) {
package/src/base.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import { SorobanRpc } from "@stellar/stellar-sdk"
2
2
 
3
+ // TODO consider adding support for a signAuthEntry method that conforms to the ed25519 signature scheme of this passkey interface
4
+ // once we do that we can clean the code a little with the `xdr.HashIdPreimage.envelopeTypeSorobanAuthorization` stuff
5
+ // ... note I've re-read the above and I've currently got no clue what this is asking for. Maybe check git-blame for when it was added to try and find some context
6
+ // actually this is just talking about adding support for signing transactions with an ed25519 key as well as a passkey. Simple enough
7
+
3
8
  export class PasskeyBase {
4
9
  public rpcUrl: string | undefined
5
10
  public rpc: SorobanRpc.Server | undefined
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PasskeyServer } from "./server"
2
- import { PasskeyKit } from "./kit"
2
+ import { PasskeyKit, DEFAULT_LTL } from "./kit"
3
3
  import { SACClient } from "./sac"
4
4
 
5
- export { PasskeyServer, PasskeyKit, SACClient }
5
+ export { PasskeyServer, PasskeyKit, SACClient, DEFAULT_LTL }
package/src/kit.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Client as PasskeyClient } from 'passkey-kit-sdk'
1
+ import { Client as PasskeyClient, type Secp256r1Signature, type Signature } from 'passkey-kit-sdk'
2
2
  import { Client as FactoryClient } from 'passkey-factory-sdk'
3
3
  import { Address, StrKey, hash, xdr, Transaction, SorobanRpc, Operation, TransactionBuilder } from '@stellar/stellar-sdk'
4
4
  import base64url from 'base64url'
@@ -6,7 +6,8 @@ import { startRegistration, startAuthentication } from "@simplewebauthn/browser"
6
6
  import type { AuthenticatorAttestationResponseJSON, AuthenticatorSelectionCriteria } from "@simplewebauthn/types"
7
7
  import { Buffer } from 'buffer'
8
8
  import { PasskeyBase } from './base'
9
- import { DEFAULT_TIMEOUT } from '@stellar/stellar-sdk/contract'
9
+
10
+ export const DEFAULT_LTL = 12
10
11
 
11
12
  export class PasskeyKit extends PasskeyBase {
12
13
  declare public rpc: SorobanRpc.Server
@@ -47,10 +48,23 @@ export class PasskeyKit extends PasskeyBase {
47
48
 
48
49
  const { result, built } = await this.factory.deploy({
49
50
  salt: hash(keyId),
50
- id: keyId,
51
- pk: publicKey
51
+ signer: {
52
+ tag: 'Secp256r1',
53
+ values: [
54
+ keyId,
55
+ publicKey,
56
+ [new Map()],
57
+ {tag: 'Persistent', values: undefined},
58
+ ]
59
+ },
52
60
  })
53
61
 
62
+ if (result.isErr())
63
+ throw new Error(result.unwrapErr().message)
64
+
65
+ if (!built)
66
+ throw new Error('Failed to create wallet')
67
+
54
68
  const contractId = result.unwrap()
55
69
 
56
70
  this.wallet = new PasskeyClient({
@@ -62,7 +76,7 @@ export class PasskeyKit extends PasskeyBase {
62
76
  return {
63
77
  keyId,
64
78
  contractId,
65
- xdr: built?.toXDR()
79
+ xdr: built.toXDR()
66
80
  }
67
81
  }
68
82
 
@@ -157,7 +171,7 @@ export class PasskeyKit extends PasskeyBase {
157
171
  }
158
172
 
159
173
  if (!contractId)
160
- throw new Error('No `contractId` was found')
174
+ throw new Error('Failed to connect wallet')
161
175
 
162
176
  this.wallet = new PasskeyClient({
163
177
  contractId,
@@ -179,7 +193,7 @@ export class PasskeyKit extends PasskeyBase {
179
193
  ledgersToLive?: number
180
194
  }
181
195
  ) {
182
- let { keyId, rpId, ledgersToLive = DEFAULT_TIMEOUT } = options || {}
196
+ let { keyId, rpId, ledgersToLive = DEFAULT_LTL } = options || {}
183
197
 
184
198
  const lastLedger = await this.rpc.getLatestLedger().then(({ sequence }) => sequence)
185
199
  const credentials = entry.credentials().address();
@@ -187,6 +201,8 @@ export class PasskeyKit extends PasskeyBase {
187
201
  new xdr.HashIdPreimageSorobanAuthorization({
188
202
  networkId: hash(Buffer.from(this.networkPassphrase)),
189
203
  nonce: credentials.nonce(),
204
+ // TODO maybe if folks set `ledgersToLive` that should be the TTL vs the extension from `lastLedger`. Will make it easier to coordinate multisig
205
+ // Call it `validUntilLedgerSeq` like the JS SDK
190
206
  signatureExpirationLedger: lastLedger + ledgersToLive,
191
207
  invocation: entry.rootInvocation()
192
208
  })
@@ -222,25 +238,48 @@ export class PasskeyKit extends PasskeyBase {
222
238
  base64url.toBuffer(authenticationResponse.response.signature)
223
239
  );
224
240
 
225
- credentials.signatureExpirationLedger(lastLedger + ledgersToLive)
226
- credentials.signature(xdr.ScVal.scvMap([
227
- new xdr.ScMapEntry({
228
- key: xdr.ScVal.scvSymbol('authenticator_data'),
229
- val: xdr.ScVal.scvBytes(base64url.toBuffer(authenticationResponse.response.authenticatorData)),
230
- }),
241
+ // TODO No idea how to make this work
242
+ // https://discord.com/channels/@me/1025113063583666246/1281789018979438672
243
+ // const t: Signature = {
244
+ // tag: 'Secp256r1',
245
+ // values: [{
246
+ // authenticator_data: base64url.toBuffer(authenticationResponse.response.authenticatorData),
247
+ // client_data_json: base64url.toBuffer(authenticationResponse.response.clientDataJSON),
248
+ // id: [base64url.toBuffer(authenticationResponse.id)],
249
+ // signature
250
+ // }]
251
+ // }
252
+
253
+ // const test = this.wallet!.spec.nativeToScVal(t, )
254
+
255
+ const sig = xdr.ScVal.scvMap([
231
256
  new xdr.ScMapEntry({
232
- key: xdr.ScVal.scvSymbol('client_data_json'),
233
- val: xdr.ScVal.scvBytes(base64url.toBuffer(authenticationResponse.response.clientDataJSON)),
234
- }),
235
- new xdr.ScMapEntry({
236
- key: xdr.ScVal.scvSymbol('id'),
237
- val: xdr.ScVal.scvBytes(base64url.toBuffer(authenticationResponse.id)),
238
- }),
239
- new xdr.ScMapEntry({
240
- key: xdr.ScVal.scvSymbol('signature'),
241
- val: xdr.ScVal.scvBytes(signature),
242
- }),
243
- ]))
257
+ key: xdr.ScVal.scvVec([
258
+ xdr.ScVal.scvSymbol('Secp256r1'),
259
+ xdr.ScVal.scvBytes(base64url.toBuffer(authenticationResponse.id))
260
+ ]),
261
+ val: xdr.ScVal.scvVec([
262
+ xdr.ScVal.scvSymbol('Secp256r1'),
263
+ xdr.ScVal.scvMap([
264
+ new xdr.ScMapEntry({
265
+ key: xdr.ScVal.scvSymbol('authenticator_data'),
266
+ val: xdr.ScVal.scvBytes(base64url.toBuffer(authenticationResponse.response.authenticatorData)),
267
+ }),
268
+ new xdr.ScMapEntry({
269
+ key: xdr.ScVal.scvSymbol('client_data_json'),
270
+ val: xdr.ScVal.scvBytes(base64url.toBuffer(authenticationResponse.response.clientDataJSON)),
271
+ }),
272
+ new xdr.ScMapEntry({
273
+ key: xdr.ScVal.scvSymbol('signature'),
274
+ val: xdr.ScVal.scvBytes(signature),
275
+ }),
276
+ ])
277
+ ])
278
+ })
279
+ ])
280
+
281
+ credentials.signatureExpirationLedger(lastLedger + ledgersToLive)
282
+ credentials.signature(sig)
244
283
 
245
284
  return entry
246
285
  }
@@ -362,7 +401,7 @@ export class PasskeyKit extends PasskeyBase {
362
401
 
363
402
  /* TODO
364
403
  - We're doing some pretty "smart" public key decoding stuff so we should verify the signature against this final public key before assuming it's safe to use and save on-chain
365
- Given that `startRegistration` doesn't produce a signature, verifying we've got the correct public key isn't really possible
404
+ Hmm...Given that `startRegistration` doesn't produce a signature, verifying we've got the correct public key isn't really possible
366
405
  @Later
367
406
  */
368
407
 
package/src/server.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { SorobanRpc, xdr } from "@stellar/stellar-sdk"
2
- import base64url from "base64url"
3
2
  import { PasskeyBase } from "./base"
3
+ import base64url from "base64url"
4
4
 
5
5
  export class PasskeyServer extends PasskeyBase {
6
6
  public launchtubeUrl: string | undefined
@@ -49,7 +49,7 @@ export class PasskeyServer extends PasskeyBase {
49
49
  Authorization: `Bearer ${this.mercuryJwt}`
50
50
  },
51
51
  body: JSON.stringify({
52
- project_name: 'smart-wallets-data',
52
+ project_name: 'smart-wallets-data-multi-signer-multi-sig',
53
53
  mode: {
54
54
  Function: {
55
55
  fname: "get_signers_by_address",
@@ -70,17 +70,20 @@ export class PasskeyServer extends PasskeyBase {
70
70
  for (const signer of signers) {
71
71
  if (!signer.admin) {
72
72
  try {
73
- await this.rpc.getContractData(contractId, xdr.ScVal.scvBytes(signer.id), SorobanRpc.Durability.Temporary)
73
+ await this.rpc.getContractData(contractId, xdr.ScVal.scvBytes(base64url.toBuffer(signer.key)), SorobanRpc.Durability.Temporary)
74
74
  } catch {
75
75
  signer.expired = true
76
76
  }
77
77
  }
78
-
79
- signer.id = base64url(signer.id)
80
- signer.pk = base64url(signer.pk)
81
78
  }
82
79
 
83
- return signers as { id: string, pk: string, admin: boolean, expired?: boolean }[]
80
+ return signers as {
81
+ kind: string,
82
+ key: string,
83
+ val: string,
84
+ limits: string,
85
+ expired?: boolean
86
+ }[]
84
87
  }
85
88
 
86
89
  public async getContractId(keyId: string) {
@@ -94,12 +97,13 @@ export class PasskeyServer extends PasskeyBase {
94
97
  Authorization: `Bearer ${this.mercuryJwt}`
95
98
  },
96
99
  body: JSON.stringify({
97
- project_name: 'smart-wallets-data',
100
+ project_name: 'smart-wallets-data-multi-signer-multi-sig',
98
101
  mode: {
99
102
  Function: {
100
103
  fname: "get_address_by_signer",
101
104
  arguments: JSON.stringify({
102
- id: [...base64url.toBuffer(keyId)]
105
+ key: keyId,
106
+ kind: 'Secp256r1'
103
107
  })
104
108
  }
105
109
  }
@@ -112,7 +116,7 @@ export class PasskeyServer extends PasskeyBase {
112
116
  throw await res.json()
113
117
  })
114
118
 
115
- return res[0]?.address as string | undefined
119
+ return res || undefined as string | undefined
116
120
  }
117
121
 
118
122
  /* TODO
package/types/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { PasskeyServer } from "./server";
2
- import { PasskeyKit } from "./kit";
2
+ import { PasskeyKit, DEFAULT_LTL } from "./kit";
3
3
  import { SACClient } from "./sac";
4
- export { PasskeyServer, PasskeyKit, SACClient };
4
+ export { PasskeyServer, PasskeyKit, SACClient, DEFAULT_LTL };
package/types/kit.d.ts CHANGED
@@ -5,6 +5,7 @@ import { startRegistration, startAuthentication } from "@simplewebauthn/browser"
5
5
  import type { AuthenticatorSelectionCriteria } from "@simplewebauthn/types";
6
6
  import { Buffer } from 'buffer';
7
7
  import { PasskeyBase } from './base';
8
+ export declare const DEFAULT_LTL = 12;
8
9
  export declare class PasskeyKit extends PasskeyBase {
9
10
  rpc: SorobanRpc.Server;
10
11
  rpcUrl: string;
@@ -28,7 +29,7 @@ export declare class PasskeyKit extends PasskeyBase {
28
29
  createWallet(app: string, user: string): Promise<{
29
30
  keyId: Buffer;
30
31
  contractId: string;
31
- xdr: string | undefined;
32
+ xdr: string;
32
33
  }>;
33
34
  createKey(app: string, user: string, settings?: {
34
35
  rpId?: string;
package/types/server.d.ts CHANGED
@@ -12,11 +12,12 @@ export declare class PasskeyServer extends PasskeyBase {
12
12
  mercuryJwt?: string;
13
13
  });
14
14
  getSigners(contractId: string): Promise<{
15
- id: string;
16
- pk: string;
17
- admin: boolean;
15
+ kind: string;
16
+ key: string;
17
+ val: string;
18
+ limits: string;
18
19
  expired?: boolean;
19
20
  }[]>;
20
- getContractId(keyId: string): Promise<string | undefined>;
21
+ getContractId(keyId: string): Promise<any>;
21
22
  send(xdr: string, fee?: number): Promise<any>;
22
23
  }