class Digitalbits::Operation
Constants
- MAX_INT64
- TRUST_LINE_FLAGS_MAPPING
Public Class Methods
Helper method to create an account merge operation
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :destination
@return [Digitalbits::Operation] the built operation
# File lib/digitalbits/operation.rb, line 450 def account_merge(attributes = {}) destination = attributes[:destination] raise ArgumentError, "Bad :destination" unless destination.is_a?(KeyPair) # TODO: add source_account support make(attributes.merge({ body: [:account_merge, destination.muxed_account] })) end
DEPRECATED in favor of `set_trustline_flags`
Helper method to create a valid AllowTrustOp
, wrapped in the necessary XDR structs to be included within a transactions `operations` array.
@deprecated Use `set_trustline_flags` operation
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :trustor @option attributes [Digitalbits::Asset] :asset @option attributes [Symbol, Boolean] :authorize :full, maintain_liabilities or :none
@return [Digitalbits::Operation] the built operation, containing a
Digitalbits::AllowTrustOp body
# File lib/digitalbits/operation.rb, line 409 def allow_trust(attributes = {}) op = AllowTrustOp.new trustor = attributes[:trustor] # we handle booleans here for the backward compatibility authorize = attributes[:authorize].yield_self { |value| value == true ? :full : value } asset = attributes[:asset] if asset.is_a?(Array) asset = Asset.send(*asset) end raise ArgumentError, "Bad :trustor" unless trustor.is_a?(Digitalbits::KeyPair) allowed_flags = TRUST_LINE_FLAGS_MAPPING.slice(:full, :maintain_liabilities) # we handle booleans here for the backward compatibility op.authorize = if allowed_flags.key?(authorize) allowed_flags[authorize].value elsif [:none, false].include?(authorize) 0 else raise ArgumentError, "Bad :authorize, supported values: :full, :maintain_liabilities, :none" end raise ArgumentError, "Bad :asset" unless asset.type == Digitalbits::AssetType.asset_type_credit_alphanum4 op.trustor = trustor.account_id op.asset = AssetCode.new(:asset_type_credit_alphanum4, asset.code) make(attributes.merge({ body: [:allow_trust, op] })) end
# File lib/digitalbits/operation.rb, line 239 def begin_sponsoring_future_reserves(sponsored:, **attributes) op = BeginSponsoringFutureReservesOp.new( sponsored_id: KeyPair(sponsored).account_id ) make(attributes.merge(body: [:begin_sponsoring_future_reserves, op])) end
# File lib/digitalbits/operation.rb, line 507 def bump_sequence(attributes = {}) op = BumpSequenceOp.new bump_to = attributes[:bump_to] raise ArgumentError, ":bump_to too big" unless bump_to <= MAX_INT64 op.bump_to = bump_to make(attributes.merge({ body: [:bump_sequence, op] })) end
Helper method to create a valid ChangeTrustOp
, wrapped in the necessary XDR structs to be included within a transactions `operations` array.
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::Asset] :line the asset to trust @option attributes [Fixnum] :limit the maximum amount to trust, defaults to max int64,
if the limit is set to 0 it deletes the trustline.
@return [Digitalbits::Operation] the built operation, containing a
Digitalbits::ChangeTrustOp body
# File lib/digitalbits/operation.rb, line 189 def change_trust(attributes = {}) line = attributes[:line] unless line.is_a?(Asset) unless Asset::TYPES.include?(line[0]) fail ArgumentError, "must be one of #{Asset::TYPES}" end line = Asset.send(*line) end limit = attributes.key?(:limit) ? interpret_amount(attributes[:limit]) : MAX_INT64 raise ArgumentError, "Bad :limit #{limit}" unless limit.is_a?(Integer) op = ChangeTrustOp.new(line: line, limit: limit) make(attributes.merge({ body: [:change_trust, op] })) end
Helper method to create a valid CreateClaimableBalanceOp
, ready to be used within a transactions `operations` array.
@see Digitalbits::DSL::Claimant
@param balance_id [ClaimableBalanceID] unique ID of claimable balance
@return [Operation] the built operation, containing a Digitalbits::ChangeTrustOp
body
# File lib/digitalbits/operation.rb, line 233 def claim_claimable_balance(balance_id:, **attributes) op = ClaimClaimableBalanceOp.new(balance_id: balance_id) make(attributes.merge(body: [:claim_claimable_balance, op])) end
# File lib/digitalbits/operation.rb, line 521 def clawback(source_account:, from:, amount:) asset, amount = get_asset_amount(amount) if amount == 0 raise ArgumentError, "Amount can not be zero" end if amount < 0 raise ArgumentError, "Negative amount is not allowed" end op = ClawbackOp.new( amount: amount, from: from.muxed_account, asset: asset ) make({ source_account: source_account, body: [:clawback, op] }) end
Helper method to create clawback claimable balance operation
@param [Digitalbits::KeyPair] source_account the attributes to create the operation with @param [String] balance_id `ClaimableBalanceID`, serialized in hex
@return [Digitalbits::Operation] the built operation
# File lib/digitalbits/operation.rb, line 550 def clawback_claimable_balance(source_account:, balance_id:) balance_id = Digitalbits::ClaimableBalanceID.from_xdr(balance_id, :hex) op = ClawbackClaimableBalanceOp.new(balance_id: balance_id) make( source_account: source_account, body: [:clawback_claimable_balance, op] ) rescue XDR::ReadError raise ArgumentError, "Claimable balance id '#{balance_id}' is invalid" end
# File lib/digitalbits/operation.rb, line 163 def create_account(attributes = {}) destination = attributes[:destination] starting_balance = interpret_amount(attributes[:starting_balance]) raise ArgumentError unless destination.is_a?(KeyPair) op = CreateAccountOp.new op.destination = destination.account_id op.starting_balance = starting_balance make(attributes.merge({ body: [:create_account, op] })) end
Helper method to create a valid CreateClaimableBalanceOp
, ready to be used within a transactions `operations` array.
@see Digitalbits::DSL::Claimant
@param asset [Asset] the asset to transfer to a claimable balance @param amount [Fixnum] the amount of `asset` to put into a claimable balance @param claimants [Array<Claimant>] accounts authorized to claim the balance in the future
@return [Operation] the built operation
# File lib/digitalbits/operation.rb, line 219 def create_claimable_balance(asset:, amount:, claimants:, **attributes) op = CreateClaimableBalanceOp.new(asset: asset, amount: amount, claimants: claimants) make(attributes.merge(body: [:create_claimable_balance, op])) end
# File lib/digitalbits/operation.rb, line 317 def create_passive_sell_offer(attributes = {}) buying = attributes[:buying] if buying.is_a?(Array) buying = Asset.send(*buying) end selling = attributes[:selling] if selling.is_a?(Array) selling = Asset.send(*selling) end amount = interpret_amount(attributes[:amount]) price = interpret_price(attributes[:price]) op = CreatePassiveSellOfferOp.new({ buying: buying, selling: selling, amount: amount, price: price }) make(attributes.merge({ body: [:create_passive_sell_offer, op] })) end
# File lib/digitalbits/operation.rb, line 247 def end_sponsoring_future_reserves(**attributes) make(attributes.merge(body: [:end_sponsoring_future_reserves])) end
Helper method to create an inflation operation
@param [Hash] attributes the attributes to create the operation with @option attributes [Integer] :sequence
@return [Digitalbits::Operation] the built operation
# File lib/digitalbits/operation.rb, line 468 def inflation(attributes = {}) sequence = attributes[:sequence] raise ArgumentError, "Bad :sequence #{sequence}" unless sequence.is_a?(Integer) # TODO: add source_account support make(attributes.merge({ body: [:inflation] })) end
Construct a new Digitalbits::Operation
from the provided source account and body
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :source_account @option attributes [Digitalbits::Operation::Body] :body
@return [Digitalbits::Operation] the built operation
# File lib/digitalbits/operation.rb, line 23 def make(attributes = {}) source_account = attributes[:source_account] if source_account && !source_account.is_a?(Digitalbits::KeyPair) raise ArgumentError, "Bad :source_account" end body = Digitalbits::Operation::Body.new(*attributes[:body]) Digitalbits::Operation.new( body: body, source_account: source_account&.muxed_account ) end
# File lib/digitalbits/operation.rb, line 291 def manage_buy_offer(attributes = {}) buying = attributes[:buying] if buying.is_a?(Array) buying = Asset.send(*buying) end selling = attributes[:selling] if selling.is_a?(Array) selling = Asset.send(*selling) end amount = interpret_amount(attributes[:amount]) offer_id = attributes[:offer_id] || 0 price = interpret_price(attributes[:price]) op = ManageBuyOfferOp.new({ buying: buying, selling: selling, buy_amount: amount, price: price, offer_id: offer_id }) make(attributes.merge({ body: [:manage_buy_offer, op] })) end
Helper method to create an manage data operation
@param [Hash] attributes the attributes to create the operation with @option attributes [Integer] :sequence
@return [Digitalbits::Operation] the built operation
# File lib/digitalbits/operation.rb, line 486 def manage_data(attributes = {}) op = ManageDataOp.new name = attributes[:name] value = attributes[:value] raise ArgumentError, "Invalid :name" unless name.is_a?(String) raise ArgumentError, ":name too long" unless name.bytesize <= 64 if value.present? raise ArgumentError, ":value too long" unless value.bytesize <= 64 end op.data_name = name op.data_value = value make(attributes.merge({ body: [:manage_data, op] })) end
# File lib/digitalbits/operation.rb, line 265 def manage_sell_offer(attributes = {}) buying = attributes[:buying] if buying.is_a?(Array) buying = Asset.send(*buying) end selling = attributes[:selling] if selling.is_a?(Array) selling = Asset.send(*selling) end amount = interpret_amount(attributes[:amount]) offer_id = attributes[:offer_id] || 0 price = interpret_price(attributes[:price]) op = ManageSellOfferOp.new({ buying: buying, selling: selling, amount: amount, price: price, offer_id: offer_id }) make(attributes.merge({ body: [:manage_sell_offer, op] })) end
Helper method to create a valid PathPaymentStrictReceiveOp
, wrapped in the necessary XDR structs to be included within a transactions `operations` array.
@deprecated Please use Operation.path_payment_strict_receive
@see Digitalbits::Asset
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :destination the receiver of the payment @option attributes [Array] :amount the destination asset and the amount to pay @option attributes [Array] :with the source asset and maximum allowed source amount to pay with @option attributes [Array<Digitalbits::Asset>] :path the payment path to use
@return [Digitalbits::Operation] the built operation, containing a Digitalbits::PaymentOp
body
# File lib/digitalbits/operation.rb, line 83 def path_payment(attributes = {}) path_payment_strict_receive(attributes) end
Helper method to create a valid PathPaymentStrictReceiveOp
, wrapped in the necessary XDR structs to be included within a transactions `operations` array.
@see Digitalbits::Asset
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :destination the receiver of the payment @option attributes [Array] :amount the destination asset and the amount to pay @option attributes [Array] :with the source asset and maximum allowed source amount to pay with @option attributes [Array<Digitalbits::Asset>] :path the payment path to use
@return [Digitalbits::Operation] the built operation, containing a Digitalbits::PaymentOp
body
# File lib/digitalbits/operation.rb, line 102 def path_payment_strict_receive(attributes = {}) destination = attributes[:destination] asset, amount = get_asset_amount(attributes[:amount]) send_asset, send_max = get_asset_amount(attributes[:with]) path = (attributes[:path] || []).map { |p| p.is_a?(Array) ? Digitalbits::Asset.send(*p) : p } raise ArgumentError unless destination.is_a?(KeyPair) op = PathPaymentStrictReceiveOp.new op.send_asset = send_asset op.send_max = send_max op.destination = destination.muxed_account op.dest_asset = asset op.dest_amount = amount op.path = path make(attributes.merge({ body: [:path_payment_strict_receive, op] })) end
Helper method to create a valid PathPaymentStrictSendOp
, wrapped in the necessary XDR structs to be included within a transactions `operations` array.
@see Digitalbits::Asset
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :destination the receiver of the payment @option attributes [Array] :amount the destination asset and the minimum amount of destination asset to be received @option attributes [Array] :with the source asset and amount to pay with @option attributes [Array<Digitalbits::Asset>] :path the payment path to use
@return [Digitalbits::Operation] the built operation, containing a Digitalbits::PaymentOp
body
# File lib/digitalbits/operation.rb, line 140 def path_payment_strict_send(attributes = {}) destination = attributes[:destination] asset, dest_min = get_asset_amount(attributes[:amount]) send_asset, send_amount = get_asset_amount(attributes[:with]) path = (attributes[:path] || []).map { |p| p.is_a?(Array) ? Digitalbits::Asset.send(*p) : p } raise ArgumentError unless destination.is_a?(KeyPair) op = PathPaymentStrictSendOp.new op.send_asset = send_asset op.send_amount = send_amount op.destination = destination.muxed_account op.dest_asset = asset op.dest_min = dest_min op.path = path make(attributes.merge({ body: [:path_payment_strict_send, op] })) end
Helper method to create a valid PaymentOp
, wrapped in the necessary XDR structs to be included within a transactions `operations` array.
@see Digitalbits::Asset
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :destination the receiver of the payment @option attributes [Array] :amount the amount to pay @return [Digitalbits::Operation] the built operation, containing a
Digitalbits::PaymentOp body
# File lib/digitalbits/operation.rb, line 50 def payment(attributes = {}) destination = attributes[:destination] asset, amount = get_asset_amount(attributes[:amount]) raise ArgumentError unless destination.is_a?(KeyPair) op = PaymentOp.new op.asset = asset op.amount = amount op.destination = destination.muxed_account make(attributes.merge({ body: [:payment, op] })) end
@param sponsored [#to_keypair] owner of sponsored entry
# File lib/digitalbits/operation.rb, line 252 def revoke_sponsorship(sponsored:, **attributes) key_fields = attributes.slice(:offer_id, :data_name, :balance_id, :asset, :signer) raise ArgumentError, "conflicting attributes: #{key_fields.keys.join(", ")}" if key_fields.size > 1 account_id = KeyPair(sponsored).account_id key, value = key_fields.first op = if key == :signer RevokeSponsorshipOp.signer(account_id: account_id, signer_key: SignerKey(value)) else RevokeSponsorshipOp.ledger_key(LedgerKey.from(account_id: account_id, **key_fields)) end make(attributes.merge(body: [:revoke_sponsorship, op])) end
Helper method to create a valid SetOptionsOp
, wrapped in the necessary XDR structs to be included within a transactions `operations` array.
@param [Hash] attributes the attributes to create the operation with @option attributes [Digitalbits::KeyPair] :inflation_dest @option attributes [Array<Digitalbits::AccountFlags>] :set flags to set @option attributes [Array<Digitalbits::AccountFlags>] :clear flags to clear @option attributes [String] :thresholds @option attributes [Digitalbits::Signer] :signer
@return [Digitalbits::Operation] the built operation, containing a
Digitalbits::SetOptionsOp body
# File lib/digitalbits/operation.rb, line 355 def set_options(attributes = {}) op = SetOptionsOp.new op.set_flags = Digitalbits::AccountFlags.make_mask attributes[:set] op.clear_flags = Digitalbits::AccountFlags.make_mask attributes[:clear] op.master_weight = attributes[:master_weight] op.low_threshold = attributes[:low_threshold] op.med_threshold = attributes[:med_threshold] op.high_threshold = attributes[:high_threshold] op.signer = attributes[:signer] op.home_domain = attributes[:home_domain] inflation_dest = attributes[:inflation_dest] if inflation_dest raise ArgumentError, "Bad :inflation_dest" unless inflation_dest.is_a?(Digitalbits::KeyPair) op.inflation_dest = inflation_dest.account_id end make(attributes.merge({ body: [:set_options, op] })) end
@param asset [Digitalbits::Asset] @param trustor [Digitalbits::KeyPair] @param flags [{String, Symbol, Digitalbits::TrustLineFlags
=> true, false}] flags to to set or clear @param source_account [Digitalbits::KeyPair] source account (default is `nil`, which will use the source account of transaction)
# File lib/digitalbits/operation.rb, line 382 def set_trust_line_flags(asset:, trustor:, flags: {}, source_account: nil) op = Digitalbits::SetTrustLineFlagsOp.new op.trustor = KeyPair(trustor).account_id op.asset = Asset(asset) op.attributes = Digitalbits::TrustLineFlags.set_clear_masks(flags) make( source_account: source_account, body: [:set_trust_line_flags, op] ) end
Private Class Methods
# File lib/digitalbits/operation.rb, line 564 def get_asset_amount(values) amount = interpret_amount(values.last) asset = if values[0].is_a?(Digitalbits::Asset) values.first else Digitalbits::Asset.send(*values[0...-1]) end [asset, amount] end
# File lib/digitalbits/operation.rb, line 575 def interpret_amount(amount) case amount when String (BigDecimal(amount) * Digitalbits::ONE).floor when Integer amount * Digitalbits::ONE when Numeric (amount * Digitalbits::ONE).floor else raise ArgumentError, "Invalid amount type: #{amount.class}. Must be String or Numeric" end end
# File lib/digitalbits/operation.rb, line 588 def interpret_price(price) case price when String bd = BigDecimal(price) Price.from_f(bd) when Numeric Price.from_f(price) when Digitalbits::Price price else raise ArgumentError, "Invalid price type: #{price.class}. Must be String, Numeric, or Digitalbits::Price" end end