Class: Coinbase::StakingOperation

Inherits:
Object
  • Object
show all
Defined in:
lib/coinbase/staking_operation.rb

Overview

A representation of a staking operation (stake, unstake, claim rewards, etc). It may have multiple steps with some being transactions to sign, and others to wait.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model) ⇒ StakingOperation

Returns a new StakingOperation object.

Parameters:



117
118
119
120
121
# File 'lib/coinbase/staking_operation.rb', line 117

def initialize(model)
  @model = model
  @transactions ||= []
  update_transactions(model.transactions)
end

Instance Attribute Details

#statusSymbol (readonly)

Returns the status of the Staking Operation.

Returns:

  • (Symbol)

    The status



9
10
11
# File 'lib/coinbase/staking_operation.rb', line 9

def status
  @status
end

#transactionsArray<Coinbase::Transaction> (readonly)

The list of current transactions associated with the operation.

Returns:



9
10
11
# File 'lib/coinbase/staking_operation.rb', line 9

def transactions
  @transactions
end

Class Method Details

.build(amount, network, asset_id, address_id, action, mode, options) ⇒ Coinbase::StakingOperation

Builds an ephemeral staking operation this is intended to be called via an Address or Wallet.

Parameters:

  • amount (BigDecimal)

    The amount to stake, in the primary denomination of the asset

  • network (Coinbase::Network, Symbol)

    The Network or Network ID

  • asset_id (Symbol)

    The Asset ID

  • address_id (String)

    The Address ID

  • action (Symbol)

    The action to perform

  • mode (Symbol)

    The staking mode

  • options (Hash)

    Additional options

Options Hash (options):

  • :integrator_contract_address (String)

    The integrator contract address. [asset_id: :eth, mode: :partial, action: all]

  • :funding_address (String)

    The address funding the 32 ETH (default: :address_id) [asset_id: :eth, mode: :native, action: :stake]

  • :withdrawal_address (String)

    The address receiving rewards and withdrawal funds. (default: :address_id) [asset_id: :eth, mode: :native, action: :stake]

  • :fee_recipient_address (String)

    The address receiving transaction fees. (default: :address_id) [asset_id: :eth, mode: :native, action: :stake]

  • :immediate (Boolean)

    To leverage “Coinbase Managed Unstake”. (default: false i.e. User Managed Unstake) [asset_id: :eth, mode: :native, action: :unstake]

  • :validator_pub_keys (String)

    List of comma separated validator public keys to unstake. (default: validators picked up on your behalf corresponding to the unstake amount.) [asset_id: :eth, mode: :native, action: :unstake]

Returns:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/coinbase/staking_operation.rb', line 34

def self.build(amount, network, asset_id, address_id, action, mode, options)
  network = Coinbase::Network.from_id(network)
  asset = network.get_asset(asset_id)

  model = Coinbase.call_api do
    stake_api.build_staking_operation(
      {
        asset_id: asset.primary_denomination.to_s,
        address_id: address_id,
        action: action,
        network_id: Coinbase.normalize_network(network),
        options: {
          amount: asset.to_atomic_amount(amount).to_i.to_s,
          mode: mode
        }.merge(options)
      }
    )
  end

  new(model)
end

.create(amount, network, asset_id, address_id, wallet_id, action, mode, options) ⇒ Coinbase::StakingOperation

Creates a persisted staking operation this is intended to be called via an Address or Wallet.

Parameters:

  • amount (BigDecimal)

    The amount to stake, in the primary denomination of the asset

  • network (Coinbase::Network, Symbol)

    The Network or Network ID

  • asset_id (Symbol)

    The Asset ID

  • address_id (String)

    The Address ID

  • wallet_id (String)

    The Wallet ID

  • action (Symbol)

    The action to perform

  • mode (Symbol)

    The staking mode

  • options (Hash)

    Additional options

