package main import ( "fmt" "github.com/Peersyst/xrpl-go/pkg/crypto" "github.com/Peersyst/xrpl-go/xrpl/currency" "github.com/Peersyst/xrpl-go/xrpl/faucet" transactions "github.com/Peersyst/xrpl-go/xrpl/transaction" "github.com/Peersyst/xrpl-go/xrpl/transaction/types" "github.com/Peersyst/xrpl-go/xrpl/wallet" "github.com/Peersyst/xrpl-go/xrpl/websocket" ) const ( currencyCode = "USDA" ) type SubmittableTransaction interface { TxType() transactions.TxType Flatten() transactions.FlatTransaction // Ensures all transactions can be flattened } func main() { fmt.Println("⏳ Setting up client...") client := getClient() fmt.Println("Connecting to server...") if err := client.Connect(); err != nil { fmt.Println(err) return } fmt.Println("✅ Client configured!") fmt.Println() fmt.Printf("Connection: %t", client.IsConnected()) fmt.Println() // Configure wallets // Issuer fmt.Println("⏳ Setting up issuer wallet...") issuer, err := wallet.New(crypto.ED25519()) if err != nil { fmt.Printf("❌ Error creating issuer wallet: %s\n", err) return } err = client.FundWallet(&issuer) if err != nil { fmt.Printf("❌ Error funding issuer wallet: %s\n", err) return } fmt.Printf("✅ Issuer wallet funded: %s\n", issuer.ClassicAddress) // ----------------------------------------------------- // Holder 1 fmt.Println("⏳ Setting up holder 1 wallet...") holderWallet1, err := wallet.New(crypto.ED25519()) if err != nil { fmt.Printf("❌ Error creating holder wallet 1: %s\n", err) return } err = client.FundWallet(&holderWallet1) if err != nil { fmt.Printf("❌ Error funding holder wallet 1: %s\n", err) return } fmt.Printf("✅ Holder wallet 1 funded: %s\n", holderWallet1.ClassicAddress) // ----------------------------------------------------- // Holder 2 fmt.Println("⏳ Setting up holder 2 wallet...") 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.Printf("✅ Holder wallet 2 funded: %s\n", holderWallet2.ClassicAddress) fmt.Println() fmt.Println("✅ Wallets setup complete!") fmt.Println() // ----------------------------------------------------- // Configuring Issuing account fmt.Println("⏳ Configuring issuer address settings...") accountSet := &transactions.AccountSet{ BaseTx: transactions.BaseTx{ Account: types.Address(issuer.ClassicAddress), }, Domain: types.Domain("697373756572"), // issuer } accountSet.SetAsfDefaultRipple() submitAndWait(client, accountSet, issuer) // ----------------------------------------------------- // Trustline from the holder 1 to the issuer fmt.Println("⏳ Setting up trustline from holder 1 to the issuer...") trustSet := &transactions.TrustSet{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet1.ClassicAddress), }, LimitAmount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "1000000000", }} trustSet.SetSetNoRippleFlag() submitAndWait(client, trustSet, holderWallet1) // ----------------------------------------------------- // Trustline from the holder 2 to the issuer fmt.Println("⏳ Setting up trustline from holder 2 to the issuer...") trustSet = &transactions.TrustSet{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet2.ClassicAddress), }, LimitAmount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "1000000000", }, } trustSet.SetSetNoRippleFlag() submitAndWait(client, trustSet, holderWallet2) // ----------------------------------------------------- // Minting to Holder 1 fmt.Println("⏳ Minting to Holder 1...") payment := &transactions.Payment{ BaseTx: transactions.BaseTx{ Account: types.Address(issuer.ClassicAddress), }, Destination: types.Address(holderWallet1.ClassicAddress), Amount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "50000", }, } submitAndWait(client, payment, issuer) // ----------------------------------------------------- // Minting to Holder 2 fmt.Println("⏳ Minting to Holder 2...") payment = &transactions.Payment{ BaseTx: transactions.BaseTx{ Account: types.Address(issuer.ClassicAddress), }, Destination: types.Address(holderWallet2.ClassicAddress), Amount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "40000", }, } submitAndWait(client, payment, issuer) // ----------------------------------------------------- // Sending payment from Holder 1 to Holder 2 fmt.Println("⏳ Sending payment from Holder 1 to Holder 2...") payment = &transactions.Payment{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet1.ClassicAddress), }, Destination: types.Address(holderWallet2.ClassicAddress), Amount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "20", }, } submitAndWait(client, payment, holderWallet1) // ----------------------------------------------------- // Freezing and Deep Freezing holder1 fmt.Println("⏳ Freezing and Deep Freezing holder 1 trustline...") trustSet = &transactions.TrustSet{ BaseTx: transactions.BaseTx{ Account: types.Address(issuer.ClassicAddress), }, LimitAmount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(holderWallet1.ClassicAddress), Value: "0", }, } trustSet.SetSetFreezeFlag() trustSet.SetSetDeepFreezeFlag() submitAndWait(client, trustSet, issuer) // ------------------- SHOULD FAIL ⬇️ ------------------ // Sending payment from Holder 1 to Holder 2 (which should fail), Holder 1 can't decrease its balance fmt.Println("⏳ Sending payment from Holder 1 to Holder 2 (which should fail). Holder 1 can't decrease its balance...") payment = &transactions.Payment{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet1.ClassicAddress), }, Destination: types.Address(holderWallet2.ClassicAddress), Amount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "10", }, } submitAndWait(client, payment, holderWallet1) // ------------------- SHOULD FAIL ⬇️ ------------------ // Sending payment from Holder 2 to Holder 1 (which should fail), Holder 1 can't increase its balance fmt.Println("⏳ Sending payment from Holder 2 to Holder 1 (which should fail). Holder 1 can't increase its balance...") payment = &transactions.Payment{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet2.ClassicAddress), }, Destination: types.Address(holderWallet1.ClassicAddress), Amount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "10", }, } submitAndWait(client, payment, holderWallet2) // ------------------- SHOULD FAIL ⬇️ ------------------ // Creating OfferCreate transaction (which should fail), Holder 1 can't create an offer fmt.Println("⏳ Creating OfferCreate transaction (which should fail). Holder 1 can't create an offer...") offerCreate := &transactions.OfferCreate{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet1.ClassicAddress), }, TakerPays: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "10", }, TakerGets: types.XRPCurrencyAmount(10), } submitAndWait(client, offerCreate, holderWallet1) // ----------------------------------------------------- // Unfreezing and Deep Unfreezing holder 1 fmt.Println("⏳ Unfreezing and Deep Unfreezing holder 1 trustline...") trustSet = &transactions.TrustSet{ BaseTx: transactions.BaseTx{ Account: types.Address(issuer.ClassicAddress), }, LimitAmount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(holderWallet1.ClassicAddress), Value: "0", }, } trustSet.SetClearFreezeFlag() trustSet.SetClearDeepFreezeFlag() submitAndWait(client, trustSet, issuer) // ----------------------------------------------------- // Sending payment from Holder 1 to Holder 2 (which should succeed), Holder 1 can decrease its balance fmt.Println("⏳ Sending payment from Holder 1 to Holder 2 (which should succeed). Holder 1 can decrease its balance...") payment = &transactions.Payment{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet1.ClassicAddress), }, Destination: types.Address(holderWallet2.ClassicAddress), Amount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "10", }, } submitAndWait(client, payment, holderWallet1) // ----------------------------------------------------- // Sending payment from Holder 2 to Holder 1 (which should succeed), Holder 1 can increase its balance fmt.Println("⏳ Sending payment from Holder 2 to Holder 1 (which should succeed). Holder 1 can increase its balance...") payment = &transactions.Payment{ BaseTx: transactions.BaseTx{ Account: types.Address(holderWallet2.ClassicAddress), }, Destination: types.Address(holderWallet1.ClassicAddress), Amount: types.IssuedCurrencyAmount{ Currency: currency.ConvertStringToHex(currencyCode), Issuer: types.Address(issuer.ClassicAddress), Value: "10", }, } submitAndWait(client, payment, holderWallet2) } // getRpcClient returns a new rpc client func getClient() *websocket.Client { client := websocket.NewClient( websocket.NewClientConfig(). WithHost("wss://s.devnet.rippletest.net:51233"). WithFaucetProvider(faucet.NewDevnetFaucetProvider()), ) return client } // submitAndWait submits a transaction and waits for it to be included in a validated ledger func submitAndWait(client *websocket.Client, txn SubmittableTransaction, wallet wallet.Wallet) { fmt.Printf("⏳ Submitting %s transaction...\n", txn.TxType()) flattenedTx := txn.Flatten() err := client.Autofill(&flattenedTx) if err != nil { fmt.Printf("❌ Error autofilling %s transaction: %s\n", txn.TxType(), err) fmt.Println() return } txBlob, _, err := wallet.Sign(flattenedTx) if err != nil { fmt.Printf("❌ Error signing %s transaction: %s\n", txn.TxType(), err) fmt.Println() return } response, err := client.SubmitTxBlobAndWait(txBlob, false) if err != nil { fmt.Printf("❌ Error submitting %s transaction: %s\n", txn.TxType(), err) fmt.Println() return } fmt.Printf("✅ %s transaction submitted\n", txn.TxType()) fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) fmt.Println() }