coinbase 0.0.1 → 4.0.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of coinbase might be problematic. Click here for more details.

Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +611 -0
  6. data/Rakefile +7 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +7 -0
  9. data/coinbase.gemspec +27 -0
  10. data/lib/coinbase/wallet/adapters/em_http.rb +78 -0
  11. data/lib/coinbase/wallet/adapters/net_http.rb +68 -0
  12. data/lib/coinbase/wallet/api_client.rb +692 -0
  13. data/lib/coinbase/wallet/api_errors.rb +120 -0
  14. data/lib/coinbase/wallet/api_response.rb +41 -0
  15. data/lib/coinbase/wallet/ca-coinbase.crt +629 -0
  16. data/lib/coinbase/wallet/client.rb +101 -0
  17. data/lib/coinbase/wallet/models/account.rb +187 -0
  18. data/lib/coinbase/wallet/models/address.rb +12 -0
  19. data/lib/coinbase/wallet/models/api_object.rb +46 -0
  20. data/lib/coinbase/wallet/models/checkout.rb +19 -0
  21. data/lib/coinbase/wallet/models/order.rb +12 -0
  22. data/lib/coinbase/wallet/models/transaction.rb +21 -0
  23. data/lib/coinbase/wallet/models/transfer.rb +13 -0
  24. data/lib/coinbase/wallet/models/user.rb +15 -0
  25. data/lib/coinbase/wallet/version.rb +5 -0
  26. data/lib/coinbase/wallet.rb +23 -156
  27. data/spec/account_spec.rb +193 -0
  28. data/spec/clients/client_spec.rb +34 -0
  29. data/spec/clients/oauth_client_spec.rb +56 -0
  30. data/spec/endpoints_spec.rb +352 -0
  31. data/spec/error_spec.rb +137 -0
  32. data/spec/models/address_spec.rb +26 -0
  33. data/spec/models/api_object_spec.rb +63 -0
  34. data/spec/models/checkout_spec.rb +52 -0
  35. data/spec/models/current_user_spec.rb +29 -0
  36. data/spec/models/order_spec.rb +52 -0
  37. data/spec/models/request_spec.rb +47 -0
  38. data/spec/models/transfer_spec.rb +64 -0
  39. data/spec/models/user_spec.rb +24 -0
  40. data/spec/spec_helper.rb +13 -0
  41. metadata +62 -98
  42. data/lib/coinbase/address.rb +0 -127
  43. data/lib/coinbase/asset.rb +0 -20
  44. data/lib/coinbase/balance_map.rb +0 -48
  45. data/lib/coinbase/constants.rb +0 -38
  46. data/lib/coinbase/network.rb +0 -55
  47. data/lib/coinbase/transfer.rb +0 -153
  48. data/lib/coinbase.rb +0 -18
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coinbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 4.0.7
5
5
  platform: ruby
6
6
  authors:
7
- - Yuga Cohler
7
+ - John Duhamel
8
+ - Jori Lallo
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2024-04-19 00:00:00.000000000 Z
12
+ date: 2015-07-28 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bigdecimal
@@ -25,55 +26,13 @@ dependencies:
25
26
  - !ruby/object:Gem::Version
26
27
  version: '0'
27
28
  - !ruby/object:Gem::Dependency
28
- name: dotenv
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '='
32
- - !ruby/object:Gem::Version
33
- version: 2.8.1
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '='
39
- - !ruby/object:Gem::Version
40
- version: 2.8.1
41
- - !ruby/object:Gem::Dependency
42
- name: eth
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: jimson
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: money-tree
29
+ name: rake
71
30
  requirement: !ruby/object:Gem::Requirement
72
31
  requirements:
73
32
  - - ">="
74
33
  - !ruby/object:Gem::Version
75
34
  version: '0'
76
- type: :runtime
35
+ type: :development
77
36
  prerelease: false
78
37
  version_requirements: !ruby/object:Gem::Requirement
