@atomiqlabs/chain-starknet 1.0.0-beta.0

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.
Files changed (136) hide show
  1. package/LICENSE +201 -0
  2. package/dist/get_serialized_block.d.ts +1 -0
  3. package/dist/get_serialized_block.js +28 -0
  4. package/dist/index.d.ts +34 -0
  5. package/dist/index.js +50 -0
  6. package/dist/starknet/StarknetChainType.d.ts +9 -0
  7. package/dist/starknet/StarknetChainType.js +2 -0
  8. package/dist/starknet/StarknetInitializer.d.ts +18 -0
  9. package/dist/starknet/StarknetInitializer.js +49 -0
  10. package/dist/starknet/base/StarknetAction.d.ts +27 -0
  11. package/dist/starknet/base/StarknetAction.js +73 -0
  12. package/dist/starknet/base/StarknetBase.d.ts +34 -0
  13. package/dist/starknet/base/StarknetBase.js +29 -0
  14. package/dist/starknet/base/StarknetModule.d.ts +14 -0
  15. package/dist/starknet/base/StarknetModule.js +13 -0
  16. package/dist/starknet/base/modules/ERC20Abi.d.ts +755 -0
  17. package/dist/starknet/base/modules/ERC20Abi.js +1032 -0
  18. package/dist/starknet/base/modules/StarknetAccounts.d.ts +6 -0
  19. package/dist/starknet/base/modules/StarknetAccounts.js +24 -0
  20. package/dist/starknet/base/modules/StarknetAddresses.d.ts +9 -0
  21. package/dist/starknet/base/modules/StarknetAddresses.js +26 -0
  22. package/dist/starknet/base/modules/StarknetBlocks.d.ts +19 -0
  23. package/dist/starknet/base/modules/StarknetBlocks.js +49 -0
  24. package/dist/starknet/base/modules/StarknetEvents.d.ts +44 -0
  25. package/dist/starknet/base/modules/StarknetEvents.js +88 -0
  26. package/dist/starknet/base/modules/StarknetFees.d.ts +55 -0
  27. package/dist/starknet/base/modules/StarknetFees.js +102 -0
  28. package/dist/starknet/base/modules/StarknetSignatures.d.ts +30 -0
  29. package/dist/starknet/base/modules/StarknetSignatures.js +71 -0
  30. package/dist/starknet/base/modules/StarknetTokens.d.ts +67 -0
  31. package/dist/starknet/base/modules/StarknetTokens.js +97 -0
  32. package/dist/starknet/base/modules/StarknetTransactions.d.ts +87 -0
  33. package/dist/starknet/base/modules/StarknetTransactions.js +226 -0
  34. package/dist/starknet/btcrelay/BtcRelayAbi.d.ts +250 -0
  35. package/dist/starknet/btcrelay/BtcRelayAbi.js +341 -0
  36. package/dist/starknet/btcrelay/StarknetBtcRelay.d.ts +166 -0
  37. package/dist/starknet/btcrelay/StarknetBtcRelay.js +323 -0
  38. package/dist/starknet/btcrelay/headers/StarknetBtcHeader.d.ts +32 -0
  39. package/dist/starknet/btcrelay/headers/StarknetBtcHeader.js +74 -0
  40. package/dist/starknet/btcrelay/headers/StarknetBtcStoredHeader.d.ts +52 -0
  41. package/dist/starknet/btcrelay/headers/StarknetBtcStoredHeader.js +113 -0
  42. package/dist/starknet/contract/StarknetContractBase.d.ts +13 -0
  43. package/dist/starknet/contract/StarknetContractBase.js +18 -0
  44. package/dist/starknet/contract/modules/StarknetContractEvents.d.ts +40 -0
  45. package/dist/starknet/contract/modules/StarknetContractEvents.js +77 -0
  46. package/dist/starknet/events/StarknetChainEvents.d.ts +19 -0
  47. package/dist/starknet/events/StarknetChainEvents.js +51 -0
  48. package/dist/starknet/events/StarknetChainEventsBrowser.d.ts +73 -0
  49. package/dist/starknet/events/StarknetChainEventsBrowser.js +210 -0
  50. package/dist/starknet/swaps/EscrowManagerAbi.d.ts +445 -0
  51. package/dist/starknet/swaps/EscrowManagerAbi.js +601 -0
  52. package/dist/starknet/swaps/StarknetSwapContract.d.ts +215 -0
  53. package/dist/starknet/swaps/StarknetSwapContract.js +452 -0
  54. package/dist/starknet/swaps/StarknetSwapData.d.ts +74 -0
  55. package/dist/starknet/swaps/StarknetSwapData.js +316 -0
  56. package/dist/starknet/swaps/StarknetSwapModule.d.ts +9 -0
  57. package/dist/starknet/swaps/StarknetSwapModule.js +12 -0
  58. package/dist/starknet/swaps/handlers/IHandler.d.ts +13 -0
  59. package/dist/starknet/swaps/handlers/IHandler.js +2 -0
  60. package/dist/starknet/swaps/handlers/claim/ClaimHandlers.d.ts +13 -0
  61. package/dist/starknet/swaps/handlers/claim/ClaimHandlers.js +13 -0
  62. package/dist/starknet/swaps/handlers/claim/HashlockClaimHandler.d.ts +22 -0
  63. package/dist/starknet/swaps/handlers/claim/HashlockClaimHandler.js +44 -0
  64. package/dist/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +25 -0
  65. package/dist/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.js +48 -0
  66. package/dist/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +26 -0
  67. package/dist/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.js +40 -0
  68. package/dist/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +20 -0
  69. package/dist/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.js +29 -0
  70. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +64 -0
  71. package/dist/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +86 -0
  72. package/dist/starknet/swaps/handlers/refund/TimelockRefundHandler.d.ts +17 -0
  73. package/dist/starknet/swaps/handlers/refund/TimelockRefundHandler.js +27 -0
  74. package/dist/starknet/swaps/modules/StarknetLpVault.d.ts +69 -0
  75. package/dist/starknet/swaps/modules/StarknetLpVault.js +122 -0
  76. package/dist/starknet/swaps/modules/StarknetSwapClaim.d.ts +53 -0
  77. package/dist/starknet/swaps/modules/StarknetSwapClaim.js +100 -0
  78. package/dist/starknet/swaps/modules/StarknetSwapInit.d.ts +84 -0
  79. package/dist/starknet/swaps/modules/StarknetSwapInit.js +164 -0
  80. package/dist/starknet/swaps/modules/StarknetSwapRefund.d.ts +64 -0
  81. package/dist/starknet/swaps/modules/StarknetSwapRefund.js +131 -0
  82. package/dist/starknet/swaps/modules/SwapClaim.d.ts +54 -0
  83. package/dist/starknet/swaps/modules/SwapClaim.js +115 -0
  84. package/dist/starknet/swaps/modules/SwapInit.d.ts +79 -0
  85. package/dist/starknet/swaps/modules/SwapInit.js +174 -0
  86. package/dist/starknet/swaps/modules/SwapRefund.d.ts +63 -0
  87. package/dist/starknet/swaps/modules/SwapRefund.js +149 -0
  88. package/dist/starknet/wallet/StarknetKeypairWallet.d.ts +6 -0
  89. package/dist/starknet/wallet/StarknetKeypairWallet.js +26 -0
  90. package/dist/starknet/wallet/StarknetSigner.d.ts +12 -0
  91. package/dist/starknet/wallet/StarknetSigner.js +46 -0
  92. package/dist/utils/Utils.d.ts +38 -0
  93. package/dist/utils/Utils.js +255 -0
  94. package/package.json +39 -0
  95. package/src/index.ts +41 -0
  96. package/src/starknet/StarknetChainType.ts +20 -0
  97. package/src/starknet/StarknetInitializer.ts +75 -0
  98. package/src/starknet/base/StarknetAction.ts +90 -0
  99. package/src/starknet/base/StarknetBase.ts +56 -0
  100. package/src/starknet/base/StarknetModule.ts +20 -0
  101. package/src/starknet/base/modules/ERC20Abi.ts +1029 -0
  102. package/src/starknet/base/modules/StarknetAccounts.ts +26 -0
  103. package/src/starknet/base/modules/StarknetAddresses.ts +23 -0
  104. package/src/starknet/base/modules/StarknetBlocks.ts +59 -0
  105. package/src/starknet/base/modules/StarknetEvents.ts +105 -0
  106. package/src/starknet/base/modules/StarknetFees.ts +136 -0
  107. package/src/starknet/base/modules/StarknetSignatures.ts +91 -0
  108. package/src/starknet/base/modules/StarknetTokens.ts +116 -0
  109. package/src/starknet/base/modules/StarknetTransactions.ts +254 -0
  110. package/src/starknet/btcrelay/BtcRelayAbi.ts +338 -0
  111. package/src/starknet/btcrelay/StarknetBtcRelay.ts +415 -0
  112. package/src/starknet/btcrelay/headers/StarknetBtcHeader.ts +101 -0
  113. package/src/starknet/btcrelay/headers/StarknetBtcStoredHeader.ts +142 -0
  114. package/src/starknet/contract/StarknetContractBase.ts +29 -0
  115. package/src/starknet/contract/modules/StarknetContractEvents.ts +108 -0
  116. package/src/starknet/events/StarknetChainEvents.ts +63 -0
  117. package/src/starknet/events/StarknetChainEventsBrowser.ts +289 -0
  118. package/src/starknet/swaps/EscrowManagerAbi.ts +600 -0
  119. package/src/starknet/swaps/StarknetSwapContract.ts +694 -0
  120. package/src/starknet/swaps/StarknetSwapData.ts +441 -0
  121. package/src/starknet/swaps/StarknetSwapModule.ts +17 -0
  122. package/src/starknet/swaps/handlers/IHandler.ts +20 -0
  123. package/src/starknet/swaps/handlers/claim/ClaimHandlers.ts +23 -0
  124. package/src/starknet/swaps/handlers/claim/HashlockClaimHandler.ts +54 -0
  125. package/src/starknet/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +73 -0
  126. package/src/starknet/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +67 -0
  127. package/src/starknet/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +49 -0
  128. package/src/starknet/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +151 -0
  129. package/src/starknet/swaps/handlers/refund/TimelockRefundHandler.ts +39 -0
  130. package/src/starknet/swaps/modules/StarknetLpVault.ts +148 -0
  131. package/src/starknet/swaps/modules/StarknetSwapClaim.ts +142 -0
  132. package/src/starknet/swaps/modules/StarknetSwapInit.ts +226 -0
  133. package/src/starknet/swaps/modules/StarknetSwapRefund.ts +202 -0
  134. package/src/starknet/wallet/StarknetKeypairWallet.ts +34 -0
  135. package/src/starknet/wallet/StarknetSigner.ts +55 -0
  136. package/src/utils/Utils.ts +247 -0