Options Hash (options):

  • :integrator_contract_address (String)

    The integrator contract address. [asset_id: :eth, mode: :partial, action: all]

  • :funding_address (String)

    The address funding the 32 ETH (default: :address_id) [asset_id: :eth, mode: :native, action: :stake]

  • :withdrawal_address (String)

    The address receiving rewards and withdrawal funds. (default: :address_id) [asset_id: :eth, mode: :native, action: :stake]

  • :fee_recipient_address (String)

    The address receiving transaction fees. (default: :address_id) [asset_id: :eth, mode: :native, action: :stake]

  • :immediate (Boolean)

    To leverage “Coinbase Managed Unstake”. (default: false i.e. User Managed Unstake) [asset_id: :eth, mode: :native, action: :unstake]

  • :validator_pub_keys (String)

    List of comma separated validator public keys to unstake. (default: validators picked up on your behalf corresponding to the unstake amount.) [asset_id: :eth, mode: :native, action: :unstake]

Returns:



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/coinbase/staking_operation.rb', line 79

def self.create(amount, network, asset_id, address_id, wallet_id, action, mode, options)
  network = Coinbase::Network.from_id(network)
  asset = network.get_asset(asset_id)

  model = Coinbase.call_api do
    wallet_stake_api.create_staking_operation(
      wallet_id,
      address_id,
      {
        asset_id: asset.primary_denomination.to_s,
        address_id: address_id,
        action: action,
        network_id: Coinbase.normalize_network(network),
        options: {
          amount: asset.to_atomic_amount(amount).to_i.to_s,
          mode: mode
        }.merge(options)
      }
    )
  end

  new(model)
end

.fetch(network, address_id, id, wallet_id: nil) ⇒ Coinbase::StakingOperation

Fetch the StakingOperation with the provided network, address and staking operation ID.

Parameters:

  • network (Coinbase::Network, Symbol)

    The Network or Network ID

  • address_id (Symbol)

    The Address ID

  • id (String)

    The ID of the StakingOperation

  • wallet_id (String) (defaults to: nil)

    The optional Wallet ID

Returns:



248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/coinbase/staking_operation.rb', line 248

def self.fetch(network, address_id, id, wallet_id: nil)
  network = Coinbase::Network.from_id(network)

  staking_operation_model = Coinbase.call_api do
    if wallet_id.nil?
      stake_api.get_external_staking_operation(network.id, address_id, id)
    else
      wallet_stake_api.get_staking_operation(wallet_id, address_id, id)
    end
  end

  new(staking_operation_model)
end

Instance Method Details

#address_idString

Returns the Address ID of the Staking Operation.

Returns:

  • (String)

    The Address ID



137
138
139
# File 'lib/coinbase/staking_operation.rb', line 137

def address_id
  @model.address_id
end

#broadcast!Coinbase::StakingOperation

Broadcasts the Staking Operation transactions to the network



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/coinbase/staking_operation.rb', line 303

def broadcast!
  transactions.each_with_index do |transaction, i|
    raise TransactionNotSignedError unless transaction.signed?

    Coinbase.call_api do
      wallet_stake_api.broadcast_staking_operation(
        wallet_id,
        address_id,
        id,
        { signed_payload: transaction.raw.hex, transaction_index: i }
      )
    end
  end

  self
end

#complete(key, interval_seconds: 5, timeout_seconds: 600) ⇒ StakingOperation

Complete helps the Staking Operation reach complete state, by polling its status at the given interval, signing and broadcasting any available transaction.

Parameters:

  • key (Eth::Key)

    The key to sign the Staking Operation transactions with

  • interval_seconds (Integer) (defaults to: 5)

    The interval at which to poll, in seconds

  • timeout_seconds (Integer) (defaults to: 600)

    The maximum amount of time to wait for the StakingOperation to complete, in seconds

Returns:

Raises:

  • (Timeout::Error)

    if the Staking Operation takes longer than the given timeout.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/coinbase/staking_operation.rb', line 214

def complete(key, interval_seconds: 5, timeout_seconds: 600)
  start_time = Time.now

  loop do
    @transactions.each_with_index do |transaction, i|
      next if transaction.signed?

      transaction.sign(key)
      @model = Coinbase.call_api do
        wallet_stake_api.broadcast_staking_operation(
          wallet_id,
          address_id,
          id,
          { signed_payload: transaction.raw.hex, transaction_index: i }
        )
      end
    end

    return self if terminal_state?

    reload

    raise Timeout::Error, 'Staking Operation timed out' if Time.now - start_time > timeout_seconds

    sleep interval_seconds
  end
