forked from xyield/xrpl-go
-
Notifications
You must be signed in to change notification settings - Fork 18
TokenEscrow Support (XLS-85) #167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
GuillemGarciaDev
merged 24 commits into
XRPLF:v0.1.x
from
florent-uzio:feat/token-escrow
Oct 17, 2025
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
496b8ef
updated Escrow ledger entry type
florent-uzio 23beecb
AccountRoot updated
florent-uzio f0b58c6
EscrowCreate Amount updated and tests
florent-uzio f410287
LockedAmount in MPTokenIssuance
florent-uzio 57b1b9f
payment channel create updated
florent-uzio f65fb81
payment channel claim Amount and Balance updated
florent-uzio 904c2e4
payment channel create, added tests for flatten with iou and mpt
florent-uzio 5432375
Payment channel unmarshal and tests
florent-uzio 766d5fc
Added the asfAllowTrustLineLocking flag
florent-uzio 58c47f1
fixed flatten fields for escrow .String()
florent-uzio 6bba89b
updated TxResponse to handle TxJson field and Sequence
florent-uzio fc5524f
TokenEscrow rpc example IOU and update PermissionedDex
florent-uzio f162d79
WS TokenEscrow example and updated Sequence func in flat_tx.go
florent-uzio e9bdb14
changelog
florent-uzio 0e9420f
renamed TxJson to TxJSON
florent-uzio 7f897bc
fixed linting for integer overflow
florent-uzio 15bc88a
domain.go added ignore linting error from revive
florent-uzio 27df013
TestAccountRoot_SetLsfAllowTrustLineLocking
florent-uzio f797ce7
reverted payment channel create amount type
florent-uzio 35c1f96
channel claim reverted
florent-uzio 5a47fdc
channel fund reverted
florent-uzio 50a2667
updated claim comments and test name
florent-uzio 1c16391
Added Optional to claim comment
florent-uzio 5e106b9
space claim comment total
florent-uzio File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,271 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "time" | ||
|
|
||
| "github.com/Peersyst/xrpl-go/pkg/crypto" | ||
| "github.com/Peersyst/xrpl-go/xrpl/currency" | ||
|
|
||
| "github.com/Peersyst/xrpl-go/xrpl/faucet" | ||
| "github.com/Peersyst/xrpl-go/xrpl/rpc" | ||
| "github.com/Peersyst/xrpl-go/xrpl/rpc/types" | ||
| rippleTime "github.com/Peersyst/xrpl-go/xrpl/time" | ||
| transactions "github.com/Peersyst/xrpl-go/xrpl/transaction" | ||
| txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" | ||
| "github.com/Peersyst/xrpl-go/xrpl/wallet" | ||
| ) | ||
|
|
||
| // safeInt64ToUint32 safely converts int64 to uint32 with bounds checking | ||
| func safeInt64ToUint32(value int64) uint32 { | ||
| if value < 0 { | ||
| return 0 | ||
| } | ||
| if value > int64(^uint32(0)) { | ||
| return ^uint32(0) // max uint32 value | ||
| } | ||
| return uint32(value) | ||
| } | ||
|
|
||
| func main() { | ||
|
|
||
| // | ||
| // Configure client | ||
| // | ||
| fmt.Println("⏳ Setting up client...") | ||
| cfg, err := rpc.NewClientConfig( | ||
| "https://s.devnet.rippletest.net:51234/", | ||
| rpc.WithFaucetProvider(faucet.NewDevnetFaucetProvider()), | ||
| ) | ||
| if err != nil { | ||
| panic(err) | ||
| } | ||
|
|
||
| client := rpc.NewClient(cfg) | ||
| fmt.Println("✅ Client configured!") | ||
| fmt.Println() | ||
|
|
||
| // Configure wallets | ||
| issuerWallet, holderWallet, holderWallet2 := createWallets(client) | ||
|
|
||
| // Configure issuer wallet to allow trust line locking | ||
| configureIssuerWallet(client, issuerWallet) | ||
|
|
||
| // Create trust line from holder to issuer | ||
| createTrustLine(client, issuerWallet, holderWallet, holderWallet2) | ||
|
|
||
| // Mint token from issuer to holder | ||
| mintToken(client, issuerWallet, holderWallet) | ||
|
|
||
| // Create escrow, the holder will escrow 100 tokens to the issuer | ||
| offerSequence := createEscrow(client, issuerWallet, holderWallet, holderWallet2) | ||
|
|
||
| // Finish escrow | ||
| finishEscrow(client, holderWallet, holderWallet2, offerSequence) | ||
| } | ||
|
|
||
| // createWallets configures the issuer and holder wallets. | ||
| func createWallets(client *rpc.Client) (issuerWallet, holderWallet, holderWallet2 wallet.Wallet) { | ||
| fmt.Println("⏳ Setting up wallets...") | ||
| issuerWallet, err := wallet.New(crypto.ED25519()) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error creating issuer wallet: %s\n", err) | ||
| return | ||
| } | ||
| err = client.FundWallet(&issuerWallet) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error funding issuer wallet: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("💸 Issuer wallet funded!") | ||
|
|
||
| // Holder wallet | ||
| holderWallet, err = wallet.New(crypto.ED25519()) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error creating holder wallet: %s\n", err) | ||
| return | ||
| } | ||
| err = client.FundWallet(&holderWallet) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error funding holder wallet: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("💸 Holder wallet funded!") | ||
|
|
||
| // Holder wallet 2 | ||
| holderWallet2, err = wallet.New(crypto.ED25519()) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error creating holder wallet 2: %s\n", err) | ||
| return | ||
| } | ||
| err = client.FundWallet(&holderWallet2) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error funding holder wallet 2: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("💸 Holder wallet 2 funded!") | ||
|
|
||
| fmt.Println("✅ Wallets setup complete!") | ||
| fmt.Println("💳 Issuer wallet:", issuerWallet.ClassicAddress) | ||
| fmt.Println("💳 Holder wallet:", holderWallet.ClassicAddress) | ||
| fmt.Println("💳 Holder wallet 2:", holderWallet2.ClassicAddress) | ||
| fmt.Println() | ||
|
|
||
| return issuerWallet, holderWallet, holderWallet2 | ||
| } | ||
|
|
||
| // configureIssuerWallet configures the issuer wallet to allow trust line locking. | ||
| func configureIssuerWallet(client *rpc.Client, issuerWallet wallet.Wallet) { | ||
| fmt.Println("⏳ Configuring issuer wallet...") | ||
| accountSet := &transactions.AccountSet{ | ||
| BaseTx: transactions.BaseTx{ | ||
| Account: issuerWallet.ClassicAddress, | ||
| }, | ||
| } | ||
| accountSet.SetAsfAllowTrustLineLocking() | ||
| accountSetResponse, err := client.SubmitTxAndWait(accountSet.Flatten(), &types.SubmitOptions{ | ||
| Autofill: true, | ||
| Wallet: &issuerWallet, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error configuring issuer wallet: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("✅ Issuer wallet configured!") | ||
| fmt.Printf("🌐 Hash: %s\n", accountSetResponse.Hash.String()) | ||
| fmt.Println() | ||
| } | ||
|
|
||
| // createTrustLine creates a trust line for the holder wallet. | ||
| func createTrustLine(client *rpc.Client, issuerWallet, holderWallet, holderWallet2 wallet.Wallet) { | ||
| fmt.Println("⏳ Creating trust line for holder wallet...") | ||
| trustLine := &transactions.TrustSet{ | ||
| BaseTx: transactions.BaseTx{ | ||
| Account: holderWallet.ClassicAddress, | ||
| }, | ||
| LimitAmount: txnTypes.IssuedCurrencyAmount{ | ||
| Issuer: issuerWallet.ClassicAddress, | ||
| Currency: currency.ConvertStringToHex("ABCD"), | ||
| Value: "1000000", | ||
| }, | ||
| } | ||
| trustLine.SetSetNoRippleFlag() | ||
| trustLineResponse, err := client.SubmitTxAndWait(trustLine.Flatten(), &types.SubmitOptions{ | ||
| Autofill: true, | ||
| Wallet: &holderWallet, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error creating trust line: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("✅ Trust line created for holder wallet!") | ||
| fmt.Printf("🌐 Hash: %s\n", trustLineResponse.Hash.String()) | ||
| fmt.Println() | ||
|
|
||
| fmt.Println("⏳ Creating trust line for holder wallet 2...") | ||
| trustLine = &transactions.TrustSet{ | ||
| BaseTx: transactions.BaseTx{ | ||
| Account: holderWallet2.ClassicAddress, | ||
| }, | ||
| LimitAmount: txnTypes.IssuedCurrencyAmount{ | ||
| Issuer: issuerWallet.ClassicAddress, | ||
| Currency: currency.ConvertStringToHex("ABCD"), | ||
| Value: "1000000", | ||
| }, | ||
| } | ||
| trustLine.SetSetNoRippleFlag() | ||
| trustLineResponse, err = client.SubmitTxAndWait(trustLine.Flatten(), &types.SubmitOptions{ | ||
| Autofill: true, | ||
| Wallet: &holderWallet2, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error creating trust line: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("✅ Trust line created for holder wallet 2!") | ||
| fmt.Printf("🌐 Hash: %s\n", trustLineResponse.Hash.String()) | ||
| fmt.Println() | ||
| } | ||
|
|
||
| // mintToken mints a token for the holder wallet. | ||
| func mintToken(client *rpc.Client, issuerWallet, holderWallet wallet.Wallet) { | ||
| fmt.Println("⏳ Minting token to holder wallet...") | ||
| token := &transactions.Payment{ | ||
| BaseTx: transactions.BaseTx{ | ||
| Account: issuerWallet.ClassicAddress, | ||
| }, | ||
| Destination: holderWallet.ClassicAddress, | ||
| Amount: txnTypes.IssuedCurrencyAmount{ | ||
| Issuer: issuerWallet.ClassicAddress, | ||
| Currency: currency.ConvertStringToHex("ABCD"), | ||
| Value: "10000", | ||
| }, | ||
| } | ||
| tokenResponse, err := client.SubmitTxAndWait(token.Flatten(), &types.SubmitOptions{ | ||
| Autofill: true, | ||
| Wallet: &issuerWallet, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error minting token: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("✅ Token minted!") | ||
| fmt.Printf("🌐 Hash: %s\n", tokenResponse.Hash.String()) | ||
| fmt.Println() | ||
| } | ||
|
|
||
| // createEscrow creates an escrow for the holder wallet. | ||
| func createEscrow(client *rpc.Client, issuerWallet, holderWallet, holderWallet2 wallet.Wallet) (offerSequence uint32) { | ||
| fmt.Println("⏳ Creating escrow...") | ||
| escrow := &transactions.EscrowCreate{ | ||
| BaseTx: transactions.BaseTx{ | ||
| Account: holderWallet.ClassicAddress, | ||
| }, | ||
| Amount: txnTypes.IssuedCurrencyAmount{ | ||
| Issuer: issuerWallet.ClassicAddress, | ||
| Currency: currency.ConvertStringToHex("ABCD"), | ||
| Value: "100", | ||
| }, | ||
| Destination: holderWallet2.ClassicAddress, | ||
| CancelAfter: safeInt64ToUint32(rippleTime.UnixTimeToRippleTime(time.Now().Unix()) + 4000), | ||
| FinishAfter: safeInt64ToUint32(rippleTime.UnixTimeToRippleTime(time.Now().Unix() + 5)), | ||
| } | ||
| escrowResponse, err := client.SubmitTxAndWait(escrow.Flatten(), &types.SubmitOptions{ | ||
| Autofill: true, | ||
| Wallet: &holderWallet, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error creating escrow: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("✅ Escrow created!") | ||
| fmt.Printf("🌐 Hash: %s\n", escrowResponse.Hash.String()) | ||
| fmt.Printf("🌐 Sequence: %d\n", escrowResponse.TxJSON.Sequence()) | ||
| fmt.Println() | ||
|
|
||
| return escrowResponse.TxJSON.Sequence() | ||
|
|
||
| } | ||
|
|
||
| // finishEscrow finishes the escrow for the holder wallet 2. | ||
| func finishEscrow(client *rpc.Client, holderWallet, holderWallet2 wallet.Wallet, offerSequence uint32) { | ||
| fmt.Println("⏳ Finishing escrow...") | ||
| escrow := &transactions.EscrowFinish{ | ||
| BaseTx: transactions.BaseTx{ | ||
| Account: holderWallet2.ClassicAddress, | ||
| }, | ||
| Owner: holderWallet.ClassicAddress, | ||
| OfferSequence: offerSequence, | ||
| } | ||
| escrowResponse, err := client.SubmitTxAndWait(escrow.Flatten(), &types.SubmitOptions{ | ||
| Autofill: true, | ||
| Wallet: &holderWallet2, | ||
| }) | ||
| if err != nil { | ||
| fmt.Printf("❌ Error finishing escrow: %s\n", err) | ||
| return | ||
| } | ||
| fmt.Println("✅ Escrow finished!") | ||
| fmt.Printf("🌐 Hash: %s\n", escrowResponse.Hash.String()) | ||
| fmt.Println() | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.