passkey-kit 0.4.6 → 0.5.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.
- package/README.md +39 -5
- package/package.json +6 -4
- package/packages/sac-sdk/README.md +54 -0
- package/packages/sac-sdk/package.json +18 -0
- package/packages/sac-sdk/src/index.ts +573 -0
- package/packages/sac-sdk/tsconfig.json +98 -0
- package/packages/sac-sdk/types/index.d.ts +527 -0
- package/pnpm-workspace.yaml +2 -1
- package/src/base.ts +4 -180
- package/src/index.ts +3 -2
- package/src/kit.ts +8 -20
- package/src/sac.ts +94 -0
- package/src/server.ts +191 -0
- package/tsconfig.json +8 -5
- package/types/base.d.ts +2 -25
- package/types/index.d.ts +3 -2
- package/types/kit.d.ts +3 -7
- package/types/sac.d.ts +12 -0
- package/types/server.d.ts +27 -0
- package/types/src/base.d.ts +0 -9
- package/types/src/index.d.ts +0 -3
- package/types/src/kit.d.ts +0 -53
- package/types/tests/index.d.ts +0 -1
package/src/base.ts
CHANGED
|
@@ -1,189 +1,13 @@
|
|
|
1
|
-
import { SorobanRpc
|
|
2
|
-
import base64url from "base64url"
|
|
1
|
+
import { SorobanRpc } from "@stellar/stellar-sdk"
|
|
3
2
|
|
|
4
3
|
export class PasskeyBase {
|
|
5
|
-
public rpc: SorobanRpc.Server | undefined
|
|
6
4
|
public rpcUrl: string | undefined
|
|
7
|
-
public
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
public mercuryJwt: string | undefined
|
|
11
|
-
public mercuryEmail: string | undefined
|
|
12
|
-
public mercuryPassword: string | undefined
|
|
13
|
-
|
|
14
|
-
constructor(options: {
|
|
15
|
-
rpcUrl?: string,
|
|
16
|
-
launchtubeUrl?: string,
|
|
17
|
-
launchtubeJwt?: string,
|
|
18
|
-
mercuryUrl?: string,
|
|
19
|
-
mercuryJwt?: string,
|
|
20
|
-
mercuryEmail?: string,
|
|
21
|
-
mercuryPassword?: string
|
|
22
|
-
}) {
|
|
23
|
-
const {
|
|
24
|
-
rpcUrl,
|
|
25
|
-
launchtubeUrl,
|
|
26
|
-
launchtubeJwt,
|
|
27
|
-
mercuryUrl,
|
|
28
|
-
mercuryJwt,
|
|
29
|
-
mercuryEmail,
|
|
30
|
-
mercuryPassword
|
|
31
|
-
} = options
|
|
32
|
-
|
|
33
|
-
if (launchtubeUrl)
|
|
34
|
-
this.launchtubeUrl = launchtubeUrl
|
|
35
|
-
|
|
36
|
-
if (launchtubeJwt)
|
|
37
|
-
this.launchtubeJwt = launchtubeJwt
|
|
38
|
-
|
|
39
|
-
if (mercuryUrl)
|
|
40
|
-
this.mercuryUrl = mercuryUrl
|
|
41
|
-
|
|
42
|
-
if (mercuryJwt)
|
|
43
|
-
this.mercuryJwt = mercuryJwt
|
|
44
|
-
|
|
45
|
-
if (mercuryEmail)
|
|
46
|
-
this.mercuryEmail = mercuryEmail
|
|
47
|
-
|
|
48
|
-
if (mercuryPassword)
|
|
49
|
-
this.mercuryPassword = mercuryPassword
|
|
50
|
-
|
|
5
|
+
public rpc: SorobanRpc.Server | undefined
|
|
6
|
+
|
|
7
|
+
constructor(rpcUrl?: string) {
|
|
51
8
|
if (rpcUrl) {
|
|
52
9
|
this.rpcUrl = rpcUrl
|
|
53
10
|
this.rpc = new SorobanRpc.Server(rpcUrl)
|
|
54
11
|
}
|
|
55
12
|
}
|
|
56
|
-
|
|
57
|
-
public async setMercuryJwt() {
|
|
58
|
-
if (!this.mercuryUrl || !this.mercuryEmail || !this.mercuryPassword)
|
|
59
|
-
throw new Error('Mercury service not configured')
|
|
60
|
-
|
|
61
|
-
const { data: { authenticate: { jwtToken } } } = await fetch(`${this.mercuryUrl}/graphql`, {
|
|
62
|
-
method: 'POST',
|
|
63
|
-
headers: {
|
|
64
|
-
'Content-Type': 'application/json',
|
|
65
|
-
},
|
|
66
|
-
body: JSON.stringify({
|
|
67
|
-
query: `mutation {
|
|
68
|
-
authenticate(input: {
|
|
69
|
-
email: "${this.mercuryEmail}"
|
|
70
|
-
password: "${this.mercuryPassword}"
|
|
71
|
-
}) {
|
|
72
|
-
jwtToken
|
|
73
|
-
}
|
|
74
|
-
}`
|
|
75
|
-
})
|
|
76
|
-
})
|
|
77
|
-
.then(async (res) => {
|
|
78
|
-
if (res.ok)
|
|
79
|
-
return res.json()
|
|
80
|
-
|
|
81
|
-
throw await res.json()
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
this.mercuryJwt = jwtToken
|
|
85
|
-
return jwtToken
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public async getSigners(contractId: string) {
|
|
89
|
-
if (!this.rpc || !this.mercuryUrl || !this.mercuryJwt)
|
|
90
|
-
throw new Error('Mercury service not configured')
|
|
91
|
-
|
|
92
|
-
const signers = await fetch(`${this.mercuryUrl}/zephyr/execute`, {
|
|
93
|
-
method: 'POST',
|
|
94
|
-
headers: {
|
|
95
|
-
'Content-Type': 'application/json',
|
|
96
|
-
Authorization: `Bearer ${this.mercuryJwt}`
|
|
97
|
-
},
|
|
98
|
-
body: JSON.stringify({
|
|
99
|
-
mode: {
|
|
100
|
-
Function: {
|
|
101
|
-
fname: "get_signers_by_address",
|
|
102
|
-
arguments: JSON.stringify({
|
|
103
|
-
address: contractId
|
|
104
|
-
})
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
})
|
|
109
|
-
.then(async (res) => {
|
|
110
|
-
if (res.ok)
|
|
111
|
-
return res.json()
|
|
112
|
-
|
|
113
|
-
throw await res.json()
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
for (const signer of signers) {
|
|
117
|
-
if (!signer.admin) {
|
|
118
|
-
try {
|
|
119
|
-
await this.rpc.getContractData(contractId, xdr.ScVal.scvBytes(signer.id), SorobanRpc.Durability.Temporary)
|
|
120
|
-
} catch {
|
|
121
|
-
signer.expired = true
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
signer.id = base64url(signer.id)
|
|
126
|
-
signer.pk = base64url(signer.pk)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return signers as { id: string, pk: string, admin: boolean, expired?: boolean }[]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
public async getContractId(keyId: string) {
|
|
133
|
-
if (!this.mercuryUrl || !this.mercuryJwt)
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
const res = await fetch(`${this.mercuryUrl}/zephyr/execute`, {
|
|
137
|
-
method: 'POST',
|
|
138
|
-
headers: {
|
|
139
|
-
'Content-Type': 'application/json',
|
|
140
|
-
Authorization: `Bearer ${this.mercuryJwt}`
|
|
141
|
-
},
|
|
142
|
-
body: JSON.stringify({
|
|
143
|
-
mode: {
|
|
144
|
-
Function: {
|
|
145
|
-
fname: "get_address_by_signer",
|
|
146
|
-
arguments: JSON.stringify({
|
|
147
|
-
id: [...base64url.toBuffer(keyId)]
|
|
148
|
-
})
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
.then(async (res) => {
|
|
154
|
-
if (res.ok)
|
|
155
|
-
return res.json()
|
|
156
|
-
|
|
157
|
-
throw await res.json()
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
return res[0]?.address as string | undefined
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/* TODO
|
|
164
|
-
- Add a method for getting a paginated or filtered list of all a wallet's events
|
|
165
|
-
@Later
|
|
166
|
-
*/
|
|
167
|
-
|
|
168
|
-
public async send(xdr: string, fee: number = 10_000) {
|
|
169
|
-
if (!this.launchtubeUrl || !this.launchtubeJwt)
|
|
170
|
-
throw new Error('Launchtube service not configured')
|
|
171
|
-
|
|
172
|
-
const data = new FormData();
|
|
173
|
-
|
|
174
|
-
data.set('xdr', xdr);
|
|
175
|
-
data.set('fee', fee.toString());
|
|
176
|
-
|
|
177
|
-
return fetch(this.launchtubeUrl, {
|
|
178
|
-
method: 'POST',
|
|
179
|
-
headers: {
|
|
180
|
-
authorization: `Bearer ${this.launchtubeJwt}`,
|
|
181
|
-
},
|
|
182
|
-
body: data
|
|
183
|
-
}).then(async (res) => {
|
|
184
|
-
if (res.ok)
|
|
185
|
-
return res.json()
|
|
186
|
-
else throw await res.json()
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
13
|
}
|
package/src/index.ts
CHANGED
package/src/kit.ts
CHANGED
|
@@ -8,6 +8,8 @@ import { Buffer } from 'buffer'
|
|
|
8
8
|
import { PasskeyBase } from './base'
|
|
9
9
|
|
|
10
10
|
export class PasskeyKit extends PasskeyBase {
|
|
11
|
+
declare public rpc: SorobanRpc.Server
|
|
12
|
+
declare public rpcUrl: string
|
|
11
13
|
public keyId: string | undefined
|
|
12
14
|
public networkPassphrase: string
|
|
13
15
|
public factory: FactoryClient
|
|
@@ -17,22 +19,10 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
17
19
|
rpcUrl: string,
|
|
18
20
|
networkPassphrase: string,
|
|
19
21
|
factoryContractId: string,
|
|
20
|
-
launchtubeUrl?: string,
|
|
21
|
-
launchtubeJwt?: string,
|
|
22
|
-
mercuryUrl?: string,
|
|
23
|
-
mercuryJwt?: string,
|
|
24
|
-
mercuryEmail?: string,
|
|
25
|
-
mercuryPassword?: string
|
|
26
22
|
}) {
|
|
27
23
|
const { rpcUrl, networkPassphrase, factoryContractId } = options
|
|
28
24
|
|
|
29
|
-
super(
|
|
30
|
-
|
|
31
|
-
if (!this.rpcUrl)
|
|
32
|
-
this.rpcUrl = rpcUrl
|
|
33
|
-
|
|
34
|
-
if (!this.rpc)
|
|
35
|
-
this.rpc = new SorobanRpc.Server(rpcUrl)
|
|
25
|
+
super(rpcUrl)
|
|
36
26
|
|
|
37
27
|
this.networkPassphrase = networkPassphrase
|
|
38
28
|
this.factory = new FactoryClient({
|
|
@@ -103,7 +93,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
103
93
|
keyId?: string | Uint8Array,
|
|
104
94
|
getContractId?: (keyId: string) => Promise<string | undefined>
|
|
105
95
|
}) {
|
|
106
|
-
let { keyId, getContractId
|
|
96
|
+
let { keyId, getContractId } = opts || {}
|
|
107
97
|
let keyIdBuffer: Buffer
|
|
108
98
|
|
|
109
99
|
if (!keyId) {
|
|
@@ -114,8 +104,6 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
114
104
|
timeout: 120_000
|
|
115
105
|
});
|
|
116
106
|
|
|
117
|
-
// console.log(response);
|
|
118
|
-
|
|
119
107
|
keyId = response.id
|
|
120
108
|
}
|
|
121
109
|
|
|
@@ -145,11 +133,11 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
145
133
|
// attempt passkey id derivation
|
|
146
134
|
try {
|
|
147
135
|
// TODO what is the error if the entry exists but is archived?
|
|
148
|
-
await this.rpc
|
|
136
|
+
await this.rpc.getContractData(contractId, xdr.ScVal.scvLedgerKeyContractInstance())
|
|
149
137
|
}
|
|
150
138
|
// if that fails look up from the `getContractId` function
|
|
151
139
|
catch {
|
|
152
|
-
contractId = await getContractId(keyId)
|
|
140
|
+
contractId = getContractId ? await getContractId(keyId) : undefined
|
|
153
141
|
}
|
|
154
142
|
|
|
155
143
|
if (!contractId)
|
|
@@ -177,7 +165,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
177
165
|
// Default mirrors DEFAULT_TIMEOUT (currently 5 minutes) https://github.com/stellar/js-stellar-sdk/blob/master/src/contract/utils.ts#L7
|
|
178
166
|
let { keyId, ledgersToLive = 60 } = options || {}
|
|
179
167
|
|
|
180
|
-
const lastLedger = await this.rpc
|
|
168
|
+
const lastLedger = await this.rpc.getLatestLedger().then(({ sequence }) => sequence)
|
|
181
169
|
const credentials = entry.credentials().address();
|
|
182
170
|
const preimage = xdr.HashIdPreimage.envelopeTypeSorobanAuthorization(
|
|
183
171
|
new xdr.HashIdPreimageSorobanAuthorization({
|
|
@@ -300,7 +288,7 @@ export class PasskeyKit extends PasskeyBase {
|
|
|
300
288
|
await this.signAuthEntries(entries, options)
|
|
301
289
|
}
|
|
302
290
|
|
|
303
|
-
const sim = await this.rpc
|
|
291
|
+
const sim = await this.rpc.simulateTransaction(txn)
|
|
304
292
|
|
|
305
293
|
if (
|
|
306
294
|
SorobanRpc.Api.isSimulationError(sim)
|
package/src/sac.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { SorobanRpc } from "@stellar/stellar-sdk"
|
|
2
|
+
import { Client as SacClient } from 'sac-sdk'
|
|
3
|
+
|
|
4
|
+
export class SACClient {
|
|
5
|
+
public networkPassphrase: string
|
|
6
|
+
public rpcUrl: string
|
|
7
|
+
public rpc: SorobanRpc.Server
|
|
8
|
+
|
|
9
|
+
constructor(options: {
|
|
10
|
+
networkPassphrase: string,
|
|
11
|
+
rpcUrl: string
|
|
12
|
+
}) {
|
|
13
|
+
const { networkPassphrase, rpcUrl } = options
|
|
14
|
+
|
|
15
|
+
this.networkPassphrase = networkPassphrase
|
|
16
|
+
this.rpcUrl = rpcUrl
|
|
17
|
+
this.rpc = new SorobanRpc.Server(rpcUrl)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public getSACClient(SACContractId: string) {
|
|
21
|
+
return new SacClient({
|
|
22
|
+
contractId: SACContractId,
|
|
23
|
+
networkPassphrase: this.networkPassphrase,
|
|
24
|
+
rpcUrl: this.rpcUrl
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
// switch (command) {
|
|
28
|
+
// case SacCommands.Allowance:
|
|
29
|
+
// return sac.allowance(args)
|
|
30
|
+
// case SacCommands.Authorized:
|
|
31
|
+
// return sac.authorized(args)
|
|
32
|
+
// case SacCommands.Approve:
|
|
33
|
+
// return sac.approve(args)
|
|
34
|
+
// case SacCommands.Balance:
|
|
35
|
+
// return sac.balance(args)
|
|
36
|
+
// case SacCommands.Burn:
|
|
37
|
+
// return sac.burn(args)
|
|
38
|
+
// case SacCommands.BurnFrom:
|
|
39
|
+
// return sac.burn_from(args)
|
|
40
|
+
// case SacCommands.Clawback:
|
|
41
|
+
// return sac.clawback(args)
|
|
42
|
+
// case SacCommands.Decimals:
|
|
43
|
+
// return sac.decimals(args)
|
|
44
|
+
// case SacCommands.Mint:
|
|
45
|
+
// return sac.mint(args)
|
|
46
|
+
// case SacCommands.Name:
|
|
47
|
+
// return sac.name(args)
|
|
48
|
+
// case SacCommands.SetAdmin:
|
|
49
|
+
// return sac.set_admin(args)
|
|
50
|
+
// case SacCommands.Admin:
|
|
51
|
+
// return sac.admin(args)
|
|
52
|
+
// case SacCommands.SetAuthorized:
|
|
53
|
+
// return sac.set_authorized(args)
|
|
54
|
+
// case SacCommands.Symbol:
|
|
55
|
+
// return sac.symbol(args)
|
|
56
|
+
// case SacCommands.Transfer:
|
|
57
|
+
// return sac.transfer(args)
|
|
58
|
+
// case SacCommands.TransferFrom:
|
|
59
|
+
// return sac.transfer_from(args)
|
|
60
|
+
// default:
|
|
61
|
+
// throw new Error('Invalid command')
|
|
62
|
+
// }
|
|
63
|
+
|
|
64
|
+
// const { SAC, from, to, amount, fee = 0 } = args
|
|
65
|
+
// const txn = new TransactionBuilder(mockSource, {
|
|
66
|
+
// fee: fee.toString(),
|
|
67
|
+
// networkPassphrase: import.meta.env.VITE_networkPassphrase
|
|
68
|
+
// })
|
|
69
|
+
// .addOperation(Operation.invokeContractFunction({
|
|
70
|
+
// contract: SAC,
|
|
71
|
+
// function: 'transfer',
|
|
72
|
+
// args: [
|
|
73
|
+
// nativeToScVal(from, { type: 'address' }),
|
|
74
|
+
// nativeToScVal(to, { type: 'address' }),
|
|
75
|
+
// nativeToScVal(amount, { type: 'i128' })
|
|
76
|
+
// ],
|
|
77
|
+
// }))
|
|
78
|
+
// .setTimeout(5 * 60)
|
|
79
|
+
// .build()
|
|
80
|
+
|
|
81
|
+
// const sim = await rpc.simulateTransaction(txn)
|
|
82
|
+
|
|
83
|
+
// if (
|
|
84
|
+
// SorobanRpc.Api.isSimulationError(sim)
|
|
85
|
+
// || SorobanRpc.Api.isSimulationRestore(sim)
|
|
86
|
+
// ) throw sim
|
|
87
|
+
|
|
88
|
+
// return {
|
|
89
|
+
// txn,
|
|
90
|
+
// sim,
|
|
91
|
+
// built: SorobanRpc.assembleTransaction(txn, sim).build()
|
|
92
|
+
// }
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { SorobanRpc, xdr } from "@stellar/stellar-sdk"
|
|
2
|
+
import base64url from "base64url"
|
|
3
|
+
import { PasskeyBase } from "./base"
|
|
4
|
+
|
|
5
|
+
export class PasskeyServer extends PasskeyBase {
|
|
6
|
+
public launchtubeUrl: string | undefined
|
|
7
|
+
public launchtubeJwt: string | undefined
|
|
8
|
+
public mercuryUrl: string | undefined
|
|
9
|
+
public mercuryJwt: string | undefined
|
|
10
|
+
public mercuryEmail: string | undefined
|
|
11
|
+
public mercuryPassword: string | undefined
|
|
12
|
+
|
|
13
|
+
constructor(options: {
|
|
14
|
+
rpcUrl?: string,
|
|
15
|
+
launchtubeUrl?: string,
|
|
16
|
+
launchtubeJwt?: string,
|
|
17
|
+
mercuryUrl?: string,
|
|
18
|
+
mercuryJwt?: string,
|
|
19
|
+
mercuryEmail?: string,
|
|
20
|
+
mercuryPassword?: string
|
|
21
|
+
}) {
|
|
22
|
+
const {
|
|
23
|
+
rpcUrl,
|
|
24
|
+
launchtubeUrl,
|
|
25
|
+
launchtubeJwt,
|
|
26
|
+
mercuryUrl,
|
|
27
|
+
mercuryJwt,
|
|
28
|
+
mercuryEmail,
|
|
29
|
+
mercuryPassword
|
|
30
|
+
} = options
|
|
31
|
+
|
|
32
|
+
super(rpcUrl)
|
|
33
|
+
|
|
34
|
+
if (launchtubeUrl)
|
|
35
|
+
this.launchtubeUrl = launchtubeUrl
|
|
36
|
+
|
|
37
|
+
if (launchtubeJwt)
|
|
38
|
+
this.launchtubeJwt = launchtubeJwt
|
|
39
|
+
|
|
40
|
+
if (mercuryUrl)
|
|
41
|
+
this.mercuryUrl = mercuryUrl
|
|
42
|
+
|
|
43
|
+
if (mercuryJwt)
|
|
44
|
+
this.mercuryJwt = mercuryJwt
|
|
45
|
+
|
|
46
|
+
if (mercuryEmail)
|
|
47
|
+
this.mercuryEmail = mercuryEmail
|
|
48
|
+
|
|
49
|
+
if (mercuryPassword)
|
|
50
|
+
this.mercuryPassword = mercuryPassword
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async setMercuryJwt() {
|
|
54
|
+
if (!this.mercuryUrl || !this.mercuryEmail || !this.mercuryPassword)
|
|
55
|
+
throw new Error('Mercury service not configured')
|
|
56
|
+
|
|
57
|
+
const { data: { authenticate: { jwtToken } } } = await fetch(`${this.mercuryUrl}/graphql`, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: {
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
},
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
query: `mutation {
|
|
64
|
+
authenticate(input: {
|
|
65
|
+
email: "${this.mercuryEmail}"
|
|
66
|
+
password: "${this.mercuryPassword}"
|
|
67
|
+
}) {
|
|
68
|
+
jwtToken
|
|
69
|
+
}
|
|
70
|
+
}`
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
.then(async (res) => {
|
|
74
|
+
if (res.ok)
|
|
75
|
+
return res.json()
|
|
76
|
+
|
|
77
|
+
throw await res.json()
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
this.mercuryJwt = jwtToken
|
|
81
|
+
return jwtToken
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public async getSigners(contractId: string) {
|
|
85
|
+
if (this.rpc && this.mercuryUrl && !this.mercuryJwt)
|
|
86
|
+
await this.setMercuryJwt()
|
|
87
|
+
|
|
88
|
+
if (!this.rpc || !this.mercuryUrl || !this.mercuryJwt)
|
|
89
|
+
throw new Error('Mercury service not configured')
|
|
90
|
+
|
|
91
|
+
const signers = await fetch(`${this.mercuryUrl}/zephyr/execute`, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: {
|
|
94
|
+
'Content-Type': 'application/json',
|
|
95
|
+
Authorization: `Bearer ${this.mercuryJwt}`
|
|
96
|
+
},
|
|
97
|
+
body: JSON.stringify({
|
|
98
|
+
mode: {
|
|
99
|
+
Function: {
|
|
100
|
+
fname: "get_signers_by_address",
|
|
101
|
+
arguments: JSON.stringify({
|
|
102
|
+
address: contractId
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
.then(async (res) => {
|
|
109
|
+
if (res.ok)
|
|
110
|
+
return res.json()
|
|
111
|
+
|
|
112
|
+
throw await res.json()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
for (const signer of signers) {
|
|
116
|
+
if (!signer.admin) {
|
|
117
|
+
try {
|
|
118
|
+
await this.rpc.getContractData(contractId, xdr.ScVal.scvBytes(signer.id), SorobanRpc.Durability.Temporary)
|
|
119
|
+
} catch {
|
|
120
|
+
signer.expired = true
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
signer.id = base64url(signer.id)
|
|
125
|
+
signer.pk = base64url(signer.pk)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return signers as { id: string, pk: string, admin: boolean, expired?: boolean }[]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public async getContractId(keyId: string) {
|
|
132
|
+
if (this.mercuryUrl && !this.mercuryJwt)
|
|
133
|
+
await this.setMercuryJwt()
|
|
134
|
+
|
|
135
|
+
if (!this.mercuryUrl || !this.mercuryJwt)
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
const res = await fetch(`${this.mercuryUrl}/zephyr/execute`, {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
headers: {
|
|
141
|
+
'Content-Type': 'application/json',
|
|
142
|
+
Authorization: `Bearer ${this.mercuryJwt}`
|
|
143
|
+
},
|
|
144
|
+
body: JSON.stringify({
|
|
145
|
+
mode: {
|
|
146
|
+
Function: {
|
|
147
|
+
fname: "get_address_by_signer",
|
|
148
|
+
arguments: JSON.stringify({
|
|
149
|
+
id: [...base64url.toBuffer(keyId)]
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
.then(async (res) => {
|
|
156
|
+
if (res.ok)
|
|
157
|
+
return res.json()
|
|
158
|
+
|
|
159
|
+
throw await res.json()
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
return res[0]?.address as string | undefined
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* TODO
|
|
166
|
+
- Add a method for getting a paginated or filtered list of all a wallet's events
|
|
167
|
+
@Later
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
public async send(xdr: string, fee: number = 10_000) {
|
|
171
|
+
if (!this.launchtubeUrl || !this.launchtubeJwt)
|
|
172
|
+
throw new Error('Launchtube service not configured')
|
|
173
|
+
|
|
174
|
+
const data = new FormData();
|
|
175
|
+
|
|
176
|
+
data.set('xdr', xdr);
|
|
177
|
+
data.set('fee', fee.toString());
|
|
178
|
+
|
|
179
|
+
return fetch(this.launchtubeUrl, {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
headers: {
|
|
182
|
+
authorization: `Bearer ${this.launchtubeJwt}`,
|
|
183
|
+
},
|
|
184
|
+
body: data
|
|
185
|
+
}).then(async (res) => {
|
|
186
|
+
if (res.ok)
|
|
187
|
+
return res.json()
|
|
188
|
+
else throw await res.json()
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"outDir": "./types",
|
|
4
|
-
|
|
5
4
|
// Enable latest features
|
|
6
5
|
"target": "ESNext",
|
|
7
6
|
"module": "ESNext",
|
|
8
7
|
"moduleDetection": "force",
|
|
9
|
-
|
|
10
8
|
// Bundler mode
|
|
11
9
|
"moduleResolution": "node",
|
|
12
10
|
"allowImportingTsExtensions": true,
|
|
13
11
|
"verbatimModuleSyntax": true,
|
|
14
12
|
"declaration": true,
|
|
15
13
|
"emitDeclarationOnly": true,
|
|
16
|
-
|
|
17
14
|
// Best practices
|
|
18
15
|
"strict": true,
|
|
19
16
|
"skipLibCheck": true,
|
|
20
17
|
"noFallthroughCasesInSwitch": true,
|
|
21
|
-
|
|
22
18
|
// Some stricter flags (disabled by default)
|
|
23
19
|
"noUnusedLocals": false,
|
|
24
20
|
"noUnusedParameters": false,
|
|
25
21
|
"noPropertyAccessFromIndexSignature": false,
|
|
26
22
|
"strictNullChecks": true,
|
|
27
23
|
},
|
|
28
|
-
"exclude": [
|
|
24
|
+
"exclude": [
|
|
25
|
+
"./bun_tests",
|
|
26
|
+
"./contracts",
|
|
27
|
+
"./demo",
|
|
28
|
+
"./packages",
|
|
29
|
+
"./types",
|
|
30
|
+
"./zephyr",
|
|
31
|
+
]
|
|
29
32
|
}
|
package/types/base.d.ts
CHANGED
|
@@ -1,29 +1,6 @@
|
|
|
1
1
|
import { SorobanRpc } from "@stellar/stellar-sdk";
|
|
2
2
|
export declare class PasskeyBase {
|
|
3
|
-
rpc: SorobanRpc.Server | undefined;
|
|
4
3
|
rpcUrl: string | undefined;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
mercuryUrl: string | undefined;
|
|
8
|
-
mercuryJwt: string | undefined;
|
|
9
|
-
mercuryEmail: string | undefined;
|
|
10
|
-
mercuryPassword: string | undefined;
|
|
11
|
-
constructor(options: {
|
|
12
|
-
rpcUrl?: string;
|
|
13
|
-
launchtubeUrl?: string;
|
|
14
|
-
launchtubeJwt?: string;
|
|
15
|
-
mercuryUrl?: string;
|
|
16
|
-
mercuryJwt?: string;
|
|
17
|
-
mercuryEmail?: string;
|
|
18
|
-
mercuryPassword?: string;
|
|
19
|
-
});
|
|
20
|
-
setMercuryJwt(): Promise<any>;
|
|
21
|
-
getSigners(contractId: string): Promise<{
|
|
22
|
-
id: string;
|
|
23
|
-
pk: string;
|
|
24
|
-
admin: boolean;
|
|
25
|
-
expired?: boolean;
|
|
26
|
-
}[]>;
|
|
27
|
-
getContractId(keyId: string): Promise<string | undefined>;
|
|
28
|
-
send(xdr: string, fee?: number): Promise<any>;
|
|
4
|
+
rpc: SorobanRpc.Server | undefined;
|
|
5
|
+
constructor(rpcUrl?: string);
|
|
29
6
|
}
|
package/types/index.d.ts
CHANGED
package/types/kit.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Client as PasskeyClient } from 'passkey-kit-sdk';
|
|
2
2
|
import { Client as FactoryClient } from 'passkey-factory-sdk';
|
|
3
|
-
import { xdr, Transaction } from '@stellar/stellar-sdk';
|
|
3
|
+
import { xdr, Transaction, SorobanRpc } from '@stellar/stellar-sdk';
|
|
4
4
|
import { Buffer } from 'buffer';
|
|
5
5
|
import { PasskeyBase } from './base';
|
|
6
6
|
export declare class PasskeyKit extends PasskeyBase {
|
|
7
|
+
rpc: SorobanRpc.Server;
|
|
8
|
+
rpcUrl: string;
|
|
7
9
|
keyId: string | undefined;
|
|
8
10
|
networkPassphrase: string;
|
|
9
11
|
factory: FactoryClient;
|
|
@@ -12,12 +14,6 @@ export declare class PasskeyKit extends PasskeyBase {
|
|
|
12
14
|
rpcUrl: string;
|
|
13
15
|
networkPassphrase: string;
|
|
14
16
|
factoryContractId: string;
|
|
15
|
-
launchtubeUrl?: string;
|
|
16
|
-
launchtubeJwt?: string;
|
|
17
|
-
mercuryUrl?: string;
|
|
18
|
-
mercuryJwt?: string;
|
|
19
|
-
mercuryEmail?: string;
|
|
20
|
-
mercuryPassword?: string;
|
|
21
17
|
});
|
|
22
18
|
createWallet(app: string, user: string): Promise<{
|
|
23
19
|
keyId: Buffer;
|
package/types/sac.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SorobanRpc } from "@stellar/stellar-sdk";
|
|
2
|
+
import { Client as SacClient } from 'sac-sdk';
|
|
3
|
+
export declare class SACClient {
|
|
4
|
+
networkPassphrase: string;
|
|
5
|
+
rpcUrl: string;
|
|
6
|
+
rpc: SorobanRpc.Server;
|
|
7
|
+
constructor(options: {
|
|
8
|
+
networkPassphrase: string;
|
|
9
|
+
rpcUrl: string;
|
|
10
|
+
});
|
|
11
|
+
getSACClient(SACContractId: string): SacClient;
|
|
12
|
+
}
|