end

#completed?Boolean

Returns whether the Staking Operation is in a complete state.

Returns:

  • (Boolean)

    Whether the Staking Operation is in a complete state



161
162
163
# File 'lib/coinbase/staking_operation.rb', line 161

def completed?
  status == 'complete'
end

#failed?Boolean

Returns whether the Staking Operation is in a failed state.

Returns:

  • (Boolean)

    Whether the Staking Operation is in a failed state



155
156
157
# File 'lib/coinbase/staking_operation.rb', line 155

def failed?
  status == 'failed'
end

#idString

Returns the Staking Operation ID.

Returns:

  • (String)

    The Staking Operation ID



125
126
127
# File 'lib/coinbase/staking_operation.rb', line 125

def id
  @model.id
end

#networkCoinbase::Network

Returns the Network of the Staking Operation.

Returns:



131
132
133
# File 'lib/coinbase/staking_operation.rb', line 131

def network
  @network ||= Coinbase::Network.from_id(@model.network_id)
end

#reloadCoinbase::StakingOperation

Reloads the staking_operation from the service

Returns:



272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/coinbase/staking_operation.rb', line 272

def reload
  @model = Coinbase.call_api do
    if wallet_id.nil?
      stake_api.get_external_staking_operation(network.id, address_id, id)
    else
      wallet_stake_api.get_staking_operation(wallet_id, address_id, id)
    end
  end

  update_transactions(@model.transactions)

  self
end

#sign(key) ⇒ Object

Signs the Open Transactions with the provided key

Parameters:

  • key (Eth::Key)

    The key to sign the transactions with



264
265
266
267
268
# File 'lib/coinbase/staking_operation.rb', line 264

def sign(key)
  transactions.each do |transaction|
    transaction.sign(key) unless transaction.signed?
  end
end

#signed_voluntary_exit_messagesArray<string>

Fetches the presigned_voluntary exit messages for the staking operation

Returns:

  • (Array<string>)

    The list of presigned exit transaction messages



288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/coinbase/staking_operation.rb', line 288

def signed_voluntary_exit_messages
  return [] unless @model.

  signed_voluntary_exit_messages = []

  @model..each do ||
    decoded_string = Base64.decode64(.signed_voluntary_exit)
    signed_voluntary_exit_messages.push(decoded_string)
  end

  signed_voluntary_exit_messages
end

#terminal_state?Boolean

Returns whether the Staking Operation is in a terminal state.

Returns:

  • (Boolean)

    Whether the Staking Operation is in a terminal state



149
150
151
# File 'lib/coinbase/staking_operation.rb', line 149

def terminal_state?
  failed? || completed?
end

#to_sString

Returns a String representation of the Staking Operation.

Returns:

  • (String)

    a String representation of the Staking Operation



167
168
169
170
171
172
173
174
175
# File 'lib/coinbase/staking_operation.rb', line 167

def to_s
  Coinbase.pretty_print_object(
    self.class,
    id: id,
    status: status,
    network_id: network.id,
    address_id: address_id
  )
end

#wait!(interval_seconds = 5, timeout_seconds = 3600) ⇒ StakingOperation

Waits until the Staking Operation is completed or failed by polling its status at the given interval.

Parameters:

  • interval_seconds (Integer) (defaults to: 5)

    The interval at which to poll, in seconds

  • timeout_seconds (Integer) (defaults to: 3600)

    The maximum amount of time to wait for the StakingOperation to complete, in seconds

Returns:

Raises:

  • (Timeout::Error)

    if the Staking Operation takes longer than the given timeout.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/coinbase/staking_operation.rb', line 189

def wait!(interval_seconds = 5, timeout_seconds = 3600)
  start_time = Time.now

  loop do
    reload

    # Wait for the Staking Operation to be in a terminal state.
    break if terminal_state?

    raise Timeout::Error, 'Staking Operation timed out' if Time.now - start_time > timeout_seconds

    self.sleep interval_seconds
  end

  self
end

#wallet_idString

Returns the Wallet ID of the Staking Operation.

Returns:

  • (String)

    The Wallet ID



179
180
181
# File 'lib/coinbase/staking_operation.rb', line 179

def wallet_id
  @model.wallet_id
end