@@ -2,13 +2,17 @@ package client
2
2
3
3
import (
4
4
"context"
5
+ "encoding/hex"
6
+ "errors"
5
7
"fmt"
6
- "log "
8
+ "math/big "
7
9
"strings"
8
10
"time"
9
11
12
+ "github.com/1inch/1inch-sdk/golang/client/tenderly"
10
13
"github.com/1inch/1inch-sdk/golang/helpers"
11
14
"github.com/1inch/1inch-sdk/golang/helpers/consts/chains"
15
+ "github.com/1inch/1inch-sdk/golang/helpers/consts/tokens"
12
16
"github.com/ethereum/go-ethereum/common"
13
17
14
18
"github.com/1inch/1inch-sdk/golang/client/onchain"
@@ -18,6 +22,8 @@ import (
18
22
"github.com/1inch/1inch-sdk/golang/helpers/consts/typehashes"
19
23
)
20
24
25
+ // This file provides helper functions that execute swaps onchain.
26
+
21
27
type ActionService service
22
28
23
29
// TODO temporarily adding a bool to the function call until config refactor
@@ -59,10 +65,6 @@ func (s *ActionService) SwapTokens(swapParams swap.AggregationControllerGetSwapP
59
65
Slippage : swapParams .Slippage ,
60
66
}
61
67
62
- if shouldTryPermit (s .client .ChainId , approvalType ) {
63
-
64
- }
65
-
66
68
var usePermit bool
67
69
68
70
// Currently, Permit1 swaps are only tested on Ethereum and Polygon
@@ -77,7 +79,7 @@ func (s *ActionService) SwapTokens(swapParams swap.AggregationControllerGetSwapP
77
79
if typehash == typehashes .Permit1 {
78
80
usePermit = true
79
81
} else {
80
- log .Printf ("Typehash exists, but it is not recognized: %v\n " , typehash )
82
+ fmt .Printf ("WARN: Typehash exists, but it is not recognized: %v\n " , typehash )
81
83
}
82
84
}
83
85
}
@@ -143,6 +145,176 @@ func (s *ActionService) SwapTokens(swapParams swap.AggregationControllerGetSwapP
143
145
return nil
144
146
}
145
147
146
- func shouldTryPermit (chainId int , approvalType swap.ApprovalType ) bool {
147
- return approvalType == swap .PermitIfPossible || approvalType == swap .PermitAlways
148
+ // ExecuteSwap executes a swap on the Ethereum blockchain using swap data generated by GetSwapData
149
+ func (s * SwapService ) ExecuteSwap (config * swap.ExecuteSwapConfig ) error {
150
+
151
+ if s .client .WalletKey == "" {
152
+ return fmt .Errorf ("wallet key must be set in the client config" )
153
+ }
154
+
155
+ if ! config .SkipWarnings {
156
+ ok , err := swap .ConfirmExecuteSwapWithUser (config , s .client .EthClient )
157
+ if err != nil {
158
+ return fmt .Errorf ("failed to confirm swap: %v" , err )
159
+ }
160
+ if ! ok {
161
+ return errors .New ("user rejected trade" )
162
+ }
163
+ }
164
+
165
+ aggregationRouter , err := contracts .Get1inchRouterFromChainId (s .client .ChainId )
166
+ if err != nil {
167
+ return fmt .Errorf ("failed to get 1inch router address: %v" , err )
168
+ }
169
+
170
+ if ! config .IsPermitSwap {
171
+ err = s .executeSwapWithApproval (aggregationRouter , config .FromToken , config .Amount , config .TransactionData , config .SkipWarnings )
172
+ if err != nil {
173
+ return fmt .Errorf ("failed to execute swap with approval: %v" , err )
174
+ }
175
+ } else {
176
+ err = s .executeSwapWithPermit (config .FromToken , config .TransactionData )
177
+ if err != nil {
178
+ return fmt .Errorf ("failed to execute swap with permit: %v" , err )
179
+ }
180
+ }
181
+
182
+ return nil
183
+ }
184
+
185
+ func (s * SwapService ) executeSwapWithApproval (spenderAddress string , fromToken string , amount string , transactionData string , skipWarnings bool ) error {
186
+
187
+ var value * big.Int
188
+ var err error
189
+ var approveFirst bool
190
+ if fromToken != tokens .NativeToken {
191
+ // When swapping erc20 tokens, the value set on the transaction will be 0
192
+ value = big .NewInt (0 )
193
+
194
+ allowance , err := onchain .ReadContractAllowance (s .client .EthClient , common .HexToAddress (fromToken ), s .client .PublicAddress , common .HexToAddress (spenderAddress ))
195
+ if err != nil {
196
+ return fmt .Errorf ("failed to read allowance: %v" , err )
197
+ }
198
+
199
+ amountBig , err := helpers .BigIntFromString (amount )
200
+ if err != nil {
201
+ return fmt .Errorf ("failed to convert amount to big.Int: %v" , err )
202
+ }
203
+ if allowance .Cmp (amountBig ) <= 0 {
204
+ if ! skipWarnings {
205
+ ok , err := swap .ConfirmApprovalWithUser (s .client .EthClient , s .client .PublicAddress .Hex (), fromToken )
206
+ if err != nil {
207
+ return fmt .Errorf ("failed to confirm approval: %v" , err )
208
+ }
209
+ if ! ok {
210
+ return errors .New ("user rejected approval" )
211
+ }
212
+ }
213
+
214
+ approveFirst = true
215
+
216
+ // Only run the approval if a tenderly key is not present
217
+ if s .client .TenderlyKey == "" {
218
+ erc20Config := onchain.Erc20ApprovalConfig {
219
+ ChainId : s .client .ChainId ,
220
+ Key : s .client .WalletKey ,
221
+ Erc20Address : common .HexToAddress (fromToken ),
222
+ PublicAddress : s .client .PublicAddress ,
223
+ SpenderAddress : common .HexToAddress (spenderAddress ),
224
+ }
225
+ err = onchain .ApproveTokenForRouter (s .client .EthClient , s .client .NonceCache , erc20Config )
226
+ if err != nil {
227
+ return fmt .Errorf ("failed to approve token for router: %v" , err )
228
+ }
229
+ helpers .Sleep ()
230
+ }
231
+ }
232
+ } else {
233
+ // When swapping from the native token, there is no need for an approval and the amount passed in must be explicitly set
234
+ value , err = helpers .BigIntFromString (amount )
235
+ if err != nil {
236
+ return fmt .Errorf ("failed to convert amount to big.Int: %v" , err )
237
+ }
238
+ }
239
+
240
+ hexData , err := hex .DecodeString (transactionData [2 :])
241
+ if err != nil {
242
+ return fmt .Errorf ("failed to decode swap data: %v" , err )
243
+ }
244
+
245
+ aggregationRouter , err := contracts .Get1inchRouterFromChainId (s .client .ChainId )
246
+ if err != nil {
247
+ return fmt .Errorf ("failed to get 1inch router address: %v" , err )
248
+ }
249
+
250
+ txConfig := onchain.TxConfig {
251
+ Description : "Swap" ,
252
+ PublicAddress : s .client .PublicAddress ,
253
+ PrivateKey : s .client .WalletKey ,
254
+ ChainId : big .NewInt (int64 (s .client .ChainId )),
255
+ Value : value ,
256
+ To : aggregationRouter ,
257
+ Data : hexData ,
258
+ }
259
+
260
+ if s .client .TenderlyKey != "" {
261
+ _ , err := tenderly .SimulateSwap (s .client .TenderlyKey , tenderly.SwapConfig {
262
+ ChainId : s .client .ChainId ,
263
+ PublicAddress : s .client .PublicAddress .Hex (),
264
+ FromToken : fromToken ,
265
+ TransactionData : transactionData ,
266
+ ApproveFirst : approveFirst ,
267
+ Value : value .String (),
268
+ })
269
+ if err != nil {
270
+ return fmt .Errorf ("failed to execute tenderly simulation: %v" , err )
271
+ }
272
+ } else {
273
+ err = onchain .ExecuteTransaction (txConfig , s .client .EthClient , s .client .NonceCache )
274
+ if err != nil {
275
+ return fmt .Errorf ("failed to execute transaction: %v" , err )
276
+ }
277
+ }
278
+ return nil
279
+ }
280
+
281
+ func (s * SwapService ) executeSwapWithPermit (fromToken string , transactionData string ) error {
282
+
283
+ hexData , err := hex .DecodeString (transactionData [2 :])
284
+ if err != nil {
285
+ return fmt .Errorf ("failed to decode swap data: %v" , err )
286
+ }
287
+
288
+ aggregationRouter , err := contracts .Get1inchRouterFromChainId (s .client .ChainId )
289
+ if err != nil {
290
+ return fmt .Errorf ("failed to get 1inch router address: %v" , err )
291
+ }
292
+
293
+ txConfig := onchain.TxConfig {
294
+ Description : "Swap" ,
295
+ PublicAddress : s .client .PublicAddress ,
296
+ PrivateKey : s .client .WalletKey ,
297
+ ChainId : big .NewInt (int64 (s .client .ChainId )),
298
+ Value : big .NewInt (0 ),
299
+ To : aggregationRouter ,
300
+ Data : hexData ,
301
+ }
302
+ if s .client .TenderlyKey != "" {
303
+ _ , err := tenderly .SimulateSwap (s .client .TenderlyKey , tenderly.SwapConfig {
304
+ ChainId : s .client .ChainId ,
305
+ PublicAddress : s .client .PublicAddress .Hex (),
306
+ FromToken : fromToken ,
307
+ TransactionData : transactionData ,
308
+ Value : "0" ,
309
+ })
310
+ if err != nil {
311
+ return fmt .Errorf ("failed to execute tenderly simulation: %v" , err )
312
+ }
313
+ } else {
314
+ err = onchain .ExecuteTransaction (txConfig , s .client .EthClient , s .client .NonceCache )
315
+ if err != nil {
316
+ return fmt .Errorf ("failed to execute transaction: %v" , err )
317
+ }
318
+ }
319
+ return nil
148
320
}
0 commit comments