@@ -0,0 +1,226 @@
1
+ import {SignatureVerificationError, SwapCommitStatus, SwapDataVerificationError} from "@atomiqlabs/base";
2
+ import {bufferToBytes31Span, toBigInt, toHex, tryWithRetries} from "../../../utils/Utils";
3
+ import {Buffer} from "buffer";
4
+ import {StarknetSwapData} from "../StarknetSwapData";
5
+ import {StarknetAction} from "../../base/StarknetAction";
6
+ import {StarknetSwapModule} from "../StarknetSwapModule";
7
+ import {BigNumberish} from "starknet";
8
+ import {StarknetSigner} from "../../wallet/StarknetSigner";
9
+ import {StarknetFees} from "../../base/modules/StarknetFees";
10
+ import {StarknetTx} from "../../base/modules/StarknetTransactions";
11
+
12
+ export type StarknetPreFetchVerification = {
13
+ pendingBlockTime?: number
14
+ };
15
+
16
+ const Initialize = [
17
+ { name: 'Swap hash', type: 'felt' },
18
+ { name: 'Timeout', type: 'timestamp' }
19
+ ];
20
+
21
+ export class StarknetSwapInit extends StarknetSwapModule {
22
+
23
+ private static readonly GasCosts = {
24
+ INIT: {l1: 500, l2: 0},
25
+ INIT_PAY_IN: {l1: 1000, l2: 0},
26
+ };
27
+
28
+ /**
29
+ * bare Init action based on the data passed in swapData
30
+ *
31
+ * @param swapData
32
+ * @param timeout
33
+ * @param signature
34
+ * @private
35
+ */
36
+ private Init(swapData: StarknetSwapData, timeout: bigint, signature: BigNumberish[]): StarknetAction {
37
+ return new StarknetAction(
38
+ swapData.payIn ? swapData.offerer : swapData.claimer,
39
+ this.root,
40
+ this.contract.populateTransaction.initialize(
41
+ swapData.toEscrowStruct(),
42
+ signature,
43
+ timeout,
44
+ swapData.extraData==null || swapData.extraData==="" ? [] : bufferToBytes31Span(Buffer.from(swapData.extraData, "hex")).map(toHex)
45
+ ),
46
+ swapData.payIn ? StarknetSwapInit.GasCosts.INIT_PAY_IN : StarknetSwapInit.GasCosts.INIT
47
+ )
48
+ }
49
+
50
+ /**
51
+ * Returns auth prefix to be used with a specific swap, payIn=true & payIn=false use different prefixes (these
52
+ * actually have no meaning for the smart contract/solana program in the Solana case)
53
+ *
54
+ * @param swapData
55
+ * @private
56
+ */
57
+ private getAuthPrefix(swapData: StarknetSwapData): string {
58
+ return swapData.isPayIn() ? "claim_initialize" : "initialize";
59
+ }
60
+
61
+ public async preFetchForInitSignatureVerification(): Promise<StarknetPreFetchVerification> {
62
+ return {
63
+ pendingBlockTime: await this.root.Blocks.getBlockTime("pending")
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Signs swap initialization authorization, using data from preFetchedBlockData if provided & still valid (subject
69
+ * to SIGNATURE_PREFETCH_DATA_VALIDITY)
70
+ *
71
+ * @param signer
72
+ * @param swapData
73
+ * @param authorizationTimeout
74
+ * @public
75
+ */
76
+ public async signSwapInitialization(
77
+ signer: StarknetSigner,
78
+ swapData: StarknetSwapData,
79
+ authorizationTimeout: number
80
+ ): Promise<{prefix: string, timeout: string, signature: string}> {
81
+ const authTimeout = Math.floor(Date.now()/1000)+authorizationTimeout;
82
+
83
+ const signature = await this.root.Signatures.signTypedMessage(signer, Initialize, "Initialize", {
84
+ "Swap hash": "0x"+swapData.getEscrowHash(),
85
+ "Timeout": toHex(authTimeout)
86
+ });
87
+
88
+ return {
89
+ prefix: this.getAuthPrefix(swapData),
90
+ timeout: authTimeout.toString(10),
91
+ signature
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Checks whether the provided signature data is valid, using preFetchedData if provided and still valid
97
+ *
98
+ * @param swapData
99
+ * @param timeout
100
+ * @param prefix
101
+ * @param signature
102
+ * @param preFetchData
103
+ * @public
104
+ */
105
+ public async isSignatureValid(
106
+ swapData: StarknetSwapData,
107
+ timeout: string,
108
+ prefix: string,
109
+ signature: string,
110
+ preFetchData?: StarknetPreFetchVerification
111
+ ): Promise<null> {
112
+ const sender = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
113
+ const signer = swapData.isPayIn() ? swapData.claimer : swapData.offerer;
114
+
115
+ if(!swapData.isPayIn() && await this.root.isExpired(sender.toString(), swapData)) {
116
+ throw new SignatureVerificationError("Swap will expire too soon!");
117
+ }
118
+
119
+ if(prefix!==this.getAuthPrefix(swapData)) throw new SignatureVerificationError("Invalid prefix");
120
+
121
+ const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
122
+ const timeoutBN = BigInt(timeout);
123
+ const isExpired = (timeoutBN - currentTimestamp) < BigInt(this.root.authGracePeriod);
124
+ if (isExpired) throw new SignatureVerificationError("Authorization expired!");
125
+ if(await this.isSignatureExpired(timeout, preFetchData)) throw new SignatureVerificationError("Authorization expired!");
126
+
127
+ const valid = await this.root.Signatures.isValidSignature(signature, signer, Initialize, "Initialize", {
128
+ "Swap hash": "0x"+swapData.getEscrowHash(),
129
+ "Timeout": toHex(timeoutBN)
130
+ });
131
+
132
+ if(!valid) throw new SignatureVerificationError("Invalid signature!");
133
+
134
+ return null;
135
+ }
136
+
137
+ /**
138
+ * Gets expiry of the provided signature data, this is a minimum of slot expiry & swap signature expiry
139
+ *
140
+ * @param timeout
141
+ * @public
142
+ */
143
+ public async getSignatureExpiry(
144
+ timeout: string
145
+ ): Promise<number> {
146
+ const now = Date.now();
147
+ const timeoutExpiryTime = (parseInt(timeout)-this.root.authGracePeriod)*1000;
148
+
149
+ if(timeoutExpiryTime<now) return 0;
150
+
151
+ return timeoutExpiryTime;
152
+ }
153
+
154
+ /**
155
+ * Checks whether signature is expired for good, compares the timestamp to the current "pending" block timestamp
156
+ *
157
+ * @param timeout
158
+ * @param preFetchData
159
+ * @public
160
+ */
161
+ public async isSignatureExpired(
162
+ timeout: string,
163
+ preFetchData?: StarknetPreFetchVerification
164
+ ): Promise<boolean> {
165
+ if(preFetchData==null || preFetchData.pendingBlockTime==null) {
166
+ preFetchData = await this.preFetchForInitSignatureVerification();
167
+ }
168
+ return preFetchData.pendingBlockTime > parseInt(timeout);
169
+ }
170
+
171
+ /**
172
+ * Creates init transaction with a valid signature from an LP
173
+ *
174
+ * @param swapData swap to initialize
175
+ * @param timeout init signature timeout
176
+ * @param prefix init signature prefix
177
+ * @param signature init signature
178
+ * @param skipChecks whether to skip signature validity checks
179
+ * @param feeRate fee rate to use for the transaction
180
+ */
181
+ public async txsInit(
182
+ swapData: StarknetSwapData,
183
+ timeout: string,
184
+ prefix: string,
185
+ signature: string,
186
+ skipChecks?: boolean,
187
+ feeRate?: string
188
+ ): Promise<StarknetTx[]> {
189
+ const sender = swapData.isPayIn() ? swapData.offerer : swapData.claimer;
190
+
191
+ if(!skipChecks) {
192
+ const [_, payStatus] = await Promise.all([
193
+ tryWithRetries(
194
+ () => this.isSignatureValid(swapData, timeout, prefix, signature),
195
+ this.retryPolicy, (e) => e instanceof SignatureVerificationError
196
+ ),
197
+ tryWithRetries(() => this.root.getCommitStatus(sender, swapData), this.retryPolicy)
198
+ ]);
199
+ if(payStatus!==SwapCommitStatus.NOT_COMMITED) throw new SwapDataVerificationError("Invoice already being paid for or paid");
200
+ }
201
+
202
+ feeRate ??= await this.root.Fees.getFeeRate();
203
+
204
+ const initAction = this.Init(swapData, BigInt(timeout), JSON.parse(signature));
205
+ if(swapData.payIn) initAction.addAction(
206
+ this.root.Tokens.Approve(sender, this.contract.address, swapData.token, swapData.amount), 0
207
+ ); //Add erc20 approve
208
+ if(swapData.getTotalDeposit() !== 0n) initAction.addAction(
209
+ this.root.Tokens.Approve(sender, this.contract.address, swapData.feeToken, swapData.getTotalDeposit()), 0
210
+ ); //Add deposit erc20 approve
211
+
212
+ this.logger.debug("txsInitPayIn(): create swap init TX, swap: "+swapData.getClaimHash()+
213
+ " feerate: "+feeRate);
214
+
215
+ return [await initAction.tx(feeRate)];
216
+ }
217
+
218
+ /**
219
+ * Get the estimated solana fee of the init transaction, this includes the required deposit for creating swap PDA
220
+ * and also deposit for ATAs
221
+ */
222
+ async getInitFee(swapData?: StarknetSwapData, feeRate?: string): Promise<bigint> {
223
+ feeRate ??= await this.root.Fees.getFeeRate();
224
+ return StarknetFees.getGasFee(swapData.payIn ? StarknetSwapInit.GasCosts.INIT_PAY_IN.l1 : StarknetSwapInit.GasCosts.INIT.l1, feeRate);
225
+ }
226
+ }
@@ -0,0 +1,202 @@
1
+ import {SignatureVerificationError, SwapDataVerificationError} from "@atomiqlabs/base";
2
+ import {toHex, tryWithRetries} from "../../../utils/Utils";
3
+ import {StarknetSwapModule} from "../StarknetSwapModule";
4
+ import {StarknetSwapData} from "../StarknetSwapData";
5
+ import {StarknetAction, StarknetGas, sumStarknetGas} from "../../base/StarknetAction";
6
+ import {StarknetSwapContract} from "../StarknetSwapContract";
7
+ import {IHandler} from "../handlers/IHandler";
8
+ import {BigNumberish} from "starknet";
9
+ import {StarknetTx} from "../../base/modules/StarknetTransactions";
10
+ import {StarknetSigner} from "../../wallet/StarknetSigner";
11
+ import {StarknetFees} from "../../base/modules/StarknetFees";
12
+
13
+ const Refund = [
14
+ { name: 'Swap hash', type: 'felt' },
15
+ { name: 'Timeout', type: 'timestamp' }
16
+ ];
17
+
18
+ export class StarknetSwapRefund extends StarknetSwapModule {
19
+
20
+ private static readonly GasCosts = {
21
+ REFUND: {l1: 750, l2: 0},
22
+ REFUND_PAY_OUT: {l1: 1250, l2: 0}
23
+ };
24
+
25
+ /**
26
+ * Action for generic Refund instruction
27
+ *
28
+ * @param signer
29
+ * @param swapData
30
+ * @param witness
31
+ * @param handlerGas
32
+ * @constructor
33
+ * @private
34
+ */
35
+ private Refund(
36
+ signer: string,
37
+ swapData: StarknetSwapData,
38
+ witness: BigNumberish[],
39
+ handlerGas?: StarknetGas
40
+ ): StarknetAction {
41
+ return new StarknetAction(signer, this.root,
42
+ this.contract.populateTransaction.refund(swapData.toEscrowStruct(), witness),
43
+ sumStarknetGas(swapData.payIn ? StarknetSwapRefund.GasCosts.REFUND_PAY_OUT : StarknetSwapRefund.GasCosts.REFUND, handlerGas)
44
+ );
45
+ }
46
+
47
+ /**
48
+ * Action for cooperative refunding with signature
49
+ *
50
+ * @param sender
51
+ * @param swapData
52
+ * @param timeout
53
+ * @param signature
54
+ * @constructor
55
+ * @private
56
+ */
57
+ private RefundWithSignature(
58
+ sender: string,
59
+ swapData: StarknetSwapData,
60
+ timeout: string,
61
+ signature: BigNumberish[]
62
+ ): StarknetAction {
63
+ return new StarknetAction(sender, this.root,
64
+ this.contract.populateTransaction.cooperative_refund(swapData.toEscrowStruct(), signature, BigInt(timeout)),
65
+ swapData.payIn ? StarknetSwapRefund.GasCosts.REFUND_PAY_OUT : StarknetSwapRefund.GasCosts.REFUND
66
+ );
67
+ }
68
+
69
+ constructor(root: StarknetSwapContract) {
70
+ super(root);
71
+ }
72
+
73
+ public async signSwapRefund(
74
+ signer: StarknetSigner,
75
+ swapData: StarknetSwapData,
76
+ authorizationTimeout: number
77
+ ): Promise<{ prefix: string; timeout: string; signature: string }> {
78
+ const authPrefix = "refund";
79
+ const authTimeout = Math.floor(Date.now()/1000)+authorizationTimeout;
80
+
81
+ const signature = await this.root.Signatures.signTypedMessage(signer, Refund, "Refund", {
82
+ "Swap hash": "0x"+swapData.getEscrowHash(),
83
+ "Timeout": toHex(authTimeout)
84
+ });
85
+
86
+ return {
87
+ prefix: authPrefix,
88
+ timeout: authTimeout.toString(10),
89
+ signature: signature
90
+ };
91
+ }
92
+
93
+ public async isSignatureValid(
94
+ swapData: StarknetSwapData,
95
+ timeout: string,
96
+ prefix: string,
97
+ signature: string
98
+ ): Promise<null> {
99
+ if(prefix!=="refund") throw new SignatureVerificationError("Invalid prefix");
100
+
101
+ const expiryTimestamp = BigInt(timeout);
102
+ const currentTimestamp = BigInt(Math.floor(Date.now() / 1000));
103
+
104
+ const isExpired = (expiryTimestamp - currentTimestamp) < BigInt(this.root.authGracePeriod);
105
+ if(isExpired) throw new SignatureVerificationError("Authorization expired!");
106
+
107
+ const valid = await this.root.Signatures.isValidSignature(signature, swapData.claimer, Refund, "Refund", {
108
+ "Swap hash": "0x"+swapData.getEscrowHash(),
109
+ "Timeout": toHex(expiryTimestamp)
110
+ });
111
+
112
+ if(!valid) {
113
+ throw new SignatureVerificationError("Invalid signature!");
114
+ }
115
+
116
+ return null;
117
+ }
118
+
119
+ /**
120
+ * Creates transactions required for refunding timed out swap
121
+ *
122
+ * @param signer
123
+ * @param swapData swap data to refund
124
+ * @param check whether to check if swap is already expired and refundable
125
+ * @param feeRate fee rate to be used for the transactions
126
+ * @param witnessData
127
+ */
128
+ public async txsRefund<T>(
129
+ signer: string,
130
+ swapData: StarknetSwapData,
131
+ check?: boolean,
132
+ feeRate?: string,
133
+ witnessData?: T
134
+ ): Promise<StarknetTx[]> {
135
+ const refundHandler: IHandler<any, T> = this.root.refundHandlersByAddress[swapData.refundHandler.toLowerCase()];
136
+ if(refundHandler==null) throw new Error("Invalid refund handler");
137
+
138
+ if(check && !await tryWithRetries(() => this.root.isRequestRefundable(swapData.offerer.toString(), swapData), this.retryPolicy)) {
139
+ throw new SwapDataVerificationError("Not refundable yet!");
140
+ }
141
+
142
+ feeRate ??= await this.root.Fees.getFeeRate();
143
+
144
+ const {initialTxns, witness} = await refundHandler.getWitness(signer, swapData, witnessData, feeRate);
145
+
146
+ const action = this.Refund(signer, swapData, witness, refundHandler.getGas(swapData));
147
+ await action.addToTxs(initialTxns, feeRate);
148
+
149
+ this.logger.debug("txsRefund(): creating refund transaction, swap: "+swapData.getClaimHash());
150
+
151
+ return initialTxns;
152
+ }
153
+
154
+ /**
155
+ * Creates transactions required for refunding the swap with authorization signature, also unwraps WSOL to SOL
156
+ *
157
+ * @param signer
158
+ * @param swapData swap data to refund
159
+ * @param timeout signature timeout
160
+ * @param prefix signature prefix of the counterparty
161
+ * @param signature signature of the counterparty
162
+ * @param check whether to check if swap is committed before attempting refund
163
+ * @param feeRate fee rate to be used for the transactions
164
+ */
165
+ public async txsRefundWithAuthorization(
166
+ signer: string,
167
+ swapData: StarknetSwapData,
168
+ timeout: string,
169
+ prefix: string,
170
+ signature: string,
171
+ check?: boolean,
172
+ feeRate?: string
173
+ ): Promise<StarknetTx[]> {
174
+ if(check && !await tryWithRetries(() => this.root.isCommited(swapData), this.retryPolicy)) {
175
+ throw new SwapDataVerificationError("Not correctly committed");
176
+ }
177
+ await tryWithRetries(
178
+ () => this.isSignatureValid(swapData, timeout, prefix, signature),
179
+ this.retryPolicy,
180
+ (e) => e instanceof SignatureVerificationError
181
+ );
182
+
183
+ const action = this.RefundWithSignature(signer, swapData, timeout, JSON.parse(signature));
184
+
185
+ feeRate ??= await this.root.Fees.getFeeRate();
186
+
187
+ this.logger.debug("txsRefundWithAuthorization(): creating refund transaction, swap: "+swapData.getClaimHash()+
188
+ " auth expiry: "+timeout+" signature: "+signature);
189
+
190
+ return [await action.tx(feeRate)];
191
+ }
192
+
193
+ /**
194
+ * Get the estimated solana transaction fee of the refund transaction, in the worst case scenario in case where the
195
+ * ATA needs to be initialized again (i.e. adding the ATA rent exempt lamports to the fee)
196
+ */
197
+ async getRefundFee(swapData: StarknetSwapData, feeRate?: string): Promise<bigint> {
198
+ feeRate ??= await this.root.Fees.getFeeRate();
199
+ return StarknetFees.getGasFee(swapData.payIn ? StarknetSwapRefund.GasCosts.REFUND_PAY_OUT.l1 : StarknetSwapRefund.GasCosts.REFUND.l1, feeRate);
200
+ }
201
+
202
+ }
@@ -0,0 +1,34 @@
1
+ import {Account, CallData, DeployAccountContractPayload, ec, hash, Provider} from "starknet";
2
+ import {toHex} from "../../utils/Utils";
3
+
4
+ const OZaccountClassHash = '0x066358a3bf5515033abe327a433e2947f9ee8dcd500ccb260f710b47039ebd36';
5
+
6
+ //Openzeppelin Account wallet
7
+ export class StarknetKeypairWallet extends Account {
8
+
9
+ public readonly publicKey: string;
10
+
11
+ constructor(provider: Provider, privateKey: string) {
12
+ const publicKey = ec.starkCurve.getStarkKey(toHex(privateKey));
13
+ // Calculate future address of the account
14
+ const OZaccountConstructorCallData = CallData.compile({ publicKey });
15
+ const OZcontractAddress = hash.calculateContractAddressFromHash(
16
+ publicKey,
17
+ OZaccountClassHash,
18
+ OZaccountConstructorCallData,
19
+ 0
20
+ );
21
+ super(provider, OZcontractAddress, privateKey, "1");
22
+ this.publicKey = publicKey;
23
+ }
24
+
25
+ public getDeploymentData(): DeployAccountContractPayload {
26
+ return {
27
+ classHash: OZaccountClassHash,
28
+ constructorCalldata: CallData.compile({ publicKey: this.publicKey }),
29
+ addressSalt: this.publicKey,
30
+ contractAddress: this.address
31
+ }
32
+ }
33
+
34
+ }
@@ -0,0 +1,55 @@
1
+ import {AbstractSigner} from "@atomiqlabs/base";
2
+ import {Account, DeployAccountContractPayload} from "starknet";
3
+ import {toHex} from "../../utils/Utils";
4
+
5
+ export class StarknetSigner implements AbstractSigner {
6
+
7
+ account: Account;
8
+
9
+ isDeployed: boolean = null;
10
+
11
+ constructor(account: Account) {
12
+ this.account = account;
13
+ }
14
+
15
+ getPublicKey(): Promise<string> {
16
+ return this.account.signer.getPubKey();
17
+ }
18
+
19
+ getAddress(): string {
20
+ return toHex(this.account.address);
21
+ }
22
+
23
+ isWalletAccount() {
24
+ return (this.account as any).walletProvider!=null;
25
+ }
26
+
27
+ //TODO: Introduce proper nonce management!
28
+ async getNonce(): Promise<bigint> {
29
+ try {
30
+ return BigInt(await this.account.getNonceForAddress(this.getAddress()));
31
+ } catch (e) {
32
+ if(e.message!=null && e.message.includes("20: Contract not found")) {
33
+ return BigInt(0);
34
+ }
35
+ throw e;
36
+ }
37
+ }
38
+
39
+ async checkAndGetDeployPayload(nonce?: bigint): Promise<DeployAccountContractPayload | null> {
40
+ if(this.isDeployed) return null;
41
+
42
+ const _account: Account & {getDeploymentData?: () => DeployAccountContractPayload} = this.account;
43
+ if(_account.getDeploymentData!=null) {
44
+ //Check if deployed
45
+ nonce ??= BigInt(await this.getNonce());
46
+ this.isDeployed = nonce!=BigInt(0);
47
+ if(!this.isDeployed ) {
48
+ return _account.getDeploymentData();
49
+ }
50
+ }
51
+
52
+ return null;
53
+ }
54
+
55
+ }