Class: Stellar::TransactionBuilder

Inherits:
Object
  • Object
show all
Includes:
DSL
Defined in:
lib/stellar/transaction_builder.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DSL

Account, Asset, ClaimPredicate, Claimant, KeyPair, SignerKey

Constructor Details

#initialize(source_account:, sequence_number:, base_fee: 100, time_bounds: nil, ledger_bounds: nil, memo: nil, min_account_sequence: nil, min_account_sequence_age: nil, min_account_sequence_ledger_gap: nil, extra_signers: [], **_) ⇒ TransactionBuilder

Returns a new instance of TransactionBuilder.

Raises:

  • (ArgumentError)


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/stellar/transaction_builder.rb', line 42

def initialize(
  source_account:,
  sequence_number:,
  base_fee: 100,
  time_bounds: nil,
  ledger_bounds: nil,
  memo: nil,
  min_account_sequence: nil,
  min_account_sequence_age: nil,
  min_account_sequence_ledger_gap: nil,
  extra_signers: [],
  **_ # ignore any additional parameters without errors
)
  raise ArgumentError, "Bad :sequence_number" unless sequence_number.is_a?(Integer) && sequence_number >= 0
  raise ArgumentError, "Bad :time_bounds" unless time_bounds.is_a?(Stellar::TimeBounds) || time_bounds.nil?
  raise ArgumentError, "Bad :base_fee" unless base_fee.is_a?(Integer) && base_fee >= 100

  @source_account = Account()
  @sequence_number = sequence_number
  @base_fee = base_fee
  @time_bounds = time_bounds
  @ledger_bounds = ledger_bounds
  @min_account_sequence = 
  @min_account_sequence_age = 
  @min_account_sequence_ledger_gap = 
  @extra_signers = extra_signers.clone

  set_timeout(0) if time_bounds.nil?

  @memo = make_memo(memo)
  @operations = []
end

Instance Attribute Details

#base_feeObject (readonly)

Returns the value of attribute base_fee.



5
6
7
# File 'lib/stellar/transaction_builder.rb', line 5

def base_fee
  @base_fee
end

#ledger_boundsObject (readonly)

Returns the value of attribute ledger_bounds.



5
6
7
# File 'lib/stellar/transaction_builder.rb', line 5

def ledger_bounds
  @ledger_bounds
end

#memoObject (readonly)

Returns the value of attribute memo.



5
6
7
# File 'lib/stellar/transaction_builder.rb', line 5

def memo
  @memo
end

#min_account_sequenceObject

If you want to prepare a transaction which will be valid only while the account sequence number is

 <=  < tx.seq_num

you can set min_account_sequence attribute

