stellar-shade 0.0.1 → 0.0.2
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/dist/index.cjs +54 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -5
- package/dist/index.d.ts +51 -5
- package/dist/index.js +54 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -45,17 +45,48 @@ interface WithdrawReceipt {
|
|
|
45
45
|
/** Amount withdrawn in whole units */
|
|
46
46
|
amount: number;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* External transaction signer.
|
|
50
|
+
*
|
|
51
|
+
* Given the base64 XDR of a prepared transaction, return the base64 XDR of the
|
|
52
|
+
* signed transaction. This is exactly the shape of a browser wallet's signing
|
|
53
|
+
* call (e.g. Freighter's `signTransaction`), allowing the client to sign
|
|
54
|
+
* without ever handling a raw secret key.
|
|
55
|
+
*/
|
|
56
|
+
type TransactionSigner = (xdr: string, context: {
|
|
57
|
+
/** Network passphrase the transaction must be signed against. */
|
|
58
|
+
networkPassphrase: string;
|
|
59
|
+
/** The account expected to sign (public key, G...). */
|
|
60
|
+
address: string;
|
|
61
|
+
}) => Promise<string>;
|
|
48
62
|
/** Options for sending to a stealth address. */
|
|
49
63
|
interface SendOpts {
|
|
50
64
|
/** Asset to send. Default: native XLM. Format: "CODE:ISSUER" */
|
|
51
65
|
asset?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Sign with an external wallet instead of a raw secret key. When provided,
|
|
68
|
+
* the `senderSecret` argument of `send()` is treated as the sender's public
|
|
69
|
+
* key (G...) and is never used to sign.
|
|
70
|
+
*/
|
|
71
|
+
signTransaction?: TransactionSigner;
|
|
52
72
|
}
|
|
53
73
|
/** Options for withdrawing from a stealth address. */
|
|
54
74
|
interface WithdrawOpts {
|
|
55
75
|
/** Stealth keys (need view + spend private keys) */
|
|
56
76
|
keys: StealthKeys;
|
|
57
|
-
/**
|
|
58
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Secret key of the account paying the Soroban invocation fee.
|
|
79
|
+
* Optional when `signTransaction` + `feePayerAddress` are supplied instead.
|
|
80
|
+
*/
|
|
81
|
+
feePayer?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Sign the fee-payer side with an external wallet instead of `feePayer`.
|
|
84
|
+
* The stealth withdraw authorization is still produced internally from
|
|
85
|
+
* `keys`; only the transaction envelope signature is delegated.
|
|
86
|
+
*/
|
|
87
|
+
signTransaction?: TransactionSigner;
|
|
88
|
+
/** Fee payer's public key (G...). Required when using `signTransaction`. */
|
|
89
|
+
feePayerAddress?: string;
|
|
59
90
|
/** Relay URL for fee-bumped submission (privacy-preserving) */
|
|
60
91
|
relay?: string;
|
|
61
92
|
/** Asset to withdraw. Default: native XLM. Format: "CODE:ISSUER" */
|
|
@@ -121,12 +152,27 @@ declare class StealthClient {
|
|
|
121
152
|
* Derives a one-time stealth address from the recipient's meta-address,
|
|
122
153
|
* deposits tokens into the pool contract, and records the announcement.
|
|
123
154
|
*
|
|
155
|
+
* Signing: by default the transaction is signed with `senderSecret` (a
|
|
156
|
+
* Stellar secret key). If `opts.signTransaction` is provided, signing is
|
|
157
|
+
* delegated to that external signer (e.g. a browser wallet) and the
|
|
158
|
+
* `senderSecret` argument is treated as the sender's public key instead.
|
|
159
|
+
*
|
|
124
160
|
* @param metaAddress - Recipient's meta-address (st:stellar:... format)
|
|
125
161
|
* @param amount - Amount in whole units (e.g. 100 = 100 XLM)
|
|
126
|
-
* @param senderSecret - Sender's
|
|
127
|
-
* @param opts - Optional: asset to send
|
|
162
|
+
* @param senderSecret - Sender's secret key, or public key when using `opts.signTransaction`
|
|
163
|
+
* @param opts - Optional: asset to send, external signer
|
|
128
164
|
*/
|
|
129
165
|
send(metaAddress: string, amount: number, senderSecret: string, opts?: SendOpts): Promise<SendReceipt>;
|
|
166
|
+
/**
|
|
167
|
+
* Sign a prepared transaction either with a local secret key (legacy path)
|
|
168
|
+
* or by delegating to an external signer that returns signed XDR.
|
|
169
|
+
*
|
|
170
|
+
* @param prepared - The prepared transaction to sign
|
|
171
|
+
* @param secretOrPublic - Secret key (local signing) or public key (external)
|
|
172
|
+
* @param publicKey - Signer's public key (G...)
|
|
173
|
+
* @param signer - Optional external signer; when present, no secret is used
|
|
174
|
+
*/
|
|
175
|
+
private signTx;
|
|
130
176
|
/**
|
|
131
177
|
* Scan for stealth payments you received.
|
|
132
178
|
*
|
|
@@ -156,4 +202,4 @@ declare class StealthClient {
|
|
|
156
202
|
withdraw(stealthAddress: string, destination: string, opts: WithdrawOpts): Promise<WithdrawReceipt>;
|
|
157
203
|
}
|
|
158
204
|
|
|
159
|
-
export { type Balance, type ClientConfig, type Payment, type SendOpts, type SendReceipt, StealthClient, type StealthKeys, type WithdrawOpts, type WithdrawReceipt };
|
|
205
|
+
export { type Balance, type ClientConfig, type Payment, type SendOpts, type SendReceipt, StealthClient, type StealthKeys, type TransactionSigner, type WithdrawOpts, type WithdrawReceipt };
|
package/dist/index.d.ts
CHANGED
|
@@ -45,17 +45,48 @@ interface WithdrawReceipt {
|
|
|
45
45
|
/** Amount withdrawn in whole units */
|
|
46
46
|
amount: number;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* External transaction signer.
|
|
50
|
+
*
|
|
51
|
+
* Given the base64 XDR of a prepared transaction, return the base64 XDR of the
|
|
52
|
+
* signed transaction. This is exactly the shape of a browser wallet's signing
|
|
53
|
+
* call (e.g. Freighter's `signTransaction`), allowing the client to sign
|
|
54
|
+
* without ever handling a raw secret key.
|
|
55
|
+
*/
|
|
56
|
+
type TransactionSigner = (xdr: string, context: {
|
|
57
|
+
/** Network passphrase the transaction must be signed against. */
|
|
58
|
+
networkPassphrase: string;
|
|
59
|
+
/** The account expected to sign (public key, G...). */
|
|
60
|
+
address: string;
|
|
61
|
+
}) => Promise<string>;
|
|
48
62
|
/** Options for sending to a stealth address. */
|
|
49
63
|
interface SendOpts {
|
|
50
64
|
/** Asset to send. Default: native XLM. Format: "CODE:ISSUER" */
|
|
51
65
|
asset?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Sign with an external wallet instead of a raw secret key. When provided,
|
|
68
|
+
* the `senderSecret` argument of `send()` is treated as the sender's public
|
|
69
|
+
* key (G...) and is never used to sign.
|
|
70
|
+
*/
|
|
71
|
+
signTransaction?: TransactionSigner;
|
|
52
72
|
}
|
|
53
73
|
/** Options for withdrawing from a stealth address. */
|
|
54
74
|
interface WithdrawOpts {
|
|
55
75
|
/** Stealth keys (need view + spend private keys) */
|
|
56
76
|
keys: StealthKeys;
|
|
57
|
-
/**
|
|
58
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Secret key of the account paying the Soroban invocation fee.
|
|
79
|
+
* Optional when `signTransaction` + `feePayerAddress` are supplied instead.
|
|
80
|
+
*/
|
|
81
|
+
feePayer?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Sign the fee-payer side with an external wallet instead of `feePayer`.
|
|
84
|
+
* The stealth withdraw authorization is still produced internally from
|
|
85
|
+
* `keys`; only the transaction envelope signature is delegated.
|
|
86
|
+
*/
|
|
87
|
+
signTransaction?: TransactionSigner;
|
|
88
|
+
/** Fee payer's public key (G...). Required when using `signTransaction`. */
|
|
89
|
+
feePayerAddress?: string;
|
|
59
90
|
/** Relay URL for fee-bumped submission (privacy-preserving) */
|
|
60
91
|
relay?: string;
|
|
61
92
|
/** Asset to withdraw. Default: native XLM. Format: "CODE:ISSUER" */
|
|
@@ -121,12 +152,27 @@ declare class StealthClient {
|
|
|
121
152
|
* Derives a one-time stealth address from the recipient's meta-address,
|
|
122
153
|
* deposits tokens into the pool contract, and records the announcement.
|
|
123
154
|
*
|
|
155
|
+
* Signing: by default the transaction is signed with `senderSecret` (a
|
|
156
|
+
* Stellar secret key). If `opts.signTransaction` is provided, signing is
|
|
157
|
+
* delegated to that external signer (e.g. a browser wallet) and the
|
|
158
|
+
* `senderSecret` argument is treated as the sender's public key instead.
|
|
159
|
+
*
|
|
124
160
|
* @param metaAddress - Recipient's meta-address (st:stellar:... format)
|
|
125
161
|
* @param amount - Amount in whole units (e.g. 100 = 100 XLM)
|
|
126
|
-
* @param senderSecret - Sender's
|
|
127
|
-
* @param opts - Optional: asset to send
|
|
162
|
+
* @param senderSecret - Sender's secret key, or public key when using `opts.signTransaction`
|
|
163
|
+
* @param opts - Optional: asset to send, external signer
|
|
128
164
|
*/
|
|
129
165
|
send(metaAddress: string, amount: number, senderSecret: string, opts?: SendOpts): Promise<SendReceipt>;
|
|
166
|
+
/**
|
|
167
|
+
* Sign a prepared transaction either with a local secret key (legacy path)
|
|
168
|
+
* or by delegating to an external signer that returns signed XDR.
|
|
169
|
+
*
|
|
170
|
+
* @param prepared - The prepared transaction to sign
|
|
171
|
+
* @param secretOrPublic - Secret key (local signing) or public key (external)
|
|
172
|
+
* @param publicKey - Signer's public key (G...)
|
|
173
|
+
* @param signer - Optional external signer; when present, no secret is used
|
|
174
|
+
*/
|
|
175
|
+
private signTx;
|
|
130
176
|
/**
|
|
131
177
|
* Scan for stealth payments you received.
|
|
132
178
|
*
|
|
@@ -156,4 +202,4 @@ declare class StealthClient {
|
|
|
156
202
|
withdraw(stealthAddress: string, destination: string, opts: WithdrawOpts): Promise<WithdrawReceipt>;
|
|
157
203
|
}
|
|
158
204
|
|
|
159
|
-
export { type Balance, type ClientConfig, type Payment, type SendOpts, type SendReceipt, StealthClient, type StealthKeys, type WithdrawOpts, type WithdrawReceipt };
|
|
205
|
+
export { type Balance, type ClientConfig, type Payment, type SendOpts, type SendReceipt, StealthClient, type StealthKeys, type TransactionSigner, type WithdrawOpts, type WithdrawReceipt };
|
package/dist/index.js
CHANGED
|
@@ -576,15 +576,20 @@ var StealthClient = class {
|
|
|
576
576
|
* Derives a one-time stealth address from the recipient's meta-address,
|
|
577
577
|
* deposits tokens into the pool contract, and records the announcement.
|
|
578
578
|
*
|
|
579
|
+
* Signing: by default the transaction is signed with `senderSecret` (a
|
|
580
|
+
* Stellar secret key). If `opts.signTransaction` is provided, signing is
|
|
581
|
+
* delegated to that external signer (e.g. a browser wallet) and the
|
|
582
|
+
* `senderSecret` argument is treated as the sender's public key instead.
|
|
583
|
+
*
|
|
579
584
|
* @param metaAddress - Recipient's meta-address (st:stellar:... format)
|
|
580
585
|
* @param amount - Amount in whole units (e.g. 100 = 100 XLM)
|
|
581
|
-
* @param senderSecret - Sender's
|
|
582
|
-
* @param opts - Optional: asset to send
|
|
586
|
+
* @param senderSecret - Sender's secret key, or public key when using `opts.signTransaction`
|
|
587
|
+
* @param opts - Optional: asset to send, external signer
|
|
583
588
|
*/
|
|
584
589
|
async send(metaAddress, amount, senderSecret, opts) {
|
|
585
590
|
if (amount <= 0) throw new Error("Amount must be positive");
|
|
586
591
|
const { spendPubKey, viewPubKey } = decodeMetaAddress(metaAddress);
|
|
587
|
-
const
|
|
592
|
+
const senderPublicKey = opts?.signTransaction ? senderSecret : Keypair.fromSecret(senderSecret).publicKey();
|
|
588
593
|
const tokenAddress = resolveTokenAddress(opts?.asset, this.networkPassphrase);
|
|
589
594
|
const stroops = BigInt(Math.round(amount * 1e7));
|
|
590
595
|
const ephemeralPrivKey = new Uint8Array(randomBytes(32));
|
|
@@ -594,14 +599,14 @@ var StealthClient = class {
|
|
|
594
599
|
ephemeralPrivKey
|
|
595
600
|
);
|
|
596
601
|
const contract = new Contract(this.contractId);
|
|
597
|
-
const account = await this.server.getAccount(
|
|
602
|
+
const account = await this.server.getAccount(senderPublicKey);
|
|
598
603
|
const depositTx = new TransactionBuilder(account, {
|
|
599
604
|
fee: "100",
|
|
600
605
|
networkPassphrase: this.networkPassphrase
|
|
601
606
|
}).addOperation(
|
|
602
607
|
contract.call(
|
|
603
608
|
"deposit",
|
|
604
|
-
new StellarSdk.Address(
|
|
609
|
+
new StellarSdk.Address(senderPublicKey).toScVal(),
|
|
605
610
|
new StellarSdk.Address(tokenAddress).toScVal(),
|
|
606
611
|
nativeToScVal(stroops, { type: "i128" }),
|
|
607
612
|
nativeToScVal(Buffer.from(stealth.stealthPubKey)),
|
|
@@ -610,8 +615,13 @@ var StealthClient = class {
|
|
|
610
615
|
)
|
|
611
616
|
).setTimeout(30).build();
|
|
612
617
|
const prepared = await this.server.prepareTransaction(depositTx);
|
|
613
|
-
|
|
614
|
-
|
|
618
|
+
const signed = await this.signTx(
|
|
619
|
+
prepared,
|
|
620
|
+
senderSecret,
|
|
621
|
+
senderPublicKey,
|
|
622
|
+
opts?.signTransaction
|
|
623
|
+
);
|
|
624
|
+
const result = await this.server.sendTransaction(signed);
|
|
615
625
|
if (result.status === "ERROR") {
|
|
616
626
|
throw new Error("Transaction submission failed");
|
|
617
627
|
}
|
|
@@ -623,6 +633,27 @@ var StealthClient = class {
|
|
|
623
633
|
txHash: result.hash
|
|
624
634
|
};
|
|
625
635
|
}
|
|
636
|
+
/**
|
|
637
|
+
* Sign a prepared transaction either with a local secret key (legacy path)
|
|
638
|
+
* or by delegating to an external signer that returns signed XDR.
|
|
639
|
+
*
|
|
640
|
+
* @param prepared - The prepared transaction to sign
|
|
641
|
+
* @param secretOrPublic - Secret key (local signing) or public key (external)
|
|
642
|
+
* @param publicKey - Signer's public key (G...)
|
|
643
|
+
* @param signer - Optional external signer; when present, no secret is used
|
|
644
|
+
*/
|
|
645
|
+
async signTx(prepared, secretOrPublic, publicKey, signer) {
|
|
646
|
+
if (signer) {
|
|
647
|
+
const signedXdr = await signer(prepared.toXDR(), {
|
|
648
|
+
networkPassphrase: this.networkPassphrase,
|
|
649
|
+
address: publicKey
|
|
650
|
+
});
|
|
651
|
+
const tx = TransactionBuilder.fromXDR(signedXdr, this.networkPassphrase);
|
|
652
|
+
return tx;
|
|
653
|
+
}
|
|
654
|
+
prepared.sign(Keypair.fromSecret(secretOrPublic));
|
|
655
|
+
return prepared;
|
|
656
|
+
}
|
|
626
657
|
/**
|
|
627
658
|
* Scan for stealth payments you received.
|
|
628
659
|
*
|
|
@@ -764,9 +795,15 @@ var StealthClient = class {
|
|
|
764
795
|
nonce
|
|
765
796
|
);
|
|
766
797
|
const signature = signWithStealthKey(messageHash, stealthPrivKey);
|
|
767
|
-
|
|
798
|
+
if (!opts.signTransaction && !opts.feePayer) {
|
|
799
|
+
throw new Error("Provide either opts.feePayer or opts.signTransaction + opts.feePayerAddress");
|
|
800
|
+
}
|
|
801
|
+
if (opts.signTransaction && !opts.feePayerAddress) {
|
|
802
|
+
throw new Error("opts.feePayerAddress is required when using opts.signTransaction");
|
|
803
|
+
}
|
|
804
|
+
const feePayerPublicKey = opts.signTransaction ? opts.feePayerAddress : Keypair.fromSecret(opts.feePayer).publicKey();
|
|
768
805
|
const contract = new Contract(this.contractId);
|
|
769
|
-
const feePayerAccount = await this.server.getAccount(
|
|
806
|
+
const feePayerAccount = await this.server.getAccount(feePayerPublicKey);
|
|
770
807
|
const withdrawTx = new TransactionBuilder(feePayerAccount, {
|
|
771
808
|
fee: "100",
|
|
772
809
|
networkPassphrase: this.networkPassphrase
|
|
@@ -782,14 +819,19 @@ var StealthClient = class {
|
|
|
782
819
|
)
|
|
783
820
|
).setTimeout(30).build();
|
|
784
821
|
const prepared = await this.server.prepareTransaction(withdrawTx);
|
|
785
|
-
|
|
822
|
+
const signedTx = await this.signTx(
|
|
823
|
+
prepared,
|
|
824
|
+
opts.feePayer ?? "",
|
|
825
|
+
feePayerPublicKey,
|
|
826
|
+
opts.signTransaction
|
|
827
|
+
);
|
|
786
828
|
let txHash;
|
|
787
829
|
if (opts.relay) {
|
|
788
830
|
const url = opts.relay.endsWith("/relay") ? opts.relay : `${opts.relay}/relay`;
|
|
789
831
|
const res = await fetch(url, {
|
|
790
832
|
method: "POST",
|
|
791
833
|
headers: { "Content-Type": "application/json" },
|
|
792
|
-
body: JSON.stringify({ xdr:
|
|
834
|
+
body: JSON.stringify({ xdr: signedTx.toEnvelope().toXDR("base64") })
|
|
793
835
|
});
|
|
794
836
|
if (!res.ok) {
|
|
795
837
|
const err = await res.json();
|
|
@@ -798,7 +840,7 @@ var StealthClient = class {
|
|
|
798
840
|
const data = await res.json();
|
|
799
841
|
txHash = data.txHash;
|
|
800
842
|
} else {
|
|
801
|
-
const result = await this.server.sendTransaction(
|
|
843
|
+
const result = await this.server.sendTransaction(signedTx);
|
|
802
844
|
if (result.status === "ERROR") throw new Error("Transaction submission failed");
|
|
803
845
|
if (result.status === "PENDING") {
|
|
804
846
|
await waitForTransaction(this.server, result.hash);
|