diff --git a/_code-samples/batch/README.md b/_code-samples/batch/README.md index e69de29bb2..c0852466c2 100644 --- a/_code-samples/batch/README.md +++ b/_code-samples/batch/README.md @@ -0,0 +1,4 @@ +# Batch + +Code samples showing how to create and submit a [Batch transaction](../../docs/concepts/transactions/batch-transactions.md). +Both for simple and multi account batch transactions. diff --git a/_code-samples/batch/go/go.mod b/_code-samples/batch/go/go.mod index 63f569b0cd..fa9fde5d08 100644 --- a/_code-samples/batch/go/go.mod +++ b/_code-samples/batch/go/go.mod @@ -1,5 +1,24 @@ module github.com/XRPLF -go 1.23 +go 1.23.0 -require github.com/Peersyst/xrpl-go v0.1.11 \ No newline at end of file +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/batch/go/go.sum b/_code-samples/batch/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/batch/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/batch/go/rpc/main.go b/_code-samples/batch/go/rpc/main.go index 9ab1e3e8e7..3675a7432d 100644 --- a/_code-samples/batch/go/rpc/main.go +++ b/_code-samples/batch/go/rpc/main.go @@ -1 +1,208 @@ -package rpc +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/rpc/types" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +var ( + CreatePaymentTx = func(sender, receiver *wallet.Wallet, amount txnTypes.CurrencyAmount) *transaction.Payment { + return &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: sender.GetAddress(), + TransactionType: transaction.PaymentTx, + Flags: txnTypes.TfInnerBatchTxn, + }, + Amount: amount, + Destination: receiver.GetAddress(), + } + } +) + +func main() { + // Configure the client + cfg, err := rpc.NewClientConfig( + "https://s.devnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + client := rpc.NewClient(cfg) + + // Create and fund wallets + userWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + user2Wallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + receiverWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + if err := client.FundWallet(&userWallet); err != nil { + fmt.Println(err) + return + } + if err := client.FundWallet(&user2Wallet); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Wallets funded") + + // Check initial balances + userBalance, err := client.GetXrpBalance(userWallet.ClassicAddress) + if err != nil { + userBalance = "0" + } + user2Balance, err := client.GetXrpBalance(user2Wallet.ClassicAddress) + if err != nil { + user2Balance = "0" + } + + receiverBalance, err := client.GetXrpBalance(receiverWallet.ClassicAddress) + if err != nil { + receiverBalance = "0" + } + + fmt.Printf("💳 User initial balance: %s XRP\n", userBalance) + fmt.Printf("💳 User2 initial balance: %s XRP\n", user2Balance) + fmt.Printf("💳 Receiver initial balance: %s XRP\n", receiverBalance) + fmt.Println() + + fmt.Printf("Batch transaction test\n") + + // Create test batch transaction + batchTx := &transaction.Batch{ + BaseTx: transaction.BaseTx{ + Account: txnTypes.Address(userWallet.ClassicAddress), + TransactionType: transaction.BatchTx, + }, + RawTransactions: []txnTypes.RawTransaction{ + {RawTransaction: CreatePaymentTx(&userWallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + {RawTransaction: CreatePaymentTx(&userWallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + }, + } + batchTx.SetAllOrNothingFlag() + + flattenedBatchTx := batchTx.Flatten() + fmt.Println("⏳ Autofilling flattened batch transaction...") + if err := client.Autofill(&flattenedBatchTx); err != nil { + fmt.Println("Autofill error:", err) + return + } + + fmt.Println("⏳ Signing batch transaction...") + response, err := client.SubmitTxAndWait(flattenedBatchTx, &types.SubmitOptions{ + Autofill: false, + Wallet: &userWallet, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Batch transaction submitted") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", response.Validated) + fmt.Println() + + // Check final balances + finalUserBalance, err := client.GetXrpBalance(userWallet.ClassicAddress) + if err != nil { + finalUserBalance = "0" + } + finalReceiverBalance, err := client.GetXrpBalance(receiverWallet.ClassicAddress) + if err != nil { + finalReceiverBalance = "0" + } + + fmt.Printf("💳 User final balance: %s XRP\n", finalUserBalance) + + fmt.Printf("💳 Receiver final balance: %s XRP\n", finalReceiverBalance) + + fmt.Println() + fmt.Printf("Multisig Batch transaction test\n") + + // Create test batch transaction + multiBatchTx := &transaction.Batch{ + BaseTx: transaction.BaseTx{ + Account: txnTypes.Address(userWallet.ClassicAddress), + TransactionType: transaction.BatchTx, + }, + RawTransactions: []txnTypes.RawTransaction{ + {RawTransaction: CreatePaymentTx(&userWallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + {RawTransaction: CreatePaymentTx(&user2Wallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + }, + BatchSigners: []txnTypes.BatchSigner{ + { + BatchSigner: txnTypes.BatchSignerData{ + Account: txnTypes.Address(user2Wallet.ClassicAddress), + SigningPubKey: user2Wallet.PublicKey, + }, + }, + }, + } + multiBatchTx.SetAllOrNothingFlag() + + flattenedMultiBatchTx := multiBatchTx.Flatten() + fmt.Println("⏳ Autofilling flattened multi batch transaction...") + if err := client.AutofillMultisigned(&flattenedMultiBatchTx, 1); err != nil { + fmt.Println("Autofill error:", err) + return + } + + fmt.Println("⏳ Signing multi batch transaction...") + if err := wallet.SignMultiBatch(user2Wallet, &flattenedMultiBatchTx, nil); err != nil { + fmt.Println("Signing error:", err) + return + } + + response, err = client.SubmitTxAndWait(flattenedMultiBatchTx, &types.SubmitOptions{ + Autofill: false, + Wallet: &userWallet, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Multisig Batch transaction submitted") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", response.Validated) + fmt.Println() + + // Check final balances + finalUser2Balance, err := client.GetXrpBalance(user2Wallet.ClassicAddress) + if err != nil { + finalUser2Balance = "0" + } + finalUserBalance, err = client.GetXrpBalance(userWallet.ClassicAddress) + if err != nil { + finalUserBalance = "0" + } + finalReceiverBalance, err = client.GetXrpBalance(receiverWallet.ClassicAddress) + if err != nil { + finalReceiverBalance = "0" + } + fmt.Printf("💳 User final balance: %s XRP\n", finalUserBalance) + fmt.Printf("💳 User2 final balance: %s XRP\n", finalUser2Balance) + fmt.Printf("💳 Receiver final balance: %s XRP\n", finalReceiverBalance) +} diff --git a/_code-samples/batch/go/ws/main.go b/_code-samples/batch/go/ws/main.go index 98592950df..db6bd304ba 100644 --- a/_code-samples/batch/go/ws/main.go +++ b/_code-samples/batch/go/ws/main.go @@ -1 +1,210 @@ -package ws +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" + "github.com/Peersyst/xrpl-go/xrpl/websocket" + "github.com/Peersyst/xrpl-go/xrpl/websocket/types" +) + +var ( + CreatePaymentTx = func(sender, receiver *wallet.Wallet, amount txnTypes.CurrencyAmount) *transaction.Payment { + return &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: sender.GetAddress(), + TransactionType: transaction.PaymentTx, + Flags: txnTypes.TfInnerBatchTxn, + }, + Amount: amount, + Destination: receiver.GetAddress(), + } + } +) + +func main() { + // Connect to testnet + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.devnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + // Create and fund wallets + userWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + user2Wallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + receiverWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + if err := client.FundWallet(&userWallet); err != nil { + fmt.Println(err) + return + } + if err := client.FundWallet(&user2Wallet); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Wallets funded") + + // Check initial balances + userBalance, err := client.GetXrpBalance(userWallet.ClassicAddress) + if err != nil { + userBalance = "0" + } + user2Balance, err := client.GetXrpBalance(user2Wallet.ClassicAddress) + if err != nil { + user2Balance = "0" + } + + receiverBalance, err := client.GetXrpBalance(receiverWallet.ClassicAddress) + if err != nil { + receiverBalance = "0" + } + + fmt.Printf("💳 User initial balance: %s XRP\n", userBalance) + fmt.Printf("💳 User2 initial balance: %s XRP\n", user2Balance) + fmt.Printf("💳 Receiver initial balance: %s XRP\n", receiverBalance) + fmt.Println() + + fmt.Printf("Batch transaction test\n") + + // Create test batch transaction + batchTx := &transaction.Batch{ + BaseTx: transaction.BaseTx{ + Account: txnTypes.Address(userWallet.ClassicAddress), + TransactionType: transaction.BatchTx, + }, + RawTransactions: []txnTypes.RawTransaction{ + {RawTransaction: CreatePaymentTx(&userWallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + {RawTransaction: CreatePaymentTx(&userWallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + }, + } + batchTx.SetAllOrNothingFlag() + + flattenedBatchTx := batchTx.Flatten() + fmt.Println("⏳ Autofilling flattened batch transaction...") + if err := client.Autofill(&flattenedBatchTx); err != nil { + fmt.Println("Autofill error:", err) + return + } + + fmt.Println("⏳ Signing batch transaction...") + response, err := client.SubmitTxAndWait(flattenedBatchTx, &types.SubmitOptions{ + Autofill: false, + Wallet: &userWallet, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Batch transaction submitted") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", response.Validated) + fmt.Println() + + // Check final balances + finalUserBalance, err := client.GetXrpBalance(userWallet.ClassicAddress) + if err != nil { + finalUserBalance = "0" + } + finalReceiverBalance, err := client.GetXrpBalance(receiverWallet.ClassicAddress) + if err != nil { + finalReceiverBalance = "0" + } + + fmt.Printf("💳 User final balance: %s XRP\n", finalUserBalance) + + fmt.Printf("💳 Receiver final balance: %s XRP\n", finalReceiverBalance) + + fmt.Println() + fmt.Printf("Multisig Batch transaction test\n") + + // Create test batch transaction + multiBatchTx := &transaction.Batch{ + BaseTx: transaction.BaseTx{ + Account: txnTypes.Address(userWallet.ClassicAddress), + TransactionType: transaction.BatchTx, + }, + RawTransactions: []txnTypes.RawTransaction{ + {RawTransaction: CreatePaymentTx(&userWallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + {RawTransaction: CreatePaymentTx(&user2Wallet, &receiverWallet, txnTypes.XRPCurrencyAmount(5000000)).Flatten()}, + }, + BatchSigners: []txnTypes.BatchSigner{ + { + BatchSigner: txnTypes.BatchSignerData{ + Account: txnTypes.Address(user2Wallet.ClassicAddress), + SigningPubKey: user2Wallet.PublicKey, + }, + }, + }, + } + multiBatchTx.SetAllOrNothingFlag() + + flattenedMultiBatchTx := multiBatchTx.Flatten() + fmt.Println("⏳ Autofilling flattened multi batch transaction...") + if err := client.AutofillMultisigned(&flattenedMultiBatchTx, 1); err != nil { + fmt.Println("Autofill error:", err) + return + } + + fmt.Println("⏳ Signing multi batch transaction...") + if err := wallet.SignMultiBatch(user2Wallet, &flattenedMultiBatchTx, nil); err != nil { + fmt.Println("Signing error:", err) + return + } + + response, err = client.SubmitTxAndWait(flattenedMultiBatchTx, &types.SubmitOptions{ + Autofill: false, + Wallet: &userWallet, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Multisig Batch transaction submitted") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", response.Validated) + fmt.Println() + + // Check final balances + finalUser2Balance, err := client.GetXrpBalance(user2Wallet.ClassicAddress) + if err != nil { + finalUser2Balance = "0" + } + finalUserBalance, err = client.GetXrpBalance(userWallet.ClassicAddress) + if err != nil { + finalUserBalance = "0" + } + finalReceiverBalance, err = client.GetXrpBalance(receiverWallet.ClassicAddress) + if err != nil { + finalReceiverBalance = "0" + } + fmt.Printf("💳 User final balance: %s XRP\n", finalUserBalance) + fmt.Printf("💳 User2 final balance: %s XRP\n", finalUser2Balance) + fmt.Printf("💳 Receiver final balance: %s XRP\n", finalReceiverBalance) +} diff --git a/_code-samples/checks/go/go.mod b/_code-samples/checks/go/go.mod index 63f569b0cd..fa9fde5d08 100644 --- a/_code-samples/checks/go/go.mod +++ b/_code-samples/checks/go/go.mod @@ -1,5 +1,24 @@ module github.com/XRPLF -go 1.23 +go 1.23.0 -require github.com/Peersyst/xrpl-go v0.1.11 \ No newline at end of file +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/checks/go/go.sum b/_code-samples/checks/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/checks/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/checks/go/rpc/main.go b/_code-samples/checks/go/rpc/main.go index 9ab1e3e8e7..fb9d51a372 100644 --- a/_code-samples/checks/go/rpc/main.go +++ b/_code-samples/checks/go/rpc/main.go @@ -1 +1,162 @@ -package rpc +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + cfg, err := rpc.NewClientConfig( + "https://s.altnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + client := rpc.NewClient(cfg) + + w, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + receiverWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Setting up wallets...") + if err := client.FundWallet(&w); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Sender wallet funded!") + + if err := client.FundWallet(&receiverWallet); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Receiver wallet funded!") + fmt.Println() + + fmt.Println("✅ Wallets setup complete!") + fmt.Println("💳 Sender wallet:", w.ClassicAddress) + fmt.Println("💳 Receiver wallet:", receiverWallet.ClassicAddress) + fmt.Println() + + fmt.Println("⏳ Creating check...") + cc := &transaction.CheckCreate{ + BaseTx: transaction.BaseTx{ + Account: w.GetAddress(), + }, + Destination: receiverWallet.GetAddress(), + SendMax: types.XRPCurrencyAmount(1000000), + InvoiceID: "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291", + } + + flatCc := cc.Flatten() + + if err := client.Autofill(&flatCc); err != nil { + fmt.Println(err) + return + } + + blob, _, err := w.Sign(flatCc) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + if !res.Validated { + fmt.Println("❌ Check creation failed!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Check created!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Println() + + meta, ok := res.Meta.(map[string]interface{}) + if !ok { + fmt.Println("❌ Meta is not of type TxObjMeta") + return + } + + var checkID string + + affectedNodes := meta["AffectedNodes"].([]interface{}) + + for _, node := range affectedNodes { + affectedNode, ok := node.(map[string]interface{}) + if !ok { + fmt.Println("❌ Node is not of type map[string]interface{}") + return + } + + createdNode, ok := affectedNode["CreatedNode"].(map[string]interface{}) + if !ok { + continue + } + + if createdNode["LedgerEntryType"] == string(ledger.CheckEntry) { + + checkID = createdNode["LedgerIndex"].(string) + } + } + + if checkID == "" { + fmt.Println("Check not found") + return + } + + fmt.Println("⏳ Cashing out check...") + checkCash := &transaction.CheckCash{ + BaseTx: transaction.BaseTx{ + Account: receiverWallet.GetAddress(), + }, + CheckID: types.Hash256(checkID), + Amount: types.XRPCurrencyAmount(1000000), + } + + flatCheckCash := checkCash.Flatten() + + if err := client.Autofill(&flatCheckCash); err != nil { + fmt.Println(err) + return + } + + blob, _, err = receiverWallet.Sign(flatCheckCash) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Check cashed out!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Println() +} diff --git a/_code-samples/checks/go/ws/main.go b/_code-samples/checks/go/ws/main.go index 98592950df..a3e38cd72b 100644 --- a/_code-samples/checks/go/ws/main.go +++ b/_code-samples/checks/go/ws/main.go @@ -1 +1,173 @@ -package ws +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" + "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" +) + +func main() { + fmt.Println("⏳ Connecting to testnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.altnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to testnet") + return + } + + fmt.Println("✅ Connected to testnet") + fmt.Println() + + w, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + receiverWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Setting up wallets...") + if err := client.FundWallet(&w); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Sender wallet funded!") + + if err := client.FundWallet(&receiverWallet); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Receiver wallet funded!") + fmt.Println() + + fmt.Println("✅ Wallets setup complete!") + fmt.Println("💳 Sender wallet:", w.ClassicAddress) + fmt.Println("💳 Receiver wallet:", receiverWallet.ClassicAddress) + fmt.Println() + + fmt.Println("⏳ Creating check...") + cc := &transaction.CheckCreate{ + BaseTx: transaction.BaseTx{ + Account: w.GetAddress(), + }, + Destination: receiverWallet.GetAddress(), + SendMax: types.XRPCurrencyAmount(1000000), + InvoiceID: "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291", + } + + flatCc := cc.Flatten() + + if err := client.Autofill(&flatCc); err != nil { + fmt.Println(err) + return + } + + blob, _, err := w.Sign(flatCc) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + if !res.Validated { + fmt.Println("❌ Check creation failed!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Check created!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Println() + + meta, ok := res.Meta.(map[string]interface{}) + if !ok { + fmt.Println("❌ Meta is not of type TxObjMeta") + return + } + + var checkID string + + affectedNodes := meta["AffectedNodes"].([]interface{}) + + for _, node := range affectedNodes { + affectedNode, ok := node.(map[string]interface{}) + if !ok { + fmt.Println("❌ Node is not of type map[string]interface{}") + return + } + + createdNode, ok := affectedNode["CreatedNode"].(map[string]interface{}) + if !ok { + continue + } + + if createdNode["LedgerEntryType"] == string(ledger.CheckEntry) { + + checkID = createdNode["LedgerIndex"].(string) + } + } + + if checkID == "" { + fmt.Println("Check not found") + return + } + + fmt.Println("⏳ Cashing out check...") + checkCash := &transaction.CheckCash{ + BaseTx: transaction.BaseTx{ + Account: receiverWallet.GetAddress(), + }, + CheckID: types.Hash256(checkID), + Amount: types.XRPCurrencyAmount(1000000), + } + + flatCheckCash := checkCash.Flatten() + + if err := client.Autofill(&flatCheckCash); err != nil { + fmt.Println(err) + return + } + + blob, _, err = receiverWallet.Sign(flatCheckCash) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Check cashed out!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Println() +} diff --git a/_code-samples/clawback/README.md b/_code-samples/clawback/README.md new file mode 100644 index 0000000000..3a6a54c8d0 --- /dev/null +++ b/_code-samples/clawback/README.md @@ -0,0 +1,3 @@ +# Clawback + +Create, configure, and execute a Clawback transaction to reclaim issued tokens from a trust line on the XRPL. diff --git a/_code-samples/clawback/go/go.mod b/_code-samples/clawback/go/go.mod index 63f569b0cd..fa9fde5d08 100644 --- a/_code-samples/clawback/go/go.mod +++ b/_code-samples/clawback/go/go.mod @@ -1,5 +1,24 @@ module github.com/XRPLF -go 1.23 +go 1.23.0 -require github.com/Peersyst/xrpl-go v0.1.11 \ No newline at end of file +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/clawback/go/go.sum b/_code-samples/clawback/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/clawback/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/clawback/go/rpc/main.go b/_code-samples/clawback/go/rpc/main.go index 9ab1e3e8e7..ead2e28eb6 100644 --- a/_code-samples/clawback/go/rpc/main.go +++ b/_code-samples/clawback/go/rpc/main.go @@ -1 +1,251 @@ -package rpc +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + transactions "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +const ( + currencyCode = "FOO" +) + +func main() { + // + // Configure client + // + cfg, err := rpc.NewClientConfig( + "https://s.altnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + client := rpc.NewClient(cfg) + + // + // Configure wallets + // + fmt.Println("⏳ Setting up wallets...") + coldWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating cold wallet: %s\n", err) + return + } + err = client.FundWallet(&coldWallet) + if err != nil { + fmt.Printf("❌ Error funding cold wallet: %s\n", err) + return + } + fmt.Println("💸 Cold wallet funded!") + + hotWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating hot wallet: %s\n", err) + return + } + err = client.FundWallet(&hotWallet) + if err != nil { + fmt.Printf("❌ Error funding hot wallet: %s\n", err) + return + } + fmt.Println("💸 Hot wallet funded!") + fmt.Println() + + fmt.Println("✅ Wallets setup complete!") + fmt.Println("💳 Cold wallet:", coldWallet.ClassicAddress) + fmt.Println("💳 Hot wallet:", hotWallet.ClassicAddress) + fmt.Println() + + // + // Configure cold address settings + // + fmt.Println("⏳ Configuring cold address settings...") + coldWalletAccountSet := &transactions.AccountSet{ + BaseTx: transactions.BaseTx{ + Account: types.Address(coldWallet.ClassicAddress), + }, + TickSize: types.TickSize(5), + TransferRate: types.TransferRate(0), + Domain: types.Domain("6578616D706C652E636F6D"), // example.com + } + + coldWalletAccountSet.SetAsfAllowTrustLineClawback() + coldWalletAccountSet.SetDisallowXRP() + + coldWalletAccountSet.SetRequireDestTag() + + flattenedTx := coldWalletAccountSet.Flatten() + + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err := coldWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err := client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Cold wallet unfreezing failed!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Cold address settings configured!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() + + // + // Create trust line from hot to cold address + // + fmt.Println("⏳ Creating trust line from hot to cold address...") + hotColdTrustSet := &transactions.TrustSet{ + BaseTx: transactions.BaseTx{ + Account: types.Address(hotWallet.ClassicAddress), + }, + LimitAmount: types.IssuedCurrencyAmount{ + Currency: currencyCode, + Issuer: types.Address(coldWallet.ClassicAddress), + Value: "100000000000000", + }, + } + + flattenedTx = hotColdTrustSet.Flatten() + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err = hotWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err = client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Trust line from hot to cold address creation failed!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Trust line from hot to cold address created!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() + + // + // Send tokens from cold wallet to hot wallet + // + fmt.Println("⏳ Sending tokens from cold wallet to hot wallet...") + coldToHotPayment := &transactions.Payment{ + BaseTx: transactions.BaseTx{ + Account: types.Address(coldWallet.ClassicAddress), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: currencyCode, + Issuer: types.Address(coldWallet.ClassicAddress), + Value: "3800", + }, + Destination: types.Address(hotWallet.ClassicAddress), + DestinationTag: types.DestinationTag(1), + } + + flattenedTx = coldToHotPayment.Flatten() + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err = coldWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err = client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Tokens not sent from cold wallet to hot wallet!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Tokens sent from cold wallet to hot wallet!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() + + // + // Claw back tokens from customer one + // + fmt.Println("⏳ Clawing back tokens from hot wallet...") + + coldWalletClawback := &transactions.Clawback{ + BaseTx: transactions.BaseTx{ + Account: types.Address(coldWallet.ClassicAddress), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: currencyCode, + Issuer: types.Address(hotWallet.ClassicAddress), + Value: "50", + }, + } + + flattenedTx = coldWalletClawback.Flatten() + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err = coldWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err = client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Tokens not clawed back from customer one!") + fmt.Println("Try again!") + return + } + + fmt.Println("✅ Tokens clawed back from customer one!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() +} diff --git a/_code-samples/clawback/go/ws/main.go b/_code-samples/clawback/go/ws/main.go index 98592950df..6a689ccde4 100644 --- a/_code-samples/clawback/go/ws/main.go +++ b/_code-samples/clawback/go/ws/main.go @@ -1 +1,258 @@ -package ws +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "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 = "FOO" +) + +func main() { + // + // Configure client + // + fmt.Println("⏳ Setting up client...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.altnet.rippletest.net"). + WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + fmt.Println("✅ Client configured!") + fmt.Println() + + fmt.Println("Connecting to server...") + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + fmt.Println("Connection: ", client.IsConnected()) + + // + // Configure wallets + // + fmt.Println("⏳ Setting up wallets...") + coldWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating cold wallet: %s\n", err) + return + } + err = client.FundWallet(&coldWallet) + if err != nil { + fmt.Printf("❌ Error funding cold wallet: %s\n", err) + return + } + fmt.Println("💸 Cold wallet funded!") + + hotWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating hot wallet: %s\n", err) + return + } + err = client.FundWallet(&hotWallet) + if err != nil { + fmt.Printf("❌ Error funding hot wallet: %s\n", err) + return + } + fmt.Println("💸 Hot wallet funded!") + fmt.Println() + + fmt.Println("✅ Wallets setup complete!") + fmt.Println("💳 Cold wallet:", coldWallet.ClassicAddress) + fmt.Println("💳 Hot wallet:", hotWallet.ClassicAddress) + fmt.Println() + + // + // Configure cold address settings + // + fmt.Println("⏳ Configuring cold address settings...") + coldWalletAccountSet := &transactions.AccountSet{ + BaseTx: transactions.BaseTx{ + Account: types.Address(coldWallet.ClassicAddress), + }, + TickSize: types.TickSize(5), + TransferRate: types.TransferRate(0), + Domain: types.Domain("6578616D706C652E636F6D"), // example.com + } + + coldWalletAccountSet.SetAsfAllowTrustLineClawback() + coldWalletAccountSet.SetDisallowXRP() + + coldWalletAccountSet.SetRequireDestTag() + + flattenedTx := coldWalletAccountSet.Flatten() + + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err := coldWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err := client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Cold wallet unfreezing failed!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Cold address settings configured!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() + + // + // Create trust line from hot to cold address + // + fmt.Println("⏳ Creating trust line from hot to cold address...") + hotColdTrustSet := &transactions.TrustSet{ + BaseTx: transactions.BaseTx{ + Account: types.Address(hotWallet.ClassicAddress), + }, + LimitAmount: types.IssuedCurrencyAmount{ + Currency: currencyCode, + Issuer: types.Address(coldWallet.ClassicAddress), + Value: "100000000000000", + }, + } + + flattenedTx = hotColdTrustSet.Flatten() + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err = hotWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err = client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Trust line from hot to cold address creation failed!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Trust line from hot to cold address created!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() + + // + // Send tokens from cold wallet to hot wallet + // + fmt.Println("⏳ Sending tokens from cold wallet to hot wallet...") + coldToHotPayment := &transactions.Payment{ + BaseTx: transactions.BaseTx{ + Account: types.Address(coldWallet.ClassicAddress), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: currencyCode, + Issuer: types.Address(coldWallet.ClassicAddress), + Value: "3800", + }, + Destination: types.Address(hotWallet.ClassicAddress), + DestinationTag: types.DestinationTag(1), + } + + flattenedTx = coldToHotPayment.Flatten() + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err = coldWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err = client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Tokens not sent from cold wallet to hot wallet!") + fmt.Println("Try again!") + fmt.Println() + return + } + + fmt.Println("✅ Tokens sent from cold wallet to hot wallet!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() + + // + // Claw back tokens from customer one + // + fmt.Println("⏳ Clawing back tokens from hot wallet...") + + coldWalletClawback := &transactions.Clawback{ + BaseTx: transactions.BaseTx{ + Account: types.Address(coldWallet.ClassicAddress), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: currencyCode, + Issuer: types.Address(hotWallet.ClassicAddress), + Value: "50", + }, + } + + flattenedTx = coldWalletClawback.Flatten() + err = client.Autofill(&flattenedTx) + if err != nil { + fmt.Printf("❌ Error autofilling transaction: %s\n", err) + return + } + + txBlob, _, err = coldWallet.Sign(flattenedTx) + if err != nil { + fmt.Printf("❌ Error signing transaction: %s\n", err) + return + } + + response, err = client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Printf("❌ Error submitting transaction: %s\n", err) + return + } + + if !response.Validated { + fmt.Println("❌ Tokens not clawed back from customer one!") + fmt.Println("Try again!") + return + } + + fmt.Println("✅ Tokens clawed back from customer one!") + fmt.Printf("🌐 Hash: %s\n", response.Hash.String()) + fmt.Println() +} diff --git a/_code-samples/credential/README.md b/_code-samples/credential/README.md new file mode 100644 index 0000000000..751fa22c5f --- /dev/null +++ b/_code-samples/credential/README.md @@ -0,0 +1,3 @@ +# Credential + +Create, accept, and delete a credential on the XRPL using dedicated transactions between issuer and subject wallets. diff --git a/_code-samples/credential/go/go.mod b/_code-samples/credential/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/credential/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/credential/go/go.sum b/_code-samples/credential/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/credential/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/credential/go/rpc/main.go b/_code-samples/credential/go/rpc/main.go new file mode 100644 index 0000000000..ab3bf1a1d0 --- /dev/null +++ b/_code-samples/credential/go/rpc/main.go @@ -0,0 +1,109 @@ +package main + +import ( + "encoding/hex" + "fmt" + "time" + + "github.com/Peersyst/xrpl-go/examples/clients" + "github.com/Peersyst/xrpl-go/pkg/crypto" + rippleTime "github.com/Peersyst/xrpl-go/xrpl/time" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + // As of February 2025, Credential is only available on Devnet. + client := clients.GetDevnetRpcClient() + + // Configure wallets + + // Issuer + fmt.Println("⏳ Setting up credential 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) + + // ----------------------------------------------------- + + // Subject (destination) + fmt.Println("⏳ Setting up Subject wallet...") + subjectWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating subject wallet: %s\n", err) + return + } + + err = client.FundWallet(&subjectWallet) + if err != nil { + fmt.Printf("❌ Error funding subject wallet: %s\n", err) + return + } + fmt.Printf("✅ Subject wallet funded: %s\n", subjectWallet.ClassicAddress) + + // ----------------------------------------------------- + + // Creating the CredentialCreate transaction + fmt.Println("⏳ Creating CredentialCreate transaction...") + + expiration, err := rippleTime.IsoTimeToRippleTime(time.Now().Add(time.Hour * 24).Format(time.RFC3339)) + credentialType := types.CredentialType("6D795F63726564656E7469616C") + + if err != nil { + fmt.Printf("❌ Error converting expiration to ripple time: %s\n", err) + return + } + + txn := &transaction.CredentialCreate{ + BaseTx: transaction.BaseTx{ + Account: types.Address(issuer.ClassicAddress), + }, + CredentialType: credentialType, + Subject: types.Address(subjectWallet.ClassicAddress), + Expiration: uint32(expiration), + URI: hex.EncodeToString([]byte("https://example.com")), + } + + clients.SubmitTxBlobAndWait(client, txn, issuer) + + // ----------------------------------------------------- + + // Creating the CredentialAccept transaction + fmt.Println("⏳ Creating CredentialAccept transaction...") + + acceptTxn := &transaction.CredentialAccept{ + BaseTx: transaction.BaseTx{ + Account: types.Address(subjectWallet.ClassicAddress), + }, + CredentialType: credentialType, + Issuer: types.Address(issuer.ClassicAddress), + } + + clients.SubmitTxBlobAndWait(client, acceptTxn, subjectWallet) + + // ----------------------------------------------------- + + // Creating the CredentialDelete transaction + fmt.Println("⏳ Creating CredentialDelete transaction...") + + deleteTxn := &transaction.CredentialDelete{ + BaseTx: transaction.BaseTx{ + Account: types.Address(issuer.ClassicAddress), + }, + CredentialType: credentialType, + Issuer: types.Address(issuer.ClassicAddress), + Subject: types.Address(subjectWallet.ClassicAddress), + } + + clients.SubmitTxBlobAndWait(client, deleteTxn, issuer) +} diff --git a/_code-samples/credential/go/ws/main.go b/_code-samples/credential/go/ws/main.go new file mode 100644 index 0000000000..3fd7eabce9 --- /dev/null +++ b/_code-samples/credential/go/ws/main.go @@ -0,0 +1,122 @@ +package main + +import ( + "encoding/hex" + "fmt" + "time" + + "github.com/Peersyst/xrpl-go/examples/clients" + "github.com/Peersyst/xrpl-go/pkg/crypto" + rippleTime "github.com/Peersyst/xrpl-go/xrpl/time" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + + fmt.Println("⏳ Setting up client...") + + client := clients.GetDevnetWebsocketClient() + 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 credential 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) + + // ----------------------------------------------------- + + // Subject (destination) + fmt.Println("⏳ Setting up Subject wallet...") + subjectWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating subject wallet: %s\n", err) + return + } + + err = client.FundWallet(&subjectWallet) + if err != nil { + fmt.Printf("❌ Error funding subject wallet: %s\n", err) + return + } + fmt.Printf("✅ Subject wallet funded: %s\n", subjectWallet.ClassicAddress) + + // ----------------------------------------------------- + + // Creating the CredentialCreate transaction + fmt.Println("⏳ Creating CredentialCreate transaction...") + + expiration, err := rippleTime.IsoTimeToRippleTime(time.Now().Add(time.Hour * 24).Format(time.RFC3339)) + credentialType := types.CredentialType("6D795F63726564656E7469616C") + + if err != nil { + fmt.Printf("❌ Error converting expiration to ripple time: %s\n", err) + return + } + + txn := &transaction.CredentialCreate{ + BaseTx: transaction.BaseTx{ + Account: types.Address(issuer.ClassicAddress), + }, + CredentialType: credentialType, + Subject: types.Address(subjectWallet.ClassicAddress), + Expiration: uint32(expiration), + URI: hex.EncodeToString([]byte("https://example.com")), + } + + clients.SubmitTxBlobAndWait(client, txn, issuer) + + // ----------------------------------------------------- + + // Creating the CredentialAccept transaction + fmt.Println("⏳ Creating CredentialAccept transaction...") + + acceptTxn := &transaction.CredentialAccept{ + BaseTx: transaction.BaseTx{ + Account: types.Address(subjectWallet.ClassicAddress), + }, + CredentialType: credentialType, + Issuer: types.Address(issuer.ClassicAddress), + } + + clients.SubmitTxBlobAndWait(client, acceptTxn, subjectWallet) + + // ----------------------------------------------------- + + // Creating the CredentialDelete transaction + fmt.Println("⏳ Creating CredentialDelete transaction...") + + deleteTxn := &transaction.CredentialDelete{ + BaseTx: transaction.BaseTx{ + Account: types.Address(issuer.ClassicAddress), + }, + CredentialType: credentialType, + Issuer: types.Address(issuer.ClassicAddress), + Subject: types.Address(subjectWallet.ClassicAddress), + } + + clients.SubmitTxBlobAndWait(client, deleteTxn, issuer) +} diff --git a/_code-samples/delegate-set/README.md b/_code-samples/delegate-set/README.md new file mode 100644 index 0000000000..2d8736f4e4 --- /dev/null +++ b/_code-samples/delegate-set/README.md @@ -0,0 +1,3 @@ +# Delegate + +Example delegating payment permission to an account and executing on behalf the delegator. diff --git a/_code-samples/delegate-set/go/go.mod b/_code-samples/delegate-set/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/delegate-set/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/delegate-set/go/go.sum b/_code-samples/delegate-set/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/delegate-set/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/delegate-set/go/rpc/main.go b/_code-samples/delegate-set/go/rpc/main.go new file mode 100644 index 0000000000..4bc070f0bc --- /dev/null +++ b/_code-samples/delegate-set/go/rpc/main.go @@ -0,0 +1,131 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/rpc/types" + transactions "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + // Configure the client + cfg, err := rpc.NewClientConfig( + "https://s.devnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + client := rpc.NewClient(cfg) + + // Create and fund wallets + delegatorWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + delegateeWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + if err := client.FundWallet(&delegatorWallet); err != nil { + fmt.Println(err) + return + } + if err := client.FundWallet(&delegateeWallet); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Wallets funded") + + // Check initial balances + delegatorBalance, err := client.GetXrpBalance(delegatorWallet.ClassicAddress) + if err != nil { + delegatorBalance = "0" + } + delegateeBalance, err := client.GetXrpBalance(delegateeWallet.ClassicAddress) + if err != nil { + delegateeBalance = "0" + } + + fmt.Printf("💳 Delegator initial balance: %s XRP\n", delegatorBalance) + fmt.Printf("💳 Delegatee initial balance: %s XRP\n", delegateeBalance) + fmt.Println() + + // Create DelegateSet transaction + delegateSetTx := &transactions.DelegateSet{ + BaseTx: transactions.BaseTx{ + Account: txnTypes.Address(delegatorWallet.ClassicAddress), + }, + Authorize: txnTypes.Address(delegateeWallet.ClassicAddress), + Permissions: []txnTypes.Permission{ + { + Permission: txnTypes.PermissionValue{ + PermissionValue: "Payment", + }, + }, + }, + } + + // Submit DelegateSet transaction + response, err := client.SubmitTxAndWait(delegateSetTx.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &delegatorWallet, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ DelegateSet transaction submitted") + fmt.Printf("🌐 Hash: %s\n", response.Hash) + fmt.Printf("🌐 Validated: %t\n", response.Validated) + fmt.Println() + + // Create delegated payment transaction + delegatedPaymentTx := &transactions.Payment{ + BaseTx: transactions.BaseTx{ + Account: txnTypes.Address(delegatorWallet.ClassicAddress), + Delegate: txnTypes.Address(delegateeWallet.ClassicAddress), + }, + Destination: txnTypes.Address(delegateeWallet.ClassicAddress), + Amount: txnTypes.XRPCurrencyAmount(1000000), // 1 XRP + } + + // Submit delegated payment + response2, err := client.SubmitTxAndWait(delegatedPaymentTx.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &delegateeWallet, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Delegated payment submitted") + fmt.Printf("🌐 Hash: %s\n", response2.Hash) + fmt.Printf("🌐 Validated: %t\n", response2.Validated) + fmt.Println() + + // Check final balances + finalDelegatorBalance, err := client.GetXrpBalance(delegatorWallet.ClassicAddress) + if err != nil { + finalDelegatorBalance = "0" + } + finalDelegateeBalance, err := client.GetXrpBalance(delegateeWallet.ClassicAddress) + if err != nil { + finalDelegateeBalance = "0" + } + + fmt.Printf("💳 Delegator final balance: %s XRP\n", finalDelegatorBalance) + fmt.Printf("💳 Delegatee final balance: %s XRP\n", finalDelegateeBalance) +} diff --git a/_code-samples/delegate-set/go/ws/main.go b/_code-samples/delegate-set/go/ws/main.go new file mode 100644 index 0000000000..7aac89cc56 --- /dev/null +++ b/_code-samples/delegate-set/go/ws/main.go @@ -0,0 +1,151 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "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" +) + +func main() { + // Connect to testnet + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.devnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + // Create and fund wallets + delegatorWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + delegateeWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + if err := client.FundWallet(&delegatorWallet); err != nil { + fmt.Println(err) + return + } + if err := client.FundWallet(&delegateeWallet); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Wallets funded") + + // Check initial balances + delegatorBalance, err := client.GetXrpBalance(delegatorWallet.ClassicAddress) + if err != nil { + delegatorBalance = "0" + } + delegateeBalance, err := client.GetXrpBalance(delegateeWallet.ClassicAddress) + if err != nil { + delegateeBalance = "0" + } + + fmt.Printf("💳 Delegator initial balance: %s XRP\n", delegatorBalance) + fmt.Printf("💳 Delegatee initial balance: %s XRP\n", delegateeBalance) + fmt.Println() + + // Create DelegateSet transaction + delegateSetTx := &transactions.DelegateSet{ + BaseTx: transactions.BaseTx{ + Account: types.Address(delegatorWallet.ClassicAddress), + }, + Authorize: types.Address(delegateeWallet.ClassicAddress), + Permissions: []types.Permission{ + { + Permission: types.PermissionValue{ + PermissionValue: "Payment", + }, + }, + }, + } + + // Submit DelegateSet transaction + flattenedTx := delegateSetTx.Flatten() + if err := client.Autofill(&flattenedTx); err != nil { + fmt.Println(err) + return + } + + txBlob, _, err := delegatorWallet.Sign(flattenedTx) + if err != nil { + fmt.Println(err) + return + } + + response, err := client.SubmitTxBlobAndWait(txBlob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ DelegateSet transaction submitted") + fmt.Printf("🌐 Hash: %s\n", response.Hash) + fmt.Printf("🌐 Validated: %t\n", response.Validated) + fmt.Println() + + // Create delegated payment transaction + delegatedPaymentTx := &transactions.Payment{ + BaseTx: transactions.BaseTx{ + Account: types.Address(delegatorWallet.ClassicAddress), + Delegate: types.Address(delegateeWallet.ClassicAddress), + }, + Destination: types.Address(delegateeWallet.ClassicAddress), + Amount: types.XRPCurrencyAmount(1000000), // 1 XRP + } + + // Submit delegated payment + flatDelegatedPayment := delegatedPaymentTx.Flatten() + if err := client.Autofill(&flatDelegatedPayment); err != nil { + fmt.Println(err) + return + } + + txBlob2, _, err := delegateeWallet.Sign(flatDelegatedPayment) + if err != nil { + fmt.Println(err) + return + } + + response2, err := client.SubmitTxBlobAndWait(txBlob2, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Delegated payment submitted") + fmt.Printf("🌐 Hash: %s\n", response2.Hash) + fmt.Printf("🌐 Validated: %t\n", response2.Validated) + fmt.Println() + + // Check final balances + finalDelegatorBalance, err := client.GetXrpBalance(delegatorWallet.ClassicAddress) + if err != nil { + finalDelegatorBalance = "0" + } + finalDelegateeBalance, err := client.GetXrpBalance(delegateeWallet.ClassicAddress) + if err != nil { + finalDelegateeBalance = "0" + } + + fmt.Printf("💳 Delegator final balance: %s XRP\n", finalDelegatorBalance) + fmt.Printf("💳 Delegatee final balance: %s XRP\n", finalDelegateeBalance) +} diff --git a/_code-samples/deposit-preauth/README.md b/_code-samples/deposit-preauth/README.md new file mode 100644 index 0000000000..16b546d7eb --- /dev/null +++ b/_code-samples/deposit-preauth/README.md @@ -0,0 +1,3 @@ +# DepositPreauth + +Example of DepositPreauth transaction demonstrating how deposit permissions can be managed. diff --git a/_code-samples/deposit-preauth/go/go.mod b/_code-samples/deposit-preauth/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/deposit-preauth/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/deposit-preauth/go/go.sum b/_code-samples/deposit-preauth/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/deposit-preauth/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/deposit-preauth/go/rpc/main.go b/_code-samples/deposit-preauth/go/rpc/main.go new file mode 100644 index 0000000000..1280390928 --- /dev/null +++ b/_code-samples/deposit-preauth/go/rpc/main.go @@ -0,0 +1,220 @@ +package main + +import ( + "encoding/hex" + "fmt" + "time" + + "github.com/Peersyst/xrpl-go/examples/clients" + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/queries/account" + "github.com/Peersyst/xrpl-go/xrpl/queries/common" + rippletime "github.com/Peersyst/xrpl-go/xrpl/time" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + client := clients.GetDevnetRpcClient() + + // Configure wallets + + // Issuer + fmt.Println("⏳ Setting up credential issuer wallet...") + issuer, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating credential issuer wallet: %s\n", err) + return + } + + err = client.FundWallet(&issuer) + if err != nil { + fmt.Printf("❌ Error funding credential issuer wallet: %s\n", err) + return + } + fmt.Printf("✅ Credential 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 1 wallet: %s\n", err) + return + } + + err = client.FundWallet(&holderWallet1) + if err != nil { + fmt.Printf("❌ Error funding holder 1 wallet: %s\n", err) + return + } + fmt.Printf("✅ Holder 1 wallet funded: %s\n", holderWallet1.ClassicAddress) + + // ----------------------------------------------------- + + // Enabling DepositAuth on the issuer account with an AccountSet transaction + fmt.Println("⏳ Enabling DepositAuth on the issuer account...") + accountSetTx := &transaction.AccountSet{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.AccountSetTx, + }, + } + accountSetTx.SetAsfDepositAuth() + + clients.SubmitTxBlobAndWait(client, accountSetTx, issuer) + + // ----------------------------------------------------- + + // Creating the CredentialCreate transaction + fmt.Println("⏳ Creating the CredentialCreate transaction...") + + expiration, err := rippletime.IsoTimeToRippleTime(time.Now().Add(time.Hour * 24).Format(time.RFC3339)) + if err != nil { + fmt.Printf("❌ Error converting expiration to ripple time: %s\n", err) + return + } + credentialType := types.CredentialType("6D795F63726564656E7469616C") // my_credential + + credentialCreateTx := &transaction.CredentialCreate{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.CredentialCreateTx, + }, + Expiration: uint32(expiration), + CredentialType: credentialType, + Subject: types.Address(holderWallet1.ClassicAddress), + URI: hex.EncodeToString([]byte("https://example.com")), + } + + clients.SubmitTxBlobAndWait(client, credentialCreateTx, issuer) + + // ----------------------------------------------------- + + // Creating the CredentialAccept transaction + fmt.Println("⏳ Creating the CredentialAccept transaction...") + + credentialAcceptTx := &transaction.CredentialAccept{ + BaseTx: transaction.BaseTx{ + Account: holderWallet1.ClassicAddress, + TransactionType: transaction.CredentialAcceptTx, + }, + CredentialType: credentialType, + Issuer: types.Address(issuer.ClassicAddress), + } + + clients.SubmitTxBlobAndWait(client, credentialAcceptTx, holderWallet1) + + // ----------------------------------------------------- + + // Creating the DepositPreauth transaction + fmt.Println("⏳ Creating the DepositPreauth transaction using AuthorizeCredentials...") + + depositPreauthTx := &transaction.DepositPreauth{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.DepositPreauthTx, + }, + AuthorizeCredentials: []types.AuthorizeCredentialsWrapper{ + { + Credential: types.AuthorizeCredentials{ + Issuer: issuer.ClassicAddress, + CredentialType: credentialType, + }, + }, + }, + } + + clients.SubmitTxBlobAndWait(client, depositPreauthTx, issuer) + + // ----------------------------------------------------- + + // Get the credential ID + fmt.Println("⏳ Getting the credential ID from the holder 1 account...") + + objectsRequest := &account.ObjectsRequest{ + Account: holderWallet1.ClassicAddress, + Type: account.CredentialObject, + LedgerIndex: common.Validated, + } + + objectsResponse, err := client.GetAccountObjects(objectsRequest) + if err != nil { + fmt.Printf("❌ Error getting the credential ID: %s\n", err) + return + } + + // Check if we have any credential objects + if len(objectsResponse.AccountObjects) == 0 { + fmt.Println("❌ No credential objects found") + return + } + + // Extract the credential ID + credentialID, ok := objectsResponse.AccountObjects[0]["index"].(string) + if !ok { + fmt.Println("❌ Could not extract credential ID from response") + return + } + + fmt.Printf("✅ Credential ID: %s\n", credentialID) + fmt.Println() + + // ----------------------------------------------------- + + // Sending XRP to the holder 1 account + fmt.Println("⏳ Sending XRP to the issuer account, should succeed...") + + sendTx := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: holderWallet1.ClassicAddress, + TransactionType: transaction.PaymentTx, + }, + Amount: types.XRPCurrencyAmount(1000000), + Destination: issuer.ClassicAddress, + CredentialIDs: types.CredentialIDs{credentialID}, + } + + clients.SubmitTxBlobAndWait(client, sendTx, holderWallet1) + + // ----------------------------------------------------- + + // Unauthorizing the holder 1 account + fmt.Println("⏳ Unauthorizing the holder 1 account with the DepositPreauth transaction and the UnauthorizeCredentials field...") + + unauthorizeTx := &transaction.DepositPreauth{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.DepositPreauthTx, + }, + UnauthorizeCredentials: []types.AuthorizeCredentialsWrapper{ + { + Credential: types.AuthorizeCredentials{ + Issuer: issuer.ClassicAddress, + CredentialType: credentialType, + }, + }, + }, + } + + clients.SubmitTxBlobAndWait(client, unauthorizeTx, issuer) + + // ----------------------------------------------------- + + // Sending XRP to the holder 1 account again (which should fail) + fmt.Println("⏳ Sending XRP to the issuer account again (which should fail)...") + + sendTx2 := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: holderWallet1.ClassicAddress, + TransactionType: transaction.PaymentTx, + }, + Amount: types.XRPCurrencyAmount(1000000), + Destination: issuer.ClassicAddress, + CredentialIDs: types.CredentialIDs{credentialID}, + } + + clients.SubmitTxBlobAndWait(client, sendTx2, holderWallet1) +} diff --git a/_code-samples/deposit-preauth/go/ws/main.go b/_code-samples/deposit-preauth/go/ws/main.go new file mode 100644 index 0000000000..2d0a304ec3 --- /dev/null +++ b/_code-samples/deposit-preauth/go/ws/main.go @@ -0,0 +1,234 @@ +package main + +import ( + "encoding/hex" + "fmt" + "time" + + "github.com/Peersyst/xrpl-go/examples/clients" + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/queries/account" + "github.com/Peersyst/xrpl-go/xrpl/queries/common" + rippletime "github.com/Peersyst/xrpl-go/xrpl/time" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + + fmt.Println("⏳ Setting up client...") + + client := clients.GetDevnetWebsocketClient() + 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 credential issuer wallet...") + issuer, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Printf("❌ Error creating credential issuer wallet: %s\n", err) + return + } + + err = client.FundWallet(&issuer) + if err != nil { + fmt.Printf("❌ Error funding credential issuer wallet: %s\n", err) + return + } + fmt.Printf("✅ Credential 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 1 wallet: %s\n", err) + return + } + + err = client.FundWallet(&holderWallet1) + if err != nil { + fmt.Printf("❌ Error funding holder 1 wallet: %s\n", err) + return + } + fmt.Printf("✅ Holder 1 wallet funded: %s\n", holderWallet1.ClassicAddress) + + // ----------------------------------------------------- + + // Enabling DepositAuth on the issuer account with an AccountSet transaction + fmt.Println("⏳ Enabling DepositAuth on the issuer account...") + accountSetTx := &transaction.AccountSet{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.AccountSetTx, + }, + } + accountSetTx.SetAsfDepositAuth() + + clients.SubmitTxBlobAndWait(client, accountSetTx, issuer) + + // ----------------------------------------------------- + + // Creating the CredentialCreate transaction + fmt.Println("⏳ Creating the CredentialCreate transaction...") + + expiration, err := rippletime.IsoTimeToRippleTime(time.Now().Add(time.Hour * 24).Format(time.RFC3339)) + if err != nil { + fmt.Printf("❌ Error converting expiration to ripple time: %s\n", err) + return + } + credentialType := types.CredentialType("6D795F63726564656E7469616C") // my_credential + + credentialCreateTx := &transaction.CredentialCreate{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.CredentialCreateTx, + }, + Expiration: uint32(expiration), + CredentialType: credentialType, + Subject: types.Address(holderWallet1.ClassicAddress), + URI: hex.EncodeToString([]byte("https://example.com")), + } + + clients.SubmitTxBlobAndWait(client, credentialCreateTx, issuer) + + // ----------------------------------------------------- + + // Creating the CredentialAccept transaction + fmt.Println("⏳ Creating the CredentialAccept transaction...") + + credentialAcceptTx := &transaction.CredentialAccept{ + BaseTx: transaction.BaseTx{ + Account: holderWallet1.ClassicAddress, + TransactionType: transaction.CredentialAcceptTx, + }, + CredentialType: credentialType, + Issuer: types.Address(issuer.ClassicAddress), + } + + clients.SubmitTxBlobAndWait(client, credentialAcceptTx, holderWallet1) + + // ----------------------------------------------------- + + // Creating the DepositPreauth transaction + fmt.Println("⏳ Creating the DepositPreauth transaction using AuthorizeCredentials...") + + depositPreauthTx := &transaction.DepositPreauth{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.DepositPreauthTx, + }, + AuthorizeCredentials: []types.AuthorizeCredentialsWrapper{ + { + Credential: types.AuthorizeCredentials{ + Issuer: issuer.ClassicAddress, + CredentialType: credentialType, + }, + }, + }, + } + + clients.SubmitTxBlobAndWait(client, depositPreauthTx, issuer) + + // ----------------------------------------------------- + + // Get the credential ID + fmt.Println("⏳ Getting the credential ID from the holder 1 account...") + + objectsRequest := &account.ObjectsRequest{ + Account: holderWallet1.ClassicAddress, + Type: account.CredentialObject, + LedgerIndex: common.Validated, + } + + objectsResponse, err := client.GetAccountObjects(objectsRequest) + if err != nil { + fmt.Printf("❌ Error getting the credential ID: %s\n", err) + return + } + + // Check if we have any credential objects + if len(objectsResponse.AccountObjects) == 0 { + fmt.Println("❌ No credential objects found") + return + } + + // Extract the credential ID + credentialID, ok := objectsResponse.AccountObjects[0]["index"].(string) + if !ok { + fmt.Println("❌ Could not extract credential ID from response") + return + } + + fmt.Printf("✅ Credential ID: %s\n", credentialID) + fmt.Println() + + // ----------------------------------------------------- + + // Sending XRP to the holder 1 account + fmt.Println("⏳ Sending XRP to the issuer account, should succeed...") + + sendTx := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: holderWallet1.ClassicAddress, + TransactionType: transaction.PaymentTx, + }, + Amount: types.XRPCurrencyAmount(1000000), + Destination: issuer.ClassicAddress, + CredentialIDs: types.CredentialIDs{credentialID}, + } + + clients.SubmitTxBlobAndWait(client, sendTx, holderWallet1) + + // ----------------------------------------------------- + + // Unauthorize the holder 1 account + fmt.Println("⏳ Unauthorize the holder 1 account with the DepositPreauth transaction and the UnauthorizeCredentials field...") + + unauthorizeTx := &transaction.DepositPreauth{ + BaseTx: transaction.BaseTx{ + Account: issuer.ClassicAddress, + TransactionType: transaction.DepositPreauthTx, + }, + UnauthorizeCredentials: []types.AuthorizeCredentialsWrapper{ + { + Credential: types.AuthorizeCredentials{ + Issuer: issuer.ClassicAddress, + CredentialType: credentialType, + }, + }, + }, + } + + clients.SubmitTxBlobAndWait(client, unauthorizeTx, issuer) + + // ----------------------------------------------------- + + // Sending XRP to the holder 1 account again (which should fail) + fmt.Println("⏳ Sending XRP to the issuer account again (which should fail)...") + + sendTx2 := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: holderWallet1.ClassicAddress, + TransactionType: transaction.PaymentTx, + }, + Amount: types.XRPCurrencyAmount(1000000), + Destination: issuer.ClassicAddress, + CredentialIDs: types.CredentialIDs{credentialID}, + } + + clients.SubmitTxBlobAndWait(client, sendTx2, holderWallet1) +} diff --git a/_code-samples/freeze/go/go.mod b/_code-samples/freeze/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/freeze/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/freeze/go/go.sum b/_code-samples/freeze/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/freeze/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/freeze/go/rpc/main.go b/_code-samples/freeze/go/rpc/main.go new file mode 100644 index 0000000000..e5a874cd75 --- /dev/null +++ b/_code-samples/freeze/go/rpc/main.go @@ -0,0 +1,347 @@ +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" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + transactions "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +const ( + currencyCode = "USDA" +) + +type SubmittableTransaction interface { + TxType() transactions.TxType + Flatten() transactions.FlatTransaction // Ensures all transactions can be flattened +} + +func main() { + client := getRpcClient() + + // 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 getRpcClient() *rpc.Client { + cfg, err := rpc.NewClientConfig( + // DeepFreeze only available on Devnet as of February 2025, change to testnet/mainnet once the amendment passes. + "https://s.devnet.rippletest.net:51234", + rpc.WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + return rpc.NewClient(cfg) +} + +// submitAndWait submits a transaction and waits for it to be included in a validated ledger +func submitAndWait(client *rpc.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() +} diff --git a/_code-samples/freeze/go/ws/main.go b/_code-samples/freeze/go/ws/main.go new file mode 100644 index 0000000000..47e2323178 --- /dev/null +++ b/_code-samples/freeze/go/ws/main.go @@ -0,0 +1,357 @@ +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() +} diff --git a/_code-samples/multisigning/go/go.mod b/_code-samples/multisigning/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/multisigning/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/multisigning/go/go.sum b/_code-samples/multisigning/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/multisigning/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/multisigning/go/rpc/main.go b/_code-samples/multisigning/go/rpc/main.go new file mode 100644 index 0000000000..447c8f8cf1 --- /dev/null +++ b/_code-samples/multisigning/go/rpc/main.go @@ -0,0 +1,166 @@ +package main + +import ( + "encoding/hex" + "fmt" + "maps" + "strings" + + "github.com/Peersyst/xrpl-go/xrpl" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + cfg, err := rpc.NewClientConfig( + "https://s.altnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + client := rpc.NewClient(cfg) + + w1, err := wallet.FromSeed("sEdTtvLmJmrb7GaivhWoXRkvU4NDjVf", "") + if err != nil { + fmt.Println(err) + return + } + + w2, err := wallet.FromSeed("sEdSFiKMQp7RvYLgH7t7FEpwNRWv2Gr", "") + if err != nil { + fmt.Println(err) + return + } + + master, err := wallet.FromSeed("sEdTMm2yv8c8Rg8YHFHQA9TxVMFy1ze", "") + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + + if err := client.FundWallet(&w1); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Wallet 1 funded") + + if err := client.FundWallet(&w2); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 2 funded") + + if err := client.FundWallet(&master); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Master wallet funded") + fmt.Println() + fmt.Println("⏳ Setting up signer list...") + + ss := &transaction.SignerListSet{ + BaseTx: transaction.BaseTx{ + Account: master.GetAddress(), + }, + SignerQuorum: uint32(2), + SignerEntries: []ledger.SignerEntryWrapper{ + { + SignerEntry: ledger.SignerEntry{ + Account: w1.GetAddress(), + SignerWeight: 1, + }, + }, + { + SignerEntry: ledger.SignerEntry{ + Account: w2.GetAddress(), + SignerWeight: 1, + }, + }, + { + SignerEntry: ledger.SignerEntry{ + Account: "XVYRdEocC28DRx94ZFGP3qNJ1D5Ln7ecXFMd3vREB5Pesju", + SignerWeight: 1, + }, + }, + }, + } + + flatSs := ss.Flatten() + + if err := client.Autofill(&flatSs); err != nil { + fmt.Println(err) + return + } + + blob, _, err := master.Sign(flatSs) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ SignerListSet transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Println() + + fmt.Println("⏳ Setting up AccountSet multisign transaction...") + + as := &transaction.AccountSet{ + BaseTx: transaction.BaseTx{ + Account: master.GetAddress(), + }, + Domain: types.Domain(strings.ToUpper(hex.EncodeToString([]byte("example.com")))), + } + + flatAs := as.Flatten() + + if err := client.AutofillMultisigned(&flatAs, 2); err != nil { + fmt.Println(err) + return + } + + w1As := maps.Clone(flatAs) + + blob1, _, err := w1.Multisign(w1As) + if err != nil { + fmt.Println(err) + return + } + + w2As := maps.Clone(flatAs) + + blob2, _, err := w2.Multisign(w2As) + if err != nil { + fmt.Println(err) + return + } + + blob, err = xrpl.Multisign(blob1, blob2) + if err != nil { + fmt.Println(err) + return + } + + mRes, err := client.SubmitMultisigned(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Multisigned transaction submitted!") + fmt.Printf("🌐 Result: %s\n", mRes.EngineResult) +} diff --git a/_code-samples/multisigning/go/ws/main.go b/_code-samples/multisigning/go/ws/main.go new file mode 100644 index 0000000000..88abba06a3 --- /dev/null +++ b/_code-samples/multisigning/go/ws/main.go @@ -0,0 +1,181 @@ +package main + +import ( + "encoding/hex" + "fmt" + "maps" + "strings" + + "github.com/Peersyst/xrpl-go/xrpl" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" + "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" +) + +func main() { + fmt.Println("⏳ Connecting to testnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.altnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to testnet") + return + } + + fmt.Println("✅ Connected to testnet") + fmt.Println() + + w1, err := wallet.FromSeed("sEdTtvLmJmrb7GaivhWoXRkvU4NDjVf", "") + if err != nil { + fmt.Println(err) + return + } + + w2, err := wallet.FromSeed("sEdSFiKMQp7RvYLgH7t7FEpwNRWv2Gr", "") + if err != nil { + fmt.Println(err) + return + } + + master, err := wallet.FromSeed("sEdTMm2yv8c8Rg8YHFHQA9TxVMFy1ze", "") + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + + if err := client.FundWallet(&w1); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Wallet 1 funded") + + if err := client.FundWallet(&w2); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 2 funded") + + if err := client.FundWallet(&master); err != nil { + fmt.Println(err) + return + } + fmt.Println("💸 Master wallet funded") + fmt.Println() + fmt.Println("⏳ Setting up signer list...") + + ss := &transaction.SignerListSet{ + BaseTx: transaction.BaseTx{ + Account: master.GetAddress(), + }, + SignerQuorum: uint32(2), + SignerEntries: []ledger.SignerEntryWrapper{ + { + SignerEntry: ledger.SignerEntry{ + Account: w1.GetAddress(), + SignerWeight: 1, + }, + }, + { + SignerEntry: ledger.SignerEntry{ + Account: w2.GetAddress(), + SignerWeight: 1, + }, + }, + { + SignerEntry: ledger.SignerEntry{ + Account: "XVYRdEocC28DRx94ZFGP3qNJ1D5Ln7ecXFMd3vREB5Pesju", + SignerWeight: 1, + }, + }, + }, + } + + fmt.Println("⏳ Flattening transaction...") + flatSs := ss.Flatten() + + fmt.Println("⏳ Autofilling transaction...") + if err := client.Autofill(&flatSs); err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Signing transaction...") + blob, _, err := master.Sign(flatSs) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Submitting transaction...") + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ SignerListSet transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Println() + + fmt.Println("⏳ Setting up AccountSet multisign transaction...") + + as := &transaction.AccountSet{ + BaseTx: transaction.BaseTx{ + Account: master.GetAddress(), + }, + Domain: types.Domain(strings.ToUpper(hex.EncodeToString([]byte("example.com")))), + } + + flatAs := as.Flatten() + + if err := client.AutofillMultisigned(&flatAs, 2); err != nil { + fmt.Println(err) + return + } + + w1As := maps.Clone(flatAs) + + blob1, _, err := w1.Multisign(w1As) + if err != nil { + fmt.Println(err) + return + } + + w2As := maps.Clone(flatAs) + + blob2, _, err := w2.Multisign(w2As) + if err != nil { + fmt.Println(err) + return + } + + blob, err = xrpl.Multisign(blob1, blob2) + if err != nil { + fmt.Println(err) + return + } + + mRes, err := client.SubmitMultisigned(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Multisigned transaction submitted!") + fmt.Printf("🌐 Result: %s\n", mRes.EngineResult) +} diff --git a/_code-samples/non-fungible-token/go/go.mod b/_code-samples/non-fungible-token/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/non-fungible-token/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/non-fungible-token/go/go.sum b/_code-samples/non-fungible-token/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/non-fungible-token/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/non-fungible-token/go/nft-accept/rpc/main.go b/_code-samples/non-fungible-token/go/nft-accept/rpc/main.go new file mode 100644 index 0000000000..72bbe964c7 --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-accept/rpc/main.go @@ -0,0 +1,128 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/rpc/types" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + // Initialize the RPC client configuration + cfg, err := rpc.NewClientConfig( + "https://s.devnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + // Create the RPC client + client := rpc.NewClient(cfg) + + // Step 1: Fund wallets + fmt.Println("⏳ Funding wallets...") + + // Create and fund the NFT minter wallet + nftMinter, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT minter wallet:", err) + return + } + if err := client.FundWallet(&nftMinter); err != nil { + fmt.Println("❌ Error funding NFT minter wallet:", err) + return + } + fmt.Println("💸 NFT minter wallet funded!") + + // Create and fund the NFT buyer wallet + nftBuyer, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT buyer wallet:", err) + return + } + if err := client.FundWallet(&nftBuyer); err != nil { + fmt.Println("❌ Error funding NFT buyer wallet:", err) + return + } + fmt.Println("💸 NFT buyer wallet funded!") + fmt.Println() + + // Step 2: Mint an NFT + fmt.Println("⏳ Minting NFT...") + + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + Destination: nftBuyer.ClassicAddress, + Amount: txnTypes.XRPCurrencyAmount(1000000), // 1 XRP + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ NFTokenMint txn is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + // Step 3: Retrieve the NFT token offer ID + fmt.Println("⏳ Retrieving NFT offer ID...") + + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + offerID, ok := metaMap["offer_id"].(string) + if !ok { + fmt.Println("❌ offer_id not found or not a string") + return + } + + fmt.Println("🌎 offer_id:", offerID) + fmt.Println() + + // Step 4: Accept the NFT offer + fmt.Println("⏳ Accepting NFT offer...") + + nftAccept := transaction.NFTokenAcceptOffer{ + BaseTx: transaction.BaseTx{ + Account: nftBuyer.ClassicAddress, + TransactionType: transaction.NFTokenAcceptOfferTx, + }, + NFTokenSellOffer: txnTypes.Hash256(offerID), + } + + response, err := client.SubmitTxAndWait(nftAccept.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftBuyer, + }) + if err != nil { + fmt.Println("❌ Error accepting NFT offer:", err) + return + } + if !response.Validated { + fmt.Println("❌ NFTokenAcceptOffer txn is not in a validated ledger", response) + return + } + fmt.Println("✅ NFT offer accepted successfully! - 🌎 Hash: ", response.Hash) +} diff --git a/_code-samples/non-fungible-token/go/nft-accept/ws/main.go b/_code-samples/non-fungible-token/go/nft-accept/ws/main.go new file mode 100644 index 0000000000..d25ac1e4d0 --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-accept/ws/main.go @@ -0,0 +1,133 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" + "github.com/Peersyst/xrpl-go/xrpl/websocket" + "github.com/Peersyst/xrpl-go/xrpl/websocket/types" +) + +func main() { + // Connect to the XRPL devnet + fmt.Println("⏳ Connecting to devnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.devnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println("❌ Error connecting to devnet:", err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to devnet") + return + } + fmt.Println("✅ Connected to devnet") + fmt.Println() + + // Fund wallets + fmt.Println("⏳ Funding wallets...") + + // Create and fund the NFT minter wallet + nftMinter, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT minter wallet:", err) + return + } + if err := client.FundWallet(&nftMinter); err != nil { + fmt.Println("❌ Error funding NFT minter wallet:", err) + return + } + fmt.Println("💸 NFT minter wallet funded!") + + // Create and fund the NFT buyer wallet + nftBuyer, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT buyer wallet:", err) + return + } + if err := client.FundWallet(&nftBuyer); err != nil { + fmt.Println("❌ Error funding NFT buyer wallet:", err) + return + } + fmt.Println("💸 NFT buyer wallet funded!") + fmt.Println() + + // Mint an NFT + fmt.Println("⏳ Minting NFT...") + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + Destination: nftBuyer.ClassicAddress, + Amount: txnTypes.XRPCurrencyAmount(1000000), // 1 XRP + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ NFTokenMint transaction is not in a validated ledger:", responseMint) + return + } + fmt.Println("✅ NFT minted successfully! - 🌎 Hash:", responseMint.Hash) + fmt.Println() + + // Extract the NFT token offer ID from the transaction metadata + fmt.Println("⏳ Extracting offer ID...") + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + offerID, ok := metaMap["offer_id"].(string) + if !ok { + fmt.Println("❌ offer_id not found or not a string") + return + } + fmt.Println("🌎 offer_id:", offerID) + fmt.Println() + + // Accept the NFT offer + fmt.Println("⏳ Accepting NFT offer...") + nftAccept := transaction.NFTokenAcceptOffer{ + BaseTx: transaction.BaseTx{ + Account: nftBuyer.ClassicAddress, + TransactionType: transaction.NFTokenAcceptOfferTx, + }, + NFTokenSellOffer: txnTypes.Hash256(offerID), + } + + response, err := client.SubmitTxAndWait(nftAccept.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftBuyer, + }) + if err != nil { + fmt.Println("❌ Error accepting NFT offer:", err) + return + } + if !response.Validated { + fmt.Println("❌ NFTokenAcceptOffer transaction is not in a validated ledger:", response) + return + } + fmt.Println("✅ NFT offer accepted successfully! - 🌎 Hash:", response.Hash) +} diff --git a/_code-samples/non-fungible-token/go/nft-burn/rpc/main.go b/_code-samples/non-fungible-token/go/nft-burn/rpc/main.go new file mode 100644 index 0000000000..317fe6be7e --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-burn/rpc/main.go @@ -0,0 +1,114 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/rpc/types" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + // Initialize the RPC client configuration + cfg, err := rpc.NewClientConfig( + "https://s.devnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + // Create the RPC client + client := rpc.NewClient(cfg) + + // Step 1: Fund wallets + fmt.Println("⏳ Funding wallets...") + + // Create and fund the NFT minter wallet + nftMinter, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT minter wallet:", err) + return + } + if err := client.FundWallet(&nftMinter); err != nil { + fmt.Println("❌ Error funding NFT minter wallet:", err) + return + } + fmt.Println("💸 NFT minter wallet funded!") + fmt.Println() + + // Step 2: Mint an NFT + fmt.Println("⏳ Minting NFT...") + + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ NFTokenMint txn is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + // Step 3: Retrieve the token ID + fmt.Println("⏳ Retrieving NFT ID...") + + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID, ok := metaMap["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID) + fmt.Println() + + // Step 4: Burn the NFT + fmt.Println("⏳ Burn the NFT...") + + nftBurn := transaction.NFTokenBurn{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenAcceptOfferTx, + }, + NFTokenID: txnTypes.NFTokenID(nftokenID), + } + + responseBurn, err := client.SubmitTxAndWait(nftBurn.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error burning NFT:", err) + return + } + if !responseBurn.Validated { + fmt.Println("❌ NFTokenBurn transactiob is not in a validated ledger", responseBurn) + return + } + fmt.Println("✅ NFT burned successfully! - 🌎 Hash: ", responseBurn.Hash) +} diff --git a/_code-samples/non-fungible-token/go/nft-burn/ws/main.go b/_code-samples/non-fungible-token/go/nft-burn/ws/main.go new file mode 100644 index 0000000000..f8a834a563 --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-burn/ws/main.go @@ -0,0 +1,123 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" + "github.com/Peersyst/xrpl-go/xrpl/websocket" + "github.com/Peersyst/xrpl-go/xrpl/websocket/types" +) + +func main() { + // Connect to the XRPL devnet + fmt.Println("⏳ Connecting to devnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.devnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println("❌ Error connecting to devnet:", err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to devnet") + return + } + fmt.Println("✅ Connected to devnet") + fmt.Println() + + // Step 1: Fund wallets + fmt.Println("⏳ Funding wallets...") + + // Create and fund the NFT minter wallet + nftMinter, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT minter wallet:", err) + return + } + if err := client.FundWallet(&nftMinter); err != nil { + fmt.Println("❌ Error funding NFT minter wallet:", err) + return + } + fmt.Println("💸 NFT minter wallet funded!") + fmt.Println() + + // Step 2: Mint an NFT + fmt.Println("⏳ Minting NFT...") + + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ NFTokenMint txn is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + // Step 3: Retrieve the token ID + fmt.Println("⏳ Retrieving NFT ID...") + + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID, ok := metaMap["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID) + fmt.Println() + + // Step 4: Burn the NFT + fmt.Println("⏳ Burn the NFT...") + + nftBurn := transaction.NFTokenBurn{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenAcceptOfferTx, + }, + NFTokenID: txnTypes.NFTokenID(nftokenID), + } + + responseBurn, err := client.SubmitTxAndWait(nftBurn.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error burning NFT:", err) + return + } + if !responseBurn.Validated { + fmt.Println("❌ NFTokenBurn transactiob is not in a validated ledger", responseBurn) + return + } + fmt.Println("✅ NFT burned successfully! - 🌎 Hash: ", responseBurn.Hash) +} diff --git a/_code-samples/non-fungible-token/go/nft-cancel/rpc/main.go b/_code-samples/non-fungible-token/go/nft-cancel/rpc/main.go new file mode 100644 index 0000000000..5d0b59dbbe --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-cancel/rpc/main.go @@ -0,0 +1,163 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/rpc/types" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + // Initialize the RPC client configuration + cfg, err := rpc.NewClientConfig( + "https://s.devnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + // Create the RPC client + client := rpc.NewClient(cfg) + + // Step 1: Fund wallet + fmt.Println("⏳ Funding wallet...") + + // Create and fund the NFT minter wallet + nftMinter, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT minter wallet:", err) + return + } + if err := client.FundWallet(&nftMinter); err != nil { + fmt.Println("❌ Error funding NFT minter wallet:", err) + return + } + fmt.Println("💸 NFT minter wallet funded!") + + // Step 2: Mint two NFTs + fmt.Println("⏳ Minting first NFT...") + + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting first NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ First NFTokenMint transaction is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ First NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + // Step 3: Retrieve the NFT token ID + fmt.Println("⏳ Retrieving NFT ID...") + + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID1, ok := metaMap["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID1) + fmt.Println() + + // ------ + + fmt.Println("⏳ Minting second NFT...") + + nftMint2 := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint2.SetTransferableFlag() + + responseMint2, err := client.SubmitTxAndWait(nftMint2.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting second NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ Second NFTokenMint transaction is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ Second NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + // Step 3: Retrieve the second NFT token ID + fmt.Println("⏳ Retrieving second NFT ID...") + + metaMap2, ok := responseMint2.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID2, ok := metaMap2["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID2) + fmt.Println() + + // Step 4: Cancel the NFT offers + fmt.Println("⏳ Canceling NFT offers...") + + nftCancel := transaction.NFTokenCancelOffer{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenAcceptOfferTx, + }, + NFTokenOffers: []txnTypes.NFTokenID{ + txnTypes.NFTokenID(nftokenID1), + txnTypes.NFTokenID(nftokenID2), + }, + } + + response, err := client.SubmitTxAndWait(nftCancel.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error canceling NFT offers:", err) + return + } + if !response.Validated { + fmt.Println("❌ NFTokenCancelOffer transaction is not in a validated ledger", response) + return + } + fmt.Println("✅ NFT offers canceled successfully! - 🌎 Hash: ", response.Hash) +} diff --git a/_code-samples/non-fungible-token/go/nft-cancel/ws/main.go b/_code-samples/non-fungible-token/go/nft-cancel/ws/main.go new file mode 100644 index 0000000000..be2fd94579 --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-cancel/ws/main.go @@ -0,0 +1,172 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" + "github.com/Peersyst/xrpl-go/xrpl/websocket" + "github.com/Peersyst/xrpl-go/xrpl/websocket/types" +) + +func main() { + // Connect to the XRPL devnet + fmt.Println("⏳ Connecting to devnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.devnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println("❌ Error connecting to devnet:", err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to devnet") + return + } + fmt.Println("✅ Connected to devnet") + fmt.Println() + + // Step 1: Fund wallet + fmt.Println("⏳ Funding wallet...") + + // Create and fund the NFT minter wallet + nftMinter, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating NFT minter wallet:", err) + return + } + if err := client.FundWallet(&nftMinter); err != nil { + fmt.Println("❌ Error funding NFT minter wallet:", err) + return + } + fmt.Println("💸 NFT minter wallet funded!") + + // Step 2: Mint two NFTs + fmt.Println("⏳ Minting first NFT...") + + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting first NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ First NFTokenMint transaction is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ First NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + // Step 3: Retrieve the NFT token ID + fmt.Println("⏳ Retrieving NFT ID...") + + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID1, ok := metaMap["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID1) + fmt.Println() + + // ------ + + fmt.Println("⏳ Minting second NFT...") + + nftMint2 := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint2.SetTransferableFlag() + + responseMint2, err := client.SubmitTxAndWait(nftMint2.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error minting second NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ Second NFTokenMint transaction is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ Second NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + // Step 3: Retrieve the second NFT token ID + fmt.Println("⏳ Retrieving second NFT ID...") + + metaMap2, ok := responseMint2.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID2, ok := metaMap2["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID2) + fmt.Println() + + // Step 4: Cancel the NFT offers + fmt.Println("⏳ Canceling NFT offers...") + + nftCancel := transaction.NFTokenCancelOffer{ + BaseTx: transaction.BaseTx{ + Account: nftMinter.ClassicAddress, + TransactionType: transaction.NFTokenAcceptOfferTx, + }, + NFTokenOffers: []txnTypes.NFTokenID{ + txnTypes.NFTokenID(nftokenID1), + txnTypes.NFTokenID(nftokenID2), + }, + } + + response, err := client.SubmitTxAndWait(nftCancel.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftMinter, + }) + if err != nil { + fmt.Println("❌ Error canceling NFT offers:", err) + return + } + if !response.Validated { + fmt.Println("❌ NFTokenCancelOffer transaction is not in a validated ledger", response) + return + } + fmt.Println("✅ NFT offers canceled successfully! - 🌎 Hash: ", response.Hash) +} diff --git a/_code-samples/non-fungible-token/go/nft-modify/rpc/main.go b/_code-samples/non-fungible-token/go/nft-modify/rpc/main.go new file mode 100644 index 0000000000..286fb14771 --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-modify/rpc/main.go @@ -0,0 +1,107 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/rpc/types" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + 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() + + fmt.Println("⏳ Funding wallet...") + + // Create and fund the nft wallet + nftWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating nft wallet:", err) + return + } + if err := client.FundWallet(&nftWallet); err != nil { + fmt.Println("❌ Error funding nft wallet:", err) + return + } + fmt.Println("💸 NFT wallet funded! - #️⃣: ", nftWallet.ClassicAddress) + fmt.Println() + + // Mint NFT + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftWallet.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetMutableFlag() + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftWallet, + }) + if err != nil { + fmt.Println("❌ Error minting NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ NFTokenMint txn is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID, ok := metaMap["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID) + fmt.Println() + + // Update NFT + nftModify := transaction.NFTokenModify{ + BaseTx: transaction.BaseTx{ + Account: nftWallet.ClassicAddress, + TransactionType: transaction.NFTokenModifyTx, + }, + URI: "68747470733A2F2F7961686F6F2E636F6D", // https://yahoo.com + NFTokenID: txnTypes.NFTokenID(nftokenID), + } + // nftoken_id + responseModify, err := client.SubmitTxAndWait(nftModify.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftWallet, + }) + if err != nil { + fmt.Println("❌ Error modifying NFT:", err) + return + } + if !responseModify.Validated { + fmt.Println("❌ NFTokenModify txn is not in a validated ledger", responseModify) + return + } + fmt.Println("✅ NFT URI modified successfully! - 🌎 Hash: ", responseModify.Hash) +} diff --git a/_code-samples/non-fungible-token/go/nft-modify/ws/main.go b/_code-samples/non-fungible-token/go/nft-modify/ws/main.go new file mode 100644 index 0000000000..77d28416d4 --- /dev/null +++ b/_code-samples/non-fungible-token/go/nft-modify/ws/main.go @@ -0,0 +1,117 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + txnTypes "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" + "github.com/Peersyst/xrpl-go/xrpl/websocket" + "github.com/Peersyst/xrpl-go/xrpl/websocket/types" +) + +func main() { + fmt.Println("⏳ Connecting to devnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.devnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewDevnetFaucetProvider()), + ) + + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to devnet") + return + } + + fmt.Println("✅ Connected to devnet") + fmt.Println() + + // Create and fund the nft wallet + fmt.Println("⏳ Funding wallet...") + nftWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println("❌ Error creating nft wallet:", err) + return + } + if err := client.FundWallet(&nftWallet); err != nil { + fmt.Println("❌ Error funding nft wallet:", err) + return + } + fmt.Println("💸 NFT wallet funded!") + fmt.Println() + + // Mint NFT + nftMint := transaction.NFTokenMint{ + BaseTx: transaction.BaseTx{ + Account: nftWallet.ClassicAddress, + TransactionType: transaction.NFTokenMintTx, + }, + NFTokenTaxon: 0, + URI: txnTypes.NFTokenURI("68747470733A2F2F676F6F676C652E636F6D"), // https://google.com + } + nftMint.SetMutableFlag() + nftMint.SetTransferableFlag() + + responseMint, err := client.SubmitTxAndWait(nftMint.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftWallet, + }) + if err != nil { + fmt.Println("❌ Error minting NFT:", err) + return + } + if !responseMint.Validated { + fmt.Println("❌ NFTokenMint txn is not in a validated ledger", responseMint) + return + } + fmt.Println("✅ NFT minted successfully! - 🌎 Hash: ", responseMint.Hash) + fmt.Println() + + metaMap, ok := responseMint.Meta.(map[string]any) + if !ok { + fmt.Println("❌ Meta is not a map[string]any") + return + } + + nftokenID, ok := metaMap["nftoken_id"].(string) + if !ok { + fmt.Println("❌ nftoken_id not found or not a string") + return + } + + fmt.Println("🌎 nftoken_id:", nftokenID) + fmt.Println() + + // Update NFT + nftModify := transaction.NFTokenModify{ + BaseTx: transaction.BaseTx{ + Account: nftWallet.ClassicAddress, + TransactionType: transaction.NFTokenModifyTx, + }, + URI: "68747470733A2F2F7961686F6F2E636F6D", // https://yahoo.com + NFTokenID: txnTypes.NFTokenID(nftokenID), + } + + responseModify, err := client.SubmitTxAndWait(nftModify.Flatten(), &types.SubmitOptions{ + Autofill: true, + Wallet: &nftWallet, + }) + if err != nil { + fmt.Println("❌ Error modifying NFT:", err) + return + } + if !responseModify.Validated { + fmt.Println("❌ NFTokenModify txn is not in a validated ledger", responseModify) + return + } + fmt.Println("✅ NFT URI modified successfully! - 🌎 Hash: ", responseModify.Hash) +} diff --git a/_code-samples/partial-payment/go/go.mod b/_code-samples/partial-payment/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/partial-payment/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/partial-payment/go/go.sum b/_code-samples/partial-payment/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/partial-payment/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/partial-payment/go/rpc/main.go b/_code-samples/partial-payment/go/rpc/main.go new file mode 100644 index 0000000000..73751ffcb7 --- /dev/null +++ b/_code-samples/partial-payment/go/rpc/main.go @@ -0,0 +1,168 @@ +package main + +import ( + "fmt" + "time" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + cfg, err := rpc.NewClientConfig( + "https://s.altnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + client := rpc.NewClient(cfg) + + fmt.Println("⏳ Funding wallets...") + w1, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + w2, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + if err := client.FundWallet(&w1); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 1 funded") + if err := client.FundWallet(&w2); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 2 funded") + fmt.Println() + + time.Sleep(5 * time.Second) + + fmt.Println("⏳ Sending TrustSet transaction...") + ts := &transaction.TrustSet{ + BaseTx: transaction.BaseTx{ + Account: w2.ClassicAddress, + }, + LimitAmount: types.IssuedCurrencyAmount{ + Currency: "FOO", + Issuer: w1.ClassicAddress, + Value: "10000000000", + }, + } + + flatTs := ts.Flatten() + + err = client.Autofill(&flatTs) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err := w2.Sign(flatTs) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ TrustSet transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + fmt.Println("⏳ Issuing tokens for wallet 2...") + p := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: w1.GetAddress(), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: "FOO", + Issuer: w1.GetAddress(), + Value: "50", + }, + Destination: w2.GetAddress(), + } + + flatP := p.Flatten() + + err = client.Autofill(&flatP) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err = w1.Sign(flatP) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Payment transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + fmt.Println("⏳ Submitting Partial Payment transaction...") + pp := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: w2.GetAddress(), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: "FOO", + Issuer: w1.GetAddress(), + Value: "10", + }, + Destination: w1.GetAddress(), + } + + pp.SetPartialPaymentFlag() + + flatPP := pp.Flatten() + + err = client.Autofill(&flatPP) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err = w2.Sign(flatPP) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Partial Payment transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() +} diff --git a/_code-samples/partial-payment/go/ws/main.go b/_code-samples/partial-payment/go/ws/main.go new file mode 100644 index 0000000000..af18ae9ac4 --- /dev/null +++ b/_code-samples/partial-payment/go/ws/main.go @@ -0,0 +1,179 @@ +package main + +import ( + "fmt" + "time" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "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" +) + +func main() { + fmt.Println("⏳ Connecting to testnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.altnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to testnet") + return + } + + fmt.Println("✅ Connected to testnet") + fmt.Println() + + fmt.Println("⏳ Funding wallets...") + w1, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + w2, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + if err := client.FundWallet(&w1); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 1 funded") + if err := client.FundWallet(&w2); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 2 funded") + fmt.Println() + + time.Sleep(5 * time.Second) + + fmt.Println("⏳ Sending TrustSet transaction...") + ts := &transaction.TrustSet{ + BaseTx: transaction.BaseTx{ + Account: w2.ClassicAddress, + }, + LimitAmount: types.IssuedCurrencyAmount{ + Currency: "FOO", + Issuer: w1.ClassicAddress, + Value: "10000000000", + }, + } + + flatTs := ts.Flatten() + + err = client.Autofill(&flatTs) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err := w2.Sign(flatTs) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ TrustSet transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + fmt.Println("⏳ Issuing tokens for wallet 2...") + p := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: w1.GetAddress(), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: "FOO", + Issuer: w1.GetAddress(), + Value: "50", + }, + Destination: w2.GetAddress(), + } + + flatP := p.Flatten() + + err = client.Autofill(&flatP) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err = w1.Sign(flatP) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Payment transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + fmt.Println("⏳ Submitting Partial Payment transaction...") + pp := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: w2.GetAddress(), + }, + Amount: types.IssuedCurrencyAmount{ + Currency: "FOO", + Issuer: w1.GetAddress(), + Value: "10", + }, + Destination: w1.GetAddress(), + } + + pp.SetPartialPaymentFlag() + + flatPP := pp.Flatten() + + err = client.Autofill(&flatPP) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err = w2.Sign(flatPP) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Partial Payment transaction submitted!") + fmt.Printf("🌐 Hash: %s\n", res.Hash.String()) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() +} diff --git a/_code-samples/paths/go/go.mod b/_code-samples/paths/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/paths/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/paths/go/go.sum b/_code-samples/paths/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/paths/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/paths/go/rpc/main.go b/_code-samples/paths/go/rpc/main.go new file mode 100644 index 0000000000..0e25d00dc2 --- /dev/null +++ b/_code-samples/paths/go/rpc/main.go @@ -0,0 +1,111 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/queries/path" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" + + pathtypes "github.com/Peersyst/xrpl-go/xrpl/queries/path/types" +) + +const ( + DestinationAccount = types.Address("rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj") +) + +var ( + DestinationAmount = types.IssuedCurrencyAmount{ + Issuer: "rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc", + Currency: "USD", + Value: "0.001", + } +) + +func main() { + cfg, err := rpc.NewClientConfig( + "https://s.altnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + client := rpc.NewClient(cfg) + + wallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallet...") + if err := client.FundWallet(&wallet); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet funded") + fmt.Println() + + fmt.Println("⏳ Getting paths...") + res, err := client.GetRipplePathFind(&path.RipplePathFindRequest{ + SourceAccount: wallet.GetAddress(), + SourceCurrencies: []pathtypes.RipplePathFindCurrency{ + { + Currency: "XRP", + }, + }, + DestinationAccount: DestinationAccount, + DestinationAmount: DestinationAmount, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("🌐 Computed paths: %d\n", len(res.Alternatives)) + fmt.Println() + + if len(res.Alternatives) == 0 { + fmt.Println("❌ No alternatives found") + return + } + + fmt.Println("⏳ Submitting Payment through path: ", res.Alternatives[0].PathsComputed) + p := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: wallet.GetAddress(), + }, + Destination: DestinationAccount, + Amount: DestinationAmount, + Paths: res.Alternatives[0].PathsComputed, + } + + flatP := p.Flatten() + + if err := client.Autofill(&flatP); err != nil { + fmt.Println(err) + return + } + + blob, hash, err := wallet.Sign(flatP) + if err != nil { + fmt.Println(err) + return + } + + txRes, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Payment submitted") + fmt.Printf("🌐 Hash: %s\n", hash) + fmt.Printf("🌐 Validated: %t\n", txRes.Validated) +} diff --git a/_code-samples/paths/go/ws/main.go b/_code-samples/paths/go/ws/main.go new file mode 100644 index 0000000000..284b7bed2d --- /dev/null +++ b/_code-samples/paths/go/ws/main.go @@ -0,0 +1,122 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/queries/path" + "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" + + pathtypes "github.com/Peersyst/xrpl-go/xrpl/queries/path/types" +) + +const ( + DestinationAccount = types.Address("rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj") +) + +var ( + DestinationAmount = types.IssuedCurrencyAmount{ + Issuer: "rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc", + Currency: "USD", + Value: "0.001", + } +) + +func main() { + fmt.Println("⏳ Connecting to testnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.altnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to testnet") + return + } + + fmt.Println("✅ Connected to testnet") + fmt.Println() + + wallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallet...") + if err := client.FundWallet(&wallet); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet funded") + fmt.Println() + + fmt.Println("⏳ Getting paths...") + res, err := client.GetRipplePathFind(&path.RipplePathFindRequest{ + SourceAccount: wallet.GetAddress(), + SourceCurrencies: []pathtypes.RipplePathFindCurrency{ + { + Currency: "XRP", + }, + }, + DestinationAccount: DestinationAccount, + DestinationAmount: DestinationAmount, + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("🌐 Computed paths: %d\n", len(res.Alternatives)) + fmt.Println() + + if len(res.Alternatives) == 0 { + fmt.Println("❌ No alternatives found") + return + } + + fmt.Println("⏳ Submitting Payment through path: ", res.Alternatives[0].PathsComputed) + p := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: wallet.GetAddress(), + }, + Destination: DestinationAccount, + Amount: DestinationAmount, + Paths: res.Alternatives[0].PathsComputed, + } + + flatP := p.Flatten() + + if err := client.Autofill(&flatP); err != nil { + fmt.Println(err) + return + } + + blob, hash, err := wallet.Sign(flatP) + if err != nil { + fmt.Println(err) + return + } + + txRes, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Payment submitted") + fmt.Printf("🌐 Hash: %s\n", hash) + fmt.Printf("🌐 Validated: %t\n", txRes.Validated) +} diff --git a/_code-samples/send-xrp/go/go.mod b/_code-samples/send-xrp/go/go.mod new file mode 100644 index 0000000000..63f569b0cd --- /dev/null +++ b/_code-samples/send-xrp/go/go.mod @@ -0,0 +1,5 @@ +module github.com/XRPLF + +go 1.23 + +require github.com/Peersyst/xrpl-go v0.1.11 \ No newline at end of file diff --git a/_code-samples/send-xrp/go/rpc/main.go b/_code-samples/send-xrp/go/rpc/main.go new file mode 100644 index 0000000000..9ab1e3e8e7 --- /dev/null +++ b/_code-samples/send-xrp/go/rpc/main.go @@ -0,0 +1 @@ +package rpc diff --git a/_code-samples/send-xrp/go/ws/main.go b/_code-samples/send-xrp/go/ws/main.go new file mode 100644 index 0000000000..98592950df --- /dev/null +++ b/_code-samples/send-xrp/go/ws/main.go @@ -0,0 +1 @@ +package ws diff --git a/_code-samples/set-regular-key/go/go.mod b/_code-samples/set-regular-key/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/set-regular-key/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/set-regular-key/go/go.sum b/_code-samples/set-regular-key/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/set-regular-key/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/set-regular-key/go/rpc/main.go b/_code-samples/set-regular-key/go/rpc/main.go new file mode 100644 index 0000000000..dd58029a6a --- /dev/null +++ b/_code-samples/set-regular-key/go/rpc/main.go @@ -0,0 +1,131 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/transaction/types" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +func main() { + cfg, err := rpc.NewClientConfig( + "https://s.altnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + client := rpc.NewClient(cfg) + + w1, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + w2, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + regularKeyWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + if err := client.FundWallet(&w1); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 1 funded") + + if err := client.FundWallet(&w2); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 2 funded") + + if err := client.FundWallet(®ularKeyWallet); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Regular key wallet funded") + fmt.Println() + + fmt.Println("⏳ Setting regular key...") + rk := &transaction.SetRegularKey{ + BaseTx: transaction.BaseTx{ + Account: w1.GetAddress(), + }, + RegularKey: regularKeyWallet.GetAddress(), + } + + flatRk := rk.Flatten() + + err = client.Autofill(&flatRk) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err := w1.Sign(flatRk) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ SetRegularKey transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + fmt.Println("⏳ Checking if regular key is set...") + p := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: w1.GetAddress(), + }, + Destination: w2.GetAddress(), + Amount: types.XRPCurrencyAmount(10000), + } + + flatP := p.Flatten() + + err = client.Autofill(&flatP) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err = regularKeyWallet.Sign(flatP) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Payment transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) +} diff --git a/_code-samples/set-regular-key/go/ws/main.go b/_code-samples/set-regular-key/go/ws/main.go new file mode 100644 index 0000000000..3bb0ec6256 --- /dev/null +++ b/_code-samples/set-regular-key/go/ws/main.go @@ -0,0 +1,142 @@ +package main + +import ( + "fmt" + + "github.com/Peersyst/xrpl-go/pkg/crypto" + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "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" +) + +func main() { + fmt.Println("⏳ Connecting to testnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.altnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to testnet") + return + } + + fmt.Println("✅ Connected to testnet") + fmt.Println() + + w1, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + w2, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + regularKeyWallet, err := wallet.New(crypto.ED25519()) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallets...") + if err := client.FundWallet(&w1); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 1 funded") + + if err := client.FundWallet(&w2); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet 2 funded") + + if err := client.FundWallet(®ularKeyWallet); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Regular key wallet funded") + fmt.Println() + + fmt.Println("⏳ Setting regular key...") + rk := &transaction.SetRegularKey{ + BaseTx: transaction.BaseTx{ + Account: w1.GetAddress(), + }, + RegularKey: regularKeyWallet.GetAddress(), + } + + flatRk := rk.Flatten() + + err = client.Autofill(&flatRk) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err := w1.Sign(flatRk) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ SetRegularKey transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + fmt.Println("⏳ Checking if regular key is set...") + p := &transaction.Payment{ + BaseTx: transaction.BaseTx{ + Account: w1.GetAddress(), + }, + Destination: w2.GetAddress(), + Amount: types.XRPCurrencyAmount(10000), + } + + flatP := p.Flatten() + + err = client.Autofill(&flatP) + if err != nil { + fmt.Println(err) + return + } + + blob, _, err = regularKeyWallet.Sign(flatP) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ Payment transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) +} diff --git a/_code-samples/use-tickets/go/go.mod b/_code-samples/use-tickets/go/go.mod new file mode 100644 index 0000000000..fa9fde5d08 --- /dev/null +++ b/_code-samples/use-tickets/go/go.mod @@ -0,0 +1,24 @@ +module github.com/XRPLF + +go 1.23.0 + +toolchain go1.23.10 + +require github.com/Peersyst/xrpl-go v0.1.11 + +require ( + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/crypto v0.23.0 // indirect +) diff --git a/_code-samples/use-tickets/go/go.sum b/_code-samples/use-tickets/go/go.sum new file mode 100644 index 0000000000..8d8522a619 --- /dev/null +++ b/_code-samples/use-tickets/go/go.sum @@ -0,0 +1,58 @@ +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= +github.com/Peersyst/xrpl-go v0.1.11 h1:P6r/gHxRnbAtAdPmzNHz/7zpsdfvwh0SS+QI2JNT44w= +github.com/Peersyst/xrpl-go v0.1.11/go.mod h1:CBRM3/soqNeeL2Jx6USVUtECqulZVUoq3UxZKMz9hdw= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys= +github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= diff --git a/_code-samples/use-tickets/go/rpc/main.go b/_code-samples/use-tickets/go/rpc/main.go new file mode 100644 index 0000000000..1c48d20df8 --- /dev/null +++ b/_code-samples/use-tickets/go/rpc/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/queries/account" + "github.com/Peersyst/xrpl-go/xrpl/rpc" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/wallet" +) + +const ( + WalletSeed = "sn3nxiW7v8KXzPzAqzyHXbSSKNuN9" +) + +func main() { + cfg, err := rpc.NewClientConfig( + "https://s.altnet.rippletest.net:51234/", + rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + if err != nil { + panic(err) + } + + client := rpc.NewClient(cfg) + + w, err := wallet.FromSeed(WalletSeed, "") + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallet...") + if err := client.FundWallet(&w); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet funded") + fmt.Println() + + info, err := client.GetAccountInfo(&account.InfoRequest{ + Account: w.GetAddress(), + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("🌐 Current wallet sequence:", info.AccountData.Sequence) + fmt.Println() + + fmt.Println("⏳ Submitting TicketCreate transaction...") + tc := &transaction.TicketCreate{ + BaseTx: transaction.BaseTx{ + Account: w.GetAddress(), + Sequence: info.AccountData.Sequence, + }, + TicketCount: 10, + } + + flatTc := tc.Flatten() + + if err := client.Autofill(&flatTc); err != nil { + fmt.Println(err) + return + } + + blob, _, err := w.Sign(flatTc) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ TicketCreate transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + objects, err := client.GetAccountObjects(&account.ObjectsRequest{ + Account: w.GetAddress(), + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("🌐 Account objects:", objects.AccountObjects[0]["TicketSequence"]) + + seq, err := objects.AccountObjects[0]["TicketSequence"].(json.Number).Int64() + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Submitting AccountSet transaction...") + as := &transaction.AccountSet{ + BaseTx: transaction.BaseTx{ + Account: w.GetAddress(), + Sequence: 0, + TicketSequence: uint32(seq), + }, + } + + flatAs := as.Flatten() + + if err := client.Autofill(&flatAs); err != nil { + fmt.Println(err) + return + } + + flatAs["Sequence"] = uint32(0) + + blob, _, err = w.Sign(flatAs) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ AccountSet transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) +} diff --git a/_code-samples/use-tickets/go/ws/main.go b/_code-samples/use-tickets/go/ws/main.go new file mode 100644 index 0000000000..5e128c2752 --- /dev/null +++ b/_code-samples/use-tickets/go/ws/main.go @@ -0,0 +1,148 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/Peersyst/xrpl-go/xrpl/faucet" + "github.com/Peersyst/xrpl-go/xrpl/queries/account" + "github.com/Peersyst/xrpl-go/xrpl/transaction" + "github.com/Peersyst/xrpl-go/xrpl/wallet" + "github.com/Peersyst/xrpl-go/xrpl/websocket" +) + +const ( + WalletSeed = "sn3nxiW7v8KXzPzAqzyHXbSSKNuN9" +) + +func main() { + fmt.Println("⏳ Connecting to testnet...") + client := websocket.NewClient( + websocket.NewClientConfig(). + WithHost("wss://s.altnet.rippletest.net:51233"). + WithFaucetProvider(faucet.NewTestnetFaucetProvider()), + ) + defer client.Disconnect() + + if err := client.Connect(); err != nil { + fmt.Println(err) + return + } + + if !client.IsConnected() { + fmt.Println("❌ Failed to connect to testnet") + return + } + + fmt.Println("✅ Connected to testnet") + fmt.Println() + + w, err := wallet.FromSeed(WalletSeed, "") + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Funding wallet...") + if err := client.FundWallet(&w); err != nil { + fmt.Println(err) + return + } + + fmt.Println("💸 Wallet funded") + fmt.Println() + + info, err := client.GetAccountInfo(&account.InfoRequest{ + Account: w.GetAddress(), + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("🌐 Current wallet sequence:", info.AccountData.Sequence) + fmt.Println() + + fmt.Println("⏳ Submitting TicketCreate transaction...") + tc := &transaction.TicketCreate{ + BaseTx: transaction.BaseTx{ + Account: w.GetAddress(), + Sequence: info.AccountData.Sequence, + }, + TicketCount: 10, + } + + flatTc := tc.Flatten() + + if err := client.Autofill(&flatTc); err != nil { + fmt.Println(err) + return + } + + blob, _, err := w.Sign(flatTc) + if err != nil { + fmt.Println(err) + return + } + + res, err := client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ TicketCreate transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) + fmt.Println() + + objects, err := client.GetAccountObjects(&account.ObjectsRequest{ + Account: w.GetAddress(), + }) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("🌐 Account objects:", objects.AccountObjects[0]["TicketSequence"]) + + seq, err := objects.AccountObjects[0]["TicketSequence"].(json.Number).Int64() + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("⏳ Submitting AccountSet transaction...") + as := &transaction.AccountSet{ + BaseTx: transaction.BaseTx{ + Account: w.GetAddress(), + Sequence: 0, + TicketSequence: uint32(seq), + }, + } + + flatAs := as.Flatten() + + if err := client.Autofill(&flatAs); err != nil { + fmt.Println(err) + return + } + + flatAs["Sequence"] = uint32(0) + + blob, _, err = w.Sign(flatAs) + if err != nil { + fmt.Println(err) + return + } + + res, err = client.SubmitTxBlobAndWait(blob, false) + if err != nil { + fmt.Println(err) + return + } + + fmt.Println("✅ AccountSet transaction submitted") + fmt.Printf("🌐 Hash: %s\n", res.Hash) + fmt.Printf("🌐 Validated: %t\n", res.Validated) +}