Note that after execution the account’s sequence number is always raised to ‘tx.seq_num`



16
17
18
# File 'lib/stellar/transaction_builder.rb', line 16

def 
  @min_account_sequence
end

#operationsObject (readonly)

Returns the value of attribute operations.



5
6
7
# File 'lib/stellar/transaction_builder.rb', line 5

def operations
  @operations
end

#sequence_numberObject (readonly)

Returns the value of attribute sequence_number.



5
6
7
# File 'lib/stellar/transaction_builder.rb', line 5

def sequence_number
  @sequence_number
end

#source_accountObject (readonly)

Returns the value of attribute source_account.



5
6
7
# File 'lib/stellar/transaction_builder.rb', line 5

def 
  @source_account
end

#time_boundsObject (readonly)

Returns the value of attribute time_bounds.



5
6
7
# File 'lib/stellar/transaction_builder.rb', line 5

def time_bounds
  @time_bounds
end

Class Method Details

.method_missing(method_name, *args, **kwargs) ⇒ Object

This enable user to call shortcut methods, like TransactionBuilder.payment(…), TransactionBuilder.manage_data(…) and etc. It reduces the boilerplate, when you just need to shoot a single operation in transaction



24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/stellar/transaction_builder.rb', line 24

def method_missing(method_name, *args, **kwargs)
  return super unless Operation.respond_to?(method_name)

  op = Operation.send(
    method_name,
    **kwargs.except(
      :source_account, :sequence_number, :base_fee, :time_bounds, :memo
    )
  )

  new(**kwargs).add_operation(op).build
end

.respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/stellar/transaction_builder.rb', line 37

def respond_to_missing?(method_name, include_private = false)
  Stellar::Operation.respond_to?(method_name) || super
end

Instance Method Details

#add_operation(operation) ⇒ Object

Raises:

  • (ArgumentError)


123
124
125
126
127
# File 'lib/stellar/transaction_builder.rb', line 123

def add_operation(operation)
  raise ArgumentError, "Bad operation" unless operation.is_a? Stellar::Operation
  @operations.push(operation)
  self
end

#buildObject



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/stellar/transaction_builder.rb', line 75

def build
  if @time_bounds.nil?
    raise "TransactionBuilder.time_bounds must be set during initialization or by calling set_timeout"
  elsif !@time_bounds.min_time.is_a?(Integer) || !@time_bounds.max_time.is_a?(Integer)
    raise "TimeBounds.min_time and max_time must be Integers"
  elsif @time_bounds.max_time != 0 && @time_bounds.min_time > @time_bounds.max_time
    raise "Timebounds.max_time must be greater than min_time"
  end

  attrs = {
    source_account: @source_account.,
    fee: @base_fee * @operations.length,
    seq_num: @sequence_number,
    memo: @memo,
    operations: @operations,
    cond: build_preconditions,
    ext: Stellar::Transaction::Ext.new(0)
  }

  @sequence_number += 1

  Stellar::Transaction.new(attrs)
end

#build_fee_bump(inner_txe:) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/stellar/transaction_builder.rb', line 99

def build_fee_bump(inner_txe:)
  if inner_txe.switch == Stellar::EnvelopeType.envelope_type_tx_v0
    inner_txe = Stellar::TransactionEnvelope.v1(tx: inner_txe.tx.to_v1, signatures: inner_txe.signatures)
  elsif inner_txe.switch != Stellar::EnvelopeType.envelope_type_tx
    raise ArgumentError, "Invalid inner transaction type #{inner_txe.switch}"
  end

  inner_tx = inner_txe.tx
  inner_ops = inner_tx.operations
  inner_base_fee_rate = inner_tx.fee.fdiv(inner_ops.length)

  # The fee rate for fee bump is at least the fee rate of the inner transaction
  if @base_fee < inner_base_fee_rate
    raise "Insufficient base_fee, it should be at least #{inner_base_fee_rate} stroops."
  end

  Stellar::FeeBumpTransaction.new(
    fee_source: @source_account.,
    fee: @base_fee * (inner_ops.length + 1),
    inner_tx: Stellar::FeeBumpTransaction::InnerTx.new(:envelope_type_tx, inner_txe.v1!),
    ext: Stellar::FeeBumpTransaction::Ext.new(0)
  )
end

#clear_operationsObject



129
130
131
132
# File 'lib/stellar/transaction_builder.rb', line 129

def clear_operations
  @operations.clear
  self
end

#make_memo(memo) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/stellar/transaction_builder.rb', line 235

def make_memo(memo)
  case memo
  when Stellar::Memo
    memo
  when nil
    Memo.new(:memo_none)
  when Integer
    Memo.new(:memo_id, memo)
  when String
    Memo.new(:memo_text, memo)
  when Array
    t, val = *memo
    Memo.new(:"memo_#{t}", val)
  else
    raise ArgumentError, "Bad :memo"
  end
end

#min_account_sequence_age=(duration_in_seconds) ⇒ Object

For the transaction to be valid, the current ledger time must be at least ‘min_account_sequence_age` greater than source account’s ‘sequence_time`



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/stellar/transaction_builder.rb', line 185

def (duration_in_seconds)
  unless duration_in_seconds.is_a?(Integer)
    raise ArgumentError, "min_account_sequence_age must be a number"
  end

  if duration_in_seconds < 0
    raise ArgumentError, "min_account_sequence_age cannot be negative"
  end

  @min_account_sequence_age = duration_in_seconds
end

#min_account_sequence_ledger_gap=(gap) ⇒ Object

For the transaction to be valid, the current ledger number must be at least ‘minAccountSequenceLedgerGap` greater than sourceAccount’s ledger sequence.