79
38
  requirements:
@@ -81,13 +40,13 @@ dependencies:
81
40
  - !ruby/object:Gem::Version
82
41
  version: '0'
83
42
  - !ruby/object:Gem::Dependency
84
- name: securerandom
43
+ name: rspec
85
44
  requirement: !ruby/object:Gem::Requirement
86
45
  requirements:
87
46
  - - ">="
88
47
  - !ruby/object:Gem::Version
89
48
  version: '0'
90
- type: :runtime
49
+ type: :development
91
50
  prerelease: false
92
51
  version_requirements: !ruby/object:Gem::Requirement
93
52
  requirements:
@@ -95,7 +54,7 @@ dependencies:
95
54
  - !ruby/object:Gem::Version
96
55
  version: '0'
97
56
  - !ruby/object:Gem::Dependency
98
- name: pry
57
+ name: webmock
99
58
  requirement: !ruby/object:Gem::Requirement
100
59
  requirements:
101
60
  - - ">="
@@ -109,7 +68,7 @@ dependencies:
109
68
  - !ruby/object:Gem::Version
110
69
  version: '0'
111
70
  - !ruby/object:Gem::Dependency
112
- name: rake
71
+ name: timecop
113
72
  requirement: !ruby/object:Gem::Requirement
114
73
  requirements:
115
74
  - - ">="
@@ -123,7 +82,7 @@ dependencies:
123
82
  - !ruby/object:Gem::Version
124
83
  version: '0'
125
84
  - !ruby/object:Gem::Dependency
126
- name: rspec
85
+ name: pry
127
86
  requirement: !ruby/object:Gem::Requirement
128
87
  requirements:
129
88
  - - ">="
@@ -136,53 +95,57 @@ dependencies:
136
95
  - - ">="
137
96
  - !ruby/object:Gem::Version
138
97
  version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - '='
144
- - !ruby/object:Gem::Version
145
- version: 1.63.1
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - '='
151
- - !ruby/object:Gem::Version
152
- version: 1.63.1
153
- - !ruby/object:Gem::Dependency
154
- name: yard
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - '='
158
- - !ruby/object:Gem::Version
159
- version: 0.9.36
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - '='
165
- - !ruby/object:Gem::Version
166
- version: 0.9.36
167
- description: Coinbase Ruby SDK for accessing Coinbase Platform APIs
168
- email: yuga.cohler@coinbase.com
169
- executables: []
98
+ description: Client library for Coinbase Wallet API v2
99
+ email:
100
+ - jjd@coinbase.com
101
+ executables:
102
+ - console
103
+ - setup
170
104
  extensions: []
171
105
  extra_rdoc_files: []
172
106
  files:
173
- - lib/coinbase.rb
174
- - lib/coinbase/address.rb
175
- - lib/coinbase/asset.rb
176
- - lib/coinbase/balance_map.rb
177
- - lib/coinbase/constants.rb
178
- - lib/coinbase/network.rb
179
- - lib/coinbase/transfer.rb
107
+ - ".gitignore"
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - coinbase.gemspec
180
115
  - lib/coinbase/wallet.rb
