@@ -297,6 +297,156 @@ print("w3s token balance = " + String(bal))
297
297
298
298
## Transactions Operations
299
299
300
+ #### Web3Options
301
+
302
+ ``` swift
303
+ /// A web3 instance bound to provider. All further functionality is provided under web.*. namespaces.
304
+ public class web3 : Web3OptionsInheritable {
305
+ public var provider : Web3Provider
306
+ public var options : Web3Options = Web3Options.defaultOptions ()
307
+ public var defaultBlock = " latest"
308
+ public var requestDispatcher: JSONRPCrequestDispatcher
309
+
310
+ /// Add a provider request to the dispatch queue.
311
+ public func dispatch (_ request : JSONRPCrequest) -> Promise<JSONRPCresponse> {
312
+ return self .requestDispatcher .addToQueue (request : request)
313
+ }
314
+
315
+ /// Raw initializer using a Web3Provider protocol object, dispatch queue and request dispatcher.
316
+ public init (provider prov : Web3Provider, queue : OperationQueue? = nil , requestDispatcher : JSONRPCrequestDispatcher? = nil ) {
317
+ provider = prov
318
+ if requestDispatcher == nil {
319
+ self .requestDispatcher = JSONRPCrequestDispatcher (provider : provider, queue : DispatchQueue.global (qos : .userInteractive ), policy : .Batch (32 ))
320
+ } else {
321
+ self .requestDispatcher = requestDispatcher!
322
+ }
323
+ }
324
+
325
+ /// Keystore manager can be bound to Web3 instance. If some manager is bound all further account related functions, such
326
+ /// as account listing, transaction signing, etc. are done locally using private keys and accounts found in a manager.
327
+ public func addKeystoreManager (_ manager : KeystoreManager? ) {
328
+ self .provider .attachedKeystoreManager = manager
329
+ }
330
+
331
+ var ethInstance: web3.Eth?
332
+
333
+ /// Public web3.eth.* namespace.
334
+ public var eth: web3.Eth {
335
+ if (self .ethInstance != nil ) {
336
+ return self .ethInstance !
337
+ }
338
+ self .ethInstance = web3.Eth (provider : self .provider , web3 : self )
339
+ return self .ethInstance !
340
+ }
341
+
342
+ public class Eth :Web3OptionsInheritable {
343
+ var provider:Web3Provider
344
+ // weak var web3: web3?
345
+ var web3: web3
346
+ public var options: Web3Options {
347
+ return self .web3 .options
348
+ }
349
+ public init (provider prov : Web3Provider, web3 web3instance : web3) {
350
+ provider = prov
351
+ web3 = web3instance
352
+ }
353
+ }
354
+
355
+ var personalInstance: web3.Personal?
356
+
357
+ /// Public web3.personal.* namespace.
358
+ public var personal: web3.Personal {
359
+ if (self .personalInstance != nil ) {
360
+ return self .personalInstance !
361
+ }
362
+ self .personalInstance = web3.Personal (provider : self .provider , web3 : self )
363
+ return self .personalInstance !
364
+ }
365
+
366
+ public class Personal :Web3OptionsInheritable {
367
+ var provider:Web3Provider
368
+ // weak var web3: web3?
369
+ var web3: web3
370
+ public var options: Web3Options {
371
+ return self .web3 .options
372
+ }
373
+ public init (provider prov : Web3Provider, web3 web3instance : web3) {
374
+ provider = prov
375
+ web3 = web3instance
376
+ }
377
+ }
378
+
379
+ var walletInstance: web3.Web3Wallet?
380
+
381
+ /// Public web3.wallet.* namespace.
382
+ public var wallet: web3.Web3Wallet {
383
+ if (self .walletInstance != nil ) {
384
+ return self .walletInstance !
385
+ }
386
+ self .walletInstance = web3.Web3Wallet (provider : self .provider , web3 : self )
387
+ return self .walletInstance !
388
+ }
389
+
390
+ public class Web3Wallet {
391
+ var provider:Web3Provider
392
+ // weak var web3: web3?
393
+ var web3: web3
394
+ public init (provider prov : Web3Provider, web3 web3instance : web3) {
395
+ provider = prov
396
+ web3 = web3instance
397
+ }
398
+ }
399
+
400
+ var browserFunctionsInstance: web3.BrowserFunctions?
401
+
402
+ /// Public web3.browserFunctions.* namespace.
403
+ public var browserFunctions: web3.BrowserFunctions {
404
+ if (self .browserFunctionsInstance != nil ) {
405
+ return self .browserFunctionsInstance !
406
+ }
407
+ self .browserFunctionsInstance = web3.BrowserFunctions (provider : self .provider , web3 : self )
408
+ return self .browserFunctionsInstance !
409
+ }
410
+
411
+ public class BrowserFunctions :Web3OptionsInheritable {
412
+ var provider:Web3Provider
413
+ // weak var web3: web3?
414
+ var web3: web3
415
+ public var options: Web3Options {
416
+ return self .web3 .options
417
+ }
418
+ public init (provider prov : Web3Provider, web3 web3instance : web3) {
419
+ provider = prov
420
+ web3 = web3instance
421
+ }
422
+ }
423
+
424
+ var erc721Instance: web3.ERC721?
425
+
426
+ /// Public web3.browserFunctions.* namespace.
427
+ public var erc721: web3.ERC721 {
428
+ if (self .erc721Instance != nil ) {
429
+ return self .erc721Instance !
430
+ }
431
+ self .erc721Instance = web3.ERC721 (provider : self .provider , web3 : self )
432
+ return self .erc721Instance !
433
+ }
434
+
435
+ public class ERC721 : Web3OptionsInheritable {
436
+ var provider:Web3Provider
437
+ // weak var web3: web3?
438
+ var web3: web3
439
+ public var options: Web3Options {
440
+ return self .web3 .options
441
+ }
442
+ public init (provider prov : Web3Provider, web3 web3instance : web3) {
443
+ provider = prov
444
+ web3 = web3instance
445
+ }
446
+ }
447
+ }
448
+ ```
449
+
300
450
### Prepare Transaction
301
451
302
452
#### Setting Transaction Options
@@ -313,6 +463,209 @@ options.gasLimit = gasLimit
313
463
options.from = EthereumAddress (" 0xE6877A4d8806e9A9F12eB2e8561EA6c1db19978d" )
314
464
```
315
465
466
+ #### Preparing Transaction For Sending Ether
467
+
468
+ ``` swift
469
+ public func prepareTransactionForSendingEther (destinationAddressString : String ,
470
+ amountString : String ,
471
+ gasLimit : BigUInt,
472
+ completion : @escaping (Result<TransactionIntermediate>) -> Void ) {
473
+ DispatchQueue.global (qos : .userInitiated ).async {
474
+ guard let destinationEthAddress = EthereumAddress (destinationAddressString) else {
475
+ DispatchQueue.main .async {
476
+ completion (Result.Error (SendErrors.invalidDestinationAddress ))
477
+ }
478
+ return
479
+ }
480
+ guard let amount = Web3.Utils.parseToBigUInt (amountString, units : .eth ) else {
481
+ DispatchQueue.main .async {
482
+ completion (Result.Error (SendErrors.invalidAmountFormat ))
483
+ }
484
+ return
485
+ }
486
+ guard let selectedKey = KeysService ().selectedWallet ()? .address else {
487
+ DispatchQueue.main .async {
488
+ completion (Result.Error (SendErrors.noAvailableKeys ))
489
+ }
490
+ return
491
+ }
492
+
493
+
494
+ let web3 = web3swift.web3 (provider : InfuraProvider (CurrentNetwork.currentNetwork ?? Networks.Mainnet )! )
495
+ web3.addKeystoreManager (KeysService ().keystoreManager ())
496
+
497
+ let ethAddressFrom = EthereumAddress (selectedKey)
498
+ var options = Web3Options.defaultOptions ()
499
+ options.from = ethAddressFrom
500
+ options.value = BigUInt (amount)
501
+
502
+ guard let contract = web3.contract (Web3.Utils .coldWalletABI , at : destinationEthAddress) else {
503
+ DispatchQueue.main .async {
504
+ completion (Result.Error (SendErrors.contractLoadingError ))
505
+ }
506
+ return
507
+ }
508
+
509
+ guard let estimatedGas = contract.method (options : options)? .estimateGas (options : nil ).value else {
510
+ DispatchQueue.main .async {
511
+ completion (Result.Error (SendErrors.retrievingEstimatedGasError ))
512
+ }
513
+ return
514
+ }
515
+ options.gasLimit = estimatedGas
516
+
517
+ guard let gasPrice = web3.eth.getGasPrice ().value else {
518
+ DispatchQueue.main .async {
519
+ completion (Result.Error (SendErrors.retrievingGasPriceError ))
520
+ }
521
+ return
522
+ }
523
+ options.gasPrice = gasPrice
524
+
525
+ guard let transaction = contract.method (options : options) else {
526
+ DispatchQueue.main .async {
527
+ completion (Result.Error (SendErrors.createTransactionIssue ))
528
+ }
529
+ return
530
+ }
531
+
532
+ DispatchQueue.main .async {
533
+ completion (Result.Success (transaction))
534
+ }
535
+
536
+ }
537
+ }
538
+ ```
539
+
540
+ #### Preparing Transaction For Sending ERC-20 tokens
541
+
542
+ ``` swift
543
+ public func prepareTransactionForSendingERC (destinationAddressString : String ,
544
+ amountString : String ,
545
+ gasLimit : BigUInt,
546
+ tokenAddress token : String ,
547
+ completion : @escaping (Result<TransactionIntermediate>) -> Void ) {
548
+ DispatchQueue.global (qos : .userInitiated ).async {
549
+ guard let destinationEthAddress = EthereumAddress (destinationAddressString) else {
550
+ DispatchQueue.main .async {
551
+ completion (Result.Error (SendErrors.invalidDestinationAddress ))
552
+ }
553
+ return
554
+ }
555
+ guard let amount = Web3.Utils.parseToBigUInt (amountString, units : .eth ) else {
556
+ DispatchQueue.main .async {
557
+ completion (Result.Error (SendErrors.invalidAmountFormat ))
558
+ }
559
+ return
560
+ }
561
+
562
+ let web3 = web3swift.web3 (provider : InfuraProvider (CurrentNetwork.currentNetwork ?? Networks.Mainnet )! )
563
+ web3.addKeystoreManager (KeysService ().keystoreManager ())
564
+
565
+ let contract = self .contract (for : token, web3 : web3)
566
+ var options = Web3Options.defaultOptions ()
567
+
568
+ guard let tokenAddress = EthereumAddress (token),
569
+ let fromAddress = Web3SwiftService.currentAddress,
570
+ let intermediate = web3.eth.sendERC20tokensWithNaturalUnits (
571
+ tokenAddress : tokenAddress,
572
+ from : fromAddress,
573
+ to : destinationEthAddress,
574
+ amount : amountString) else {
575
+ DispatchQueue.main .async {
576
+ completion (Result.Error (SendErrors.createTransactionIssue ))
577
+ }
578
+ return
579
+ }
580
+ DispatchQueue.main .async {
581
+ completion (Result.Success (intermediate))
582
+ }
583
+
584
+ // MARK: - Just to check that everything is all right
585
+ guard let _ = contract? .method (options : options)? .estimateGas (options : options).value else {
586
+ DispatchQueue.main .async {
587
+ completion (Result.Error (SendErrors.retrievingEstimatedGasError ))
588
+ }
589
+ return
590
+ }
591
+ guard let gasPrice = web3.eth.getGasPrice ().value else {
592
+ DispatchQueue.main .async {
593
+ completion (Result.Error (SendErrors.retrievingGasPriceError ))
594
+ }
595
+ return
596
+ }
597
+
598
+ options.from = Web3SwiftService.currentAddress
599
+ options.gasPrice = gasPrice
600
+ // options.gasLimit = estimatedGas
601
+ options.value = 0
602
+ options.to = EthereumAddress (token)
603
+ let parameters = [destinationEthAddress,
604
+ amount] as [Any ]
605
+ guard let transaction = contract? .method (" transfer" ,
606
+ parameters : parameters as [AnyObject ],
607
+ options : options) else {
608
+ DispatchQueue.main .async {
609
+ completion (Result.Error (SendErrors.createTransactionIssue ))
610
+ }
611
+
612
+ return
613
+ }
614
+ DispatchQueue.main .async {
615
+ completion (Result.Success (transaction))
616
+ }
617
+
618
+ return
619
+ }
620
+ }
621
+ ```
622
+
623
+ #### Preparing Transaction For Sending To Some Contract
624
+
625
+ ``` swift
626
+ public func prepareTransactionToContract (data : [AnyObject ],
627
+ contractAbi : String ,
628
+ contractAddress : String ,
629
+ method : String ,
630
+ predefinedOptions : Web3Options? = nil ,
631
+ completion : @escaping (Result<TransactionIntermediate>) -> Void ) {
632
+ let wallet = TransactionsService.keyservice .selectedWallet ()
633
+ guard let address = wallet? .address else { return }
634
+ let ethAddressFrom = EthereumAddress (address)
635
+ let ethContractAddress = EthereumAddress (contractAddress)!
636
+
637
+ let web3 = CurrentWeb.currentWeb ?? Web3.InfuraMainnetWeb3 ()
638
+ web3.addKeystoreManager (TransactionsService.keyservice .keystoreManager ())
639
+ var options = predefinedOptions ?? Web3Options.defaultOptions ()
640
+ options.from = ethAddressFrom
641
+ options.to = ethContractAddress
642
+ options.value = options.value ?? 0
643
+ guard let contract = web3.contract (contractAbi,
644
+ at : ethContractAddress,
645
+ abiVersion : 2 ) else {
646
+ return
647
+ DispatchQueue.main .async {
648
+ completion (Result.Error (TransactionErrors.init (rawValue : " Can not create a contract with given abi and address." )! ))
649
+ }
650
+ }
651
+ guard let gasPrice = web3.eth.getGasPrice ().value else { return }
652
+ options.gasPrice = predefinedOptions? .gasPrice ?? gasPrice
653
+ guard let transaction = contract.method (method,
654
+ parameters : data,
655
+ options : options) else { return }
656
+ guard case .success (let estimate) = transaction.estimateGas (options : options) else {
657
+ DispatchQueue.main .async {
658
+ completion (Result.Error (TransactionErrors.PreparingError ))
659
+ }
660
+ return
661
+ }
662
+ print (" estimated cost: \( estimate ) " )
663
+ DispatchQueue.main .async {
664
+ completion (Result.Success (transaction))
665
+ }
666
+ }
667
+ ```
668
+
316
669
### Send Transaction
317
670
318
671
#### Sending ETH
0 commit comments