199
200
201
202
203
204
205
# File 'lib/stellar/transaction_builder.rb', line 199

def (gap)
  if gap < 0
    raise ArgumentError, "min_account_sequence_ledger_gap cannot be negative"
  end

  @min_account_sequence_ledger_gap = gap
end

#set_base_fee(base_fee) ⇒ Object

Raises:

  • (ArgumentError)


229
230
231
232
233
# File 'lib/stellar/transaction_builder.rb', line 229

def set_base_fee(base_fee)
  raise ArgumentError, "Bad base fee" unless base_fee.is_a?(Integer) && base_fee >= 100
  @base_fee = base_fee
  self
end

#set_extra_signers(extra_signers) ⇒ Object

For the transaction to be valid, there must be a signature corresponding to every Signer in this array, even if the signature is not otherwise required by the sourceAccount or operations



210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/stellar/transaction_builder.rb', line 210

def set_extra_signers(extra_signers)
  unless extra_signers.is_a?(Array)
    raise ArgumentError, "extra_signers must be an array of strings"
  end

  if extra_signers.size > 2
    raise ArgumentError, "extra_signers cannot be longer than 2 elements"
  end

  @extra_signers = extra_signers.clone

  self
end

#set_ledger_bounds(min_ledger, max_ledger) ⇒ Object

If you want to prepare a transaction which will only be valid within some range of ledgers, you can set a ‘ledger_bounds` precondition.



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/stellar/transaction_builder.rb', line 162

def set_ledger_bounds(min_ledger, max_ledger)
  if min_ledger < 0
    raise ArgumentError, "min_ledger cannot be negative"
  end

  if max_ledger < 0
    raise ArgumentError, "max_ledger cannot be negative"
  end

  if max_ledger > 0 && min_ledger > max_ledger
    raise ArgumentError, "min_ledger cannot be greater than max_ledger"
  end

  @ledger_bounds = Stellar::LedgerBounds.new(
    min_ledger: min_ledger,
    max_ledger: max_ledger
  )

  self
end

#set_memo(memo) ⇒ Object



224
225
226
227
# File 'lib/stellar/transaction_builder.rb', line 224

def set_memo(memo)
  @memo = make_memo(memo)
  self
end

#set_sequence_number(seq_num) ⇒ Object

Raises:

  • (ArgumentError)


140
141
142
143
144
# File 'lib/stellar/transaction_builder.rb', line 140

def set_sequence_number(seq_num)
  raise ArgumentError, "Bad sequence number" unless seq_num.is_a?(Integer) && seq_num >= 0
  @sequence_number = seq_num
  self
end

#set_source_account(account_kp) ⇒ Object

Raises:

  • (ArgumentError)


134
135
136
137
138
# File 'lib/stellar/transaction_builder.rb', line 134

def ()
  raise ArgumentError, "Bad source account" unless .is_a?(Stellar::KeyPair)
  @source_account = 
  self
end

#set_timeout(timeout) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/stellar/transaction_builder.rb', line 146

def set_timeout(timeout)
  if !timeout.is_a?(Integer) || timeout < 0
    raise ArgumentError, "Timeout must be a non-negative integer"
  end

  if @time_bounds.nil?
    @time_bounds = Stellar::TimeBounds.new(min_time: 0, max_time: nil)
  end

  @time_bounds.max_time = timeout == 0 ? timeout : Time.now.to_i + timeout

  self
end