181
- homepage: https://github.com/coinbase/coinbase-sdk-ruby
182
- licenses:
183
- - Apache-2.0
184
- metadata:
185
- rubygems_mfa_required: 'true'
116
+ - lib/coinbase/wallet/adapters/em_http.rb
117
+ - lib/coinbase/wallet/adapters/net_http.rb
118
+ - lib/coinbase/wallet/api_client.rb
119
+ - lib/coinbase/wallet/api_errors.rb
120
+ - lib/coinbase/wallet/api_response.rb
121
+ - lib/coinbase/wallet/ca-coinbase.crt
122
+ - lib/coinbase/wallet/client.rb
123
+ - lib/coinbase/wallet/models/account.rb
124
+ - lib/coinbase/wallet/models/address.rb
125
+ - lib/coinbase/wallet/models/api_object.rb
126
+ - lib/coinbase/wallet/models/checkout.rb
127
+ - lib/coinbase/wallet/models/order.rb
128
+ - lib/coinbase/wallet/models/transaction.rb
129
+ - lib/coinbase/wallet/models/transfer.rb
130
+ - lib/coinbase/wallet/models/user.rb
131
+ - lib/coinbase/wallet/version.rb
132
+ - spec/account_spec.rb
133
+ - spec/clients/client_spec.rb
134
+ - spec/clients/oauth_client_spec.rb
135
+ - spec/endpoints_spec.rb
136
+ - spec/error_spec.rb
137
+ - spec/models/address_spec.rb
138
+ - spec/models/api_object_spec.rb
139
+ - spec/models/checkout_spec.rb
140
+ - spec/models/current_user_spec.rb
141
+ - spec/models/order_spec.rb
142
+ - spec/models/request_spec.rb
143
+ - spec/models/transfer_spec.rb
144
+ - spec/models/user_spec.rb
145
+ - spec/spec_helper.rb
146
+ homepage: https://developers.coinbase.com/api/v2
147
+ licenses: []
148
+ metadata: {}
186
149
  post_install_message:
187
150
  rdoc_options: []
188
151
  require_paths:
@@ -191,15 +154,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
154
  requirements:
192
155
  - - ">="
193
156
  - !ruby/object:Gem::Version
194
- version: 2.7.0
157
+ version: '0'
195
158
  required_rubygems_version: !ruby/object:Gem::Requirement
196
159
  requirements:
197
160
  - - ">="
198
161
  - !ruby/object:Gem::Version
199
162
  version: '0'
200
163
  requirements: []
201
- rubygems_version: 3.1.6
164
+ rubyforge_project:
165
+ rubygems_version: 2.2.2
202
166
  signing_key:
203
167
  specification_version: 4
204
- summary: Coinbase Ruby SDK
168
+ summary: Client library for Coinbase Wallet API v2
205
169
  test_files: []
