🚀

Path Payments - Stellar

2023/01/04に公開

Welcome

Hi, nice to meet you. Wishing you and yours a prosperous 2023.
Well, my first technical post is a note on using “Path Payment Strict Send/Receive” operation in Stellar Network.

First, a conclusion

When using “Path Payment Strict Send/Receive” Operation, it is possible to relay non-authorization Assets. Of course, “Path Payment Strict Send/Receive” will target assets that are offered as offers.
So if offers are created, even assets for a limited account could be executed in an outside account.

Why?

“Path Payment Strict Send/Receive” operation allows the asset output from the execution of an offer to be used as input for another offer. This works like a Unix Pipeline. And the execution of this series of offers is a consistent processing, just as in a relational database transaction.
In other words, TrustLine is a restriction on whether assets can be held, not whether assets are transferable.

Example

There are two offers:
1: buy Asset:A - sell Asset:B
2: buy Asset:B - sell Asset:C
You have not established only a TrustLine for Asset:B, but "Path Payment Strict Send" operation can be used to exchange Asset:A to Asset:C.
The program code for this process is listed at the bottom of the article.

Remarks

Soroban is getting a lot of attention and it is going to be a great year for Stellar.
As a developer myself, I am looking forward to it.
Let’s get Soroban-ing!!

Please check the official website for all accurate information about Stellar.
https://www.stellar.org/blog


Sample code by Ruby

I'm Japanese, so I support Ruby!

require 'stellar-sdk'

Client = Stellar::Client.default_testnet

# create issuer
Issuer = Stellar::KeyPair.random
Client.friendbot(Issuer)

# define assets
AssetA = Stellar::Asset.alphanum4(?A, Issuer)
AssetB = Stellar::Asset.alphanum4(?B, Issuer)
AssetC = Stellar::Asset.alphanum4(?C, Issuer)

# manage offers
Client.horizon.transactions._post(tx:
  Stellar::TransactionBuilder.new(
    source_account: Issuer,
    sequence_number: Client.account_info(Issuer.address).sequence.to_i + 1
  )
  .add_operation(
    # buy Asset:A - sell Asset:B
    Stellar::Operation.manage_buy_offer(
      buying: AssetA,
      selling: AssetB,
      amount: 100,
      price: 1
    )
  )
  .add_operation(
    # buy Asset:B - sell Asset:C
    Stellar::Operation.manage_buy_offer(
      buying: AssetB,
      selling: AssetC,
      amount: 100,
      price: 1
    )
  )
  .set_timeout(600).build.to_envelope(Issuer).to_xdr(:base64)
)

# create trader
Trader = Stellar::KeyPair.random
Client.friendbot(Trader)

# change trustline without Asset:B
Client.horizon.transactions._post(tx:
  Stellar::TransactionBuilder.new(
    source_account: Trader,
    sequence_number: Client.account_info(Trader.address).sequence.to_i + 1
  )
  .add_operation(
    # for Asset:A
    Stellar::Operation.change_trust(asset: AssetA)
  )
  .add_operation(
    # for Asset:C
    Stellar::Operation.change_trust(asset: AssetC)
  )
  .set_timeout(600).build.to_envelope(Trader).to_xdr(:base64)
)

# payment seed Asset:A
Client.horizon.transactions._post(tx:
  Stellar::TransactionBuilder.new(
    source_account: Issuer,
    sequence_number: Client.account_info(Issuer.address).sequence.to_i + 1
  )
  .add_operation(
    Stellar::Operation.payment(
      destination: Trader,
      amount: [AssetA, 100]
    )
  )
  .set_timeout(600).build.to_envelope(Issuer).to_xdr(:base64)
)

# check
puts 'Before'
Client.account_info(Trader.address).balances.each { |balance|
  puts "  Asset:#{balance['asset_code']} = #{balance['balance']}" if [?A, ?C].include?(balance['asset_code'])
}

# path payment Asset:A to Asset:C
Client.horizon.transactions._post(tx:
  Stellar::TransactionBuilder.new(
    source_account: Trader,
    sequence_number: Client.account_info(Trader.address).sequence.to_i + 1
  )
  .add_operation(
    Stellar::Operation.path_payment_strict_send(
      destination: Trader,
      with: [AssetA, 100],
      amount: [AssetC, 100],
      path: [AssetB]
    )
  )
  .set_timeout(600).build.to_envelope(Trader).to_xdr(:base64)
)

# check
puts 'After'
Client.account_info(Trader.address).balances.each { |balance|
  puts "  Asset:#{balance['asset_code']} = #{balance['balance']}" if [?A, ?C].include?(balance['asset_code'])
}

Reference: https://github.com/astroband/ruby-stellar-sdk

Discussion