@@ -1,127 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'balance_map'
4
- require_relative 'constants'
5
- require 'bigdecimal'
6
- require 'eth'
7
- require 'jimson'
8
-
9
- module Coinbase
10
- # A representation of a blockchain Address, which is a user-controlled account on a Network. Addresses are used to
11
- # send and receive Assets, and should be created using {link:Wallet#create_address}. Addresses require a
12
- # {link:Eth::Key} to sign transaction data.
13
- class Address
14
- attr_reader :network_id, :address_id, :wallet_id
15
-
16
- # Returns a new Address object.
17
- # @param network_id [Symbol] The ID of the Network on which the Address exists
18
- # @param address_id [String] The ID of the Address. On EVM Networks, for example, this is a hash of the public key.
19
- # @param wallet_id [String] The ID of the Wallet to which the Address belongs
20
- # @param key [Eth::Key] The key backing the Address
21
- # @param client [Jimson::Client] (Optional) The JSON RPC client to use for interacting with the Network
22
- def initialize(network_id, address_id, wallet_id, key,
23
- client: Jimson::Client.new(ENV.fetch('BASE_SEPOLIA_RPC_URL', nil)))
24
- # TODO: Don't require key.
25
- @network_id = network_id
26
- @address_id = address_id
27
- @wallet_id = wallet_id
28
- @key = key
29
- @client = client
30
- end
31
-
32
- # Returns the balances of the Address. Currently only ETH balances are supported.
33
- # @return [BalanceMap] The balances of the Address, keyed by asset ID. Ether balances are denominated
34
- # in ETH.
35
- def list_balances
36
- # TODO: Handle multiple currencies.
37
- eth_balance_in_wei = BigDecimal(@client.eth_getBalance(@address_id, 'latest').to_i(16).to_s)
38
- eth_balance = BigDecimal(eth_balance_in_wei / BigDecimal(Coinbase::WEI_PER_ETHER.to_s))
39
-
40
- BalanceMap.new({ eth: eth_balance })
41
- end
42
-
43
- # Returns the balance of the provided Asset. Currently only ETH is supported.
44
- # @param asset_id [Symbol] The Asset to retrieve the balance for
45
- # @return [BigDecimal] The balance of the Asset
46
- def get_balance(asset_id)
47
- normalized_asset_id = if %i[wei gwei].include?(asset_id)
48
- :eth
49
- else
50
- asset_id
51
- end
52
-
53
- eth_balance = list_balances[normalized_asset_id] || BigDecimal(0)
54
-
55
- case asset_id
56
- when :eth
57
- eth_balance
58
- when :gwei
59
- eth_balance * Coinbase::GWEI_PER_ETHER
60
- when :wei
61
- eth_balance * Coinbase::WEI_PER_ETHER
62
- else
63
- BigDecimal(0)
64
- end
65
- end
66
-
67
- # Transfers the given amount of the given Asset to the given address. Only same-Network Transfers are supported.
68
- # @param amount [Integer, Float, BigDecimal] The amount of the Asset to send.
69
- # @param asset_id [Symbol] The ID of the Asset to send. For Ether, :eth, :gwei, and :wei are supported.
70
- # @param destination [Wallet | Address | String] The destination of the transfer. If a Wallet, sends to the Wallet's
71
- # default address. If a String, interprets it as the address ID.
72
- # @return [String] The hash of the Transfer transaction.
73
- def transfer(amount, asset_id, destination)
74
- # TODO: Handle multiple currencies.
75
- raise ArgumentError, "Unsupported asset: #{asset_id}" unless Coinbase::SUPPORTED_ASSET_IDS[asset_id]
76
-
77
- if destination.is_a?(Wallet)
78
- raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != @network_id
79
-
80
- destination = destination.default_address.address_id
81
- elsif destination.is_a?(Address)
82
- raise ArgumentError, 'Transfer must be on the same Network' if destination.network_id != @network_id
83
-
84
- destination = destination.address_id
85
- end
86
-
87
- current_balance = get_balance(asset_id)
88
- if current_balance < amount
89
- raise ArgumentError, "Insufficient funds: #{amount} requested, but only #{current_balance} available"
90
- end
91
-
92
- transfer = Coinbase::Transfer.new(@network_id, @wallet_id, @address_id, amount, asset_id, destination,
93
- client: @client)
94
-
95
- transaction = transfer.transaction
96
- transaction.sign(@key)
97
- @client.eth_sendRawTransaction("0x#{transaction.hex}")
98
-
99
- transfer
100
- end
101
-
102
- # Returns the address as a string.
103
- # @return [String] The address
104
- def to_s
105
- @address_id
106
- end
107
-
108
- private
109
-
110
- # Normalizes the amount of ETH to send based on the asset ID.
111
- # @param amount [Integer, Float, BigDecimal] The amount to normalize
112
- # @param asset_id [Symbol] The ID of the Asset being transferred
113
- # @return [BigDecimal] The normalized amount in units of ETH
114
- def normalize_eth_amount(amount, asset_id)
115
- case asset_id
116
- when :eth
117
- amount.is_a?(BigDecimal) ? amount : BigDecimal(amount.to_s)
118
- when :gwei
119
- BigDecimal(amount / Coinbase::GWEI_PER_ETHER)
120
- when :wei
121
- BigDecimal(amount / Coinbase::WEI_PER_ETHER)
122
- else
123
- raise ArgumentError, "Unsupported asset: #{asset_id}"
124
- end
125
- end
126
- end
127
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coinbase
4
- # A representation of an Asset.
5
- class Asset
6
- attr_reader :network_id, :asset_id, :display_name, :address_id
7
-
8
- # Returns a new Asset object.
9
- # @param network_id [Symbol] The ID of the Network to which the Asset belongs
10
- # @param asset_id [Symbol] The Asset ID
11
- # @param display_name [String] The Asset's display name
12
- # @param address_id [String] (Optional) The Asset's address ID, if one exists
13
- def initialize(network_id:, asset_id:, display_name:, address_id: nil)
14
- @network_id = network_id
15
- @asset_id = asset_id
16
- @display_name = display_name
17
- @address_id = address_id
18
- end
19
- end
20
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bigdecimal'
4
-
5
- module Coinbase
6
- # A convenience class for printing out crypto asset balances in a human-readable format.
7
- class BalanceMap < Hash
8
- # Returns a new BalanceMap object.
9
- # @param hash [Map<Symbol, BigDecimal>] The hash to initialize with
10
- def initialize(hash = {})
11
- super()
12
- hash.each do |key, value|
13
- self[key] = value
14
- end
15
- end
16
-
17
- # Returns a string representation of the balance map.
18
- # @return [String] The string representation of the balance
19
- def to_s
20
- to_string
21
- end
22
-
23
- # Returns a string representation of the balance map.
24
- # @return [String] The string representation of the balance
25
- def inspect
26
- to_string
27
- end
28
-
29
- private
30
-
31
- # Returns a string representation of the balance.
32
- # @return [String] The string representation of the balance
33
- def to_string
34
- result = {}
35
-
36
- each do |asset_id, balance|
37
- # Convert to floating-point number (not scientific notation)
38
- str = balance.to_s('F')
39
-
40
- str = balance.to_i.to_s if balance.frac.zero?
41
-
42
- result[asset_id] = str
43
- end
44
-
45
- result
46
- end
47
- end
48
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'asset'
4
- require_relative 'network'
5
-
6
- module Coinbase
7
- # The Assets supported on Base Sepolia by the Coinbase SDK.
8
- ETH = Asset.new(network_id: :base_sepolia, asset_id: :eth, display_name: 'Ether')
9
- USDC = Asset.new(network_id: :base_sepolia, asset_id: :usdc, display_name: 'USD Coin',
10
- address_id: '0x036CbD53842c5426634e7929541eC2318f3dCF7e')
11
-
12
- # The Base Sepolia Network.
13
- BASE_SEPOLIA = Network.new(
14
- network_id: :base_sepolia,
15
- display_name: 'Base Sepolia',
16
- protocol_family: :evm,
17
- is_testnet: true,
18
- assets: [ETH, USDC],
19
- native_asset_id: :eth,
20
- chain_id: 84_532
21
- )
22
-
23
- # The amount of Wei per Ether.
24
- WEI_PER_ETHER = 1_000_000_000_000_000_000
25
-
26
- # The amount of Wei per Gwei.
27
- WEI_PER_GWEI = 1_000_000_000
28
-
29
- # The amount of Gwei per Ether.
30
- GWEI_PER_ETHER = 1_000_000_000
31
-
32
- # A map of supported Asset IDs.
33
- SUPPORTED_ASSET_IDS = {
34
- eth: true, # Ether, the native asset of most EVM networks.
35
- gwei: true, # A medium denomination of Ether, typically used in gas prices.
36
- wei: true # The smallest denomination of Ether.
37
- }.freeze
38
- end
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coinbase
4
- # A blockchain network.
5
- class Network
6
- attr_reader :chain_id
7
-
8
- # Returns a new Network object.
9
- #
10
- # @param network_id [Symbol] The Network ID
11
- # @param display_name [String] The Network's display name
12
- # @param protocol_family [String] The protocol family to which the Network belongs
13
- # (e.g., "evm")
14
- # @param is_testnet [Boolean] Whether the Network is a testnet
15
- # @param assets [Array<Asset>] The Assets supported by the Network
16
- # @param native_asset_id [String] The ID of the Network's native Asset
17
- # @param chain_id [Integer] The Chain ID of the Network
18
- def initialize(network_id:, display_name:, protocol_family:, is_testnet:, assets:, native_asset_id:, chain_id:)
19
- @network_id = network_id
20
- @display_name = display_name
21
- @protocol_family = protocol_family
22
- @is_testnet = is_testnet
23
- @chain_id = chain_id
24
-
25
- @asset_map = {}
26
- assets.each do |asset|
27
- @asset_map[asset.asset_id] = asset
28
- end
29
-
30
- raise ArgumentError, 'Native Asset not found' unless @asset_map.key?(native_asset_id)
31
-
32
- @native_asset = @asset_map[native_asset_id]
33
- end
34
-
35
- # Lists the Assets supported by the Network.
36
- #
37
- # @return [Array<Asset>] The Assets supported by the Network
38
- def list_assets
39
- @asset_map.values
40
- end
41
-
42
- # Gets the Asset with the given ID.
43
- #
44
- # @param asset_id [Symbol] The ID of the Asset
45
- # @return [Asset] The Asset with the given ID
46
- def get_asset(asset_id)
47
- @asset_map[asset_id]
48
- end
49
-
50
- # Gets the native Asset of the Network.
51
- #
52
- # @return [Asset] The native Asset of the Network
53
- attr_reader :native_asset
54
- end
55
- end
@@ -1,153 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'constants'
4
- require 'bigdecimal'
5
- require 'eth'
6
-
7
- module Coinbase
8
- # A representation of a Transfer, which moves an amount of an Asset from
9
- # a user-controlled Wallet to another address. The fee is assumed to be paid
10
- # in the native Asset of the Network. Currently only ETH transfers are supported. Transfers
11
- # should be created through {link:Wallet#transfer} or {link:Address#transfer}.
12
- class Transfer
13
- attr_reader :network_id, :wallet_id, :from_address_id, :amount, :asset_id, :to_address_id
14
-
15
- # A representation of a Transfer status.
16
- module Status
17
- # The Transfer is awaiting being broadcast to the Network. At this point, transaction
18
- # hashes may not yet be assigned.
19
- PENDING = :pending
20
-
21
- # The Transfer has been broadcast to the Network. At this point, at least the transaction hash
22
- # should be assigned.
23
- BROADCAST = :broadcast
24
-
25
- # The Transfer is complete, and has confirmed on the Network.
26
- COMPLETE = :complete
27
-
28
- # The Transfer has failed for some reason.
29
- FAILED = :failed
30
- end
31
-
32
- # Returns a new Transfer object.
33
- # @param network_id [Symbol] The ID of the Network on which the Transfer originated
34
- # @param wallet_id [String] The ID of the Wallet from which the Transfer originated
35
- # @param from_address_id [String] The ID of the address from which the Transfer originated
36
- # @param amount [Integer, Float, BigDecimal] The amount of the Asset to send. Integers are interpreted as
37
- # the smallest denomination of the Asset (e.g. Wei for Ether). Floats and BigDecimals are interpreted as the Asset
38
- # itself (e.g. Ether).
39
- # @param asset_id [Symbol] The ID of the Asset being transferred. Currently only ETH is supported.
40
- # @param to_address_id [String] The address to which the Transfer is being sent
41
- # @param client [Jimson::Client] (Optional) The JSON RPC client to use for interacting with the Network
42
- def initialize(network_id, wallet_id, from_address_id, amount, asset_id, to_address_id,
43
- client: Jimson::Client.new(ENV.fetch('BASE_SEPOLIA_RPC_URL', nil)))
44
-
45
- raise ArgumentError, "Unsupported asset: #{asset_id}" if asset_id != :eth
46
-
47
- @network_id = network_id
48
- @wallet_id = wallet_id
49
- @from_address_id = from_address_id
50
- @amount = normalize_eth_amount(amount)
51
- @asset_id = asset_id
52
- @to_address_id = to_address_id
53
- @client = client
54
- end
55
-
56
- # Returns the underlying Transfer transaction, creating it if it has not been yet.
57
- # @return [Eth::Tx::Eip1559] The Transfer transaction
58
- def transaction
59
- return @transaction unless @transaction.nil?
60
-
61
- nonce = @client.eth_getTransactionCount(@from_address_id.to_s, 'latest').to_i(16)
62
- gas_price = @client.eth_gasPrice.to_i(16)
63
-
64
- params = {
65
- chain_id: BASE_SEPOLIA.chain_id, # TODO: Don't hardcode Base Sepolia.
66
- nonce: nonce,
67
- priority_fee: gas_price, # TODO: Optimize this.
68
- max_gas_fee: gas_price,
69
- gas_limit: 21_000, # TODO: Handle multiple currencies.
70
- from: Eth::Address.new(@from_address_id),
71
- to: Eth::Address.new(@to_address_id),
72
- value: (@amount * Coinbase::WEI_PER_ETHER).to_i
73
- }
74
-
75
- @transaction = Eth::Tx::Eip1559.new(Eth::Tx.validate_eip1559_params(params))
76
- @transaction
77
- end
78
-
79
- # Returns the status of the Transfer.
80
- # @return [Symbol] The status
81
- def status
82
- begin
83
- # Create the transaction, and attempt to get the hash to see if it has been signed.
84
- transaction.hash
85
- rescue Eth::Signature::SignatureError
86
- # If the transaction has not been signed, it is still pending.
87
- return Status::PENDING
88
- end
89
-
90
- onchain_transaction = @client.eth_getTransactionByHash(transaction_hash)
91
-
92
- if onchain_transaction.nil?
93
- # If the transaction has not been broadcast, it is still pending.
94
- Status::PENDING
95
- elsif onchain_transaction['blockHash'].nil?
96
- # If the transaction has been broadcast but hasn't been included in a block, it is
97
- # broadcast.
98
- Status::BROADCAST
99
- else
100
- transaction_receipt = @client.eth_getTransactionReceipt(transaction_hash)
101
-
102
- if transaction_receipt['status'].to_i(16) == 1
103
- Status::COMPLETE
104
- else
105
- Status::FAILED
106
- end
107
- end
108
- end
109
-
110
- # Waits until the Transfer is completed or failed by polling the Network at the given interval. Raises a
111
- # Timeout::Error if the Transfer takes longer than the given timeout.
112
- # @param interval_seconds [Integer] The interval at which to poll the Network, in seconds
113
- # @param timeout_seconds [Integer] The maximum amount of time to wait for the Transfer to complete, in seconds
114
- # @return [Transfer] The completed Transfer object
115
- def wait!(interval_seconds = 0.2, timeout_seconds = 10)
116
- start_time = Time.now
117
-
118
- loop do
119
- return self if status == Status::COMPLETE || status == Status::FAILED
120
-
121
- raise Timeout::Error, 'Transfer timed out' if Time.now - start_time > timeout_seconds
122
-
123
- self.sleep interval_seconds
124
- end
125
-
126
- self
127
- end
128
-
129
- # Returns the transaction hash of the Transfer, or nil if not yet available.
130
- # @return [String] The transaction hash
131
- def transaction_hash
132
- "0x#{transaction.hash}"
133
- rescue Eth::Signature::SignatureError
134
- nil
135
- end
136
-
137
- private
138
-
139
- # Normalizes the given Ether amount into a BigDecimal.
140
- # @param amount [Integer, Float, BigDecimal] The amount to normalize
141
- # @return [BigDecimal] The normalized amount
142
- def normalize_eth_amount(amount)
143
- case amount
144
- when BigDecimal
145
- amount
146
- when Integer, Float
147
- BigDecimal(amount.to_s)
148
- else
149
- raise ArgumentError, "Invalid amount: #{amount}"
150
- end
151
- end
152
- end
153
- end