├── docs ├── .nvmrc ├── static │ ├── .nojekyll │ └── img │ │ ├── bg-top.png │ │ ├── favicon.ico │ │ ├── bg-bottom.png │ │ ├── xrpl-logo.png │ │ └── xrpl-go-logo.png ├── src │ ├── pages │ │ ├── markdown-page.md │ │ ├── index.module.css │ │ └── index.tsx │ ├── components │ │ ├── HomepageFeatures │ │ │ └── styles.module.css │ │ ├── LinkButton │ │ │ ├── styles.module.css │ │ │ └── index.tsx │ │ └── HeroSection │ │ │ ├── styles.module.css │ │ │ └── index.tsx │ └── theme │ │ └── SearchBar.tsx ├── docs │ ├── xrpl │ │ ├── _category_.json │ │ ├── hash.md │ │ ├── time.md │ │ ├── faucet.md │ │ └── currency.md │ └── intro.md ├── tsconfig.json ├── .gitignore ├── README.md ├── sidebars.ts └── package.json ├── .go-version ├── CODEOWNERS.md ├── xrpl ├── faucet │ ├── constants.go │ ├── devnet_test.go │ └── testnet_test.go ├── transaction │ ├── types │ │ ├── asset_scale.go │ │ ├── expiration.go │ │ ├── holder.go │ │ ├── transfer_fee.go │ │ ├── destination_tag.go │ │ ├── mptoken_metadata.go │ │ ├── address.go │ │ ├── hash128.go │ │ ├── hash256.go │ │ ├── nftoken.go │ │ ├── message_key.go │ │ ├── wallet_size.go │ │ ├── nftoken_id.go │ │ ├── nftoken_uri.go │ │ ├── domain.go │ │ ├── nftoken_minter.go │ │ ├── email_hash.go │ │ ├── wallet_locator.go │ │ ├── ticksize.go │ │ ├── transfer_rate.go │ │ ├── issued_currency.go │ │ ├── credential_ids.go │ │ ├── credential.go │ │ ├── message_key_test.go │ │ ├── nftoken_minter_test.go │ │ ├── domain_test.go │ │ ├── ticksize_test.go │ │ ├── wallet_size_test.go │ │ ├── transfer_fee_test.go │ │ ├── destination_tag_test.go │ │ ├── flags.go │ │ ├── expiration_test.go │ │ ├── email_hash_test.go │ │ ├── flags_test.go │ │ ├── nftoken_id_test.go │ │ ├── wallet_locator_test.go │ │ ├── signer.go │ │ ├── memo.go │ │ ├── transfer_rate_test.go │ │ ├── nftoken_uri_test.go │ │ ├── credential_type.go │ │ ├── credential_test.go │ │ ├── authorize_credential.go │ │ ├── authorize_credential_list.go │ │ ├── authorize_credentials.go │ │ ├── permission.go │ │ └── issued_currency_test.go │ ├── integration │ │ └── types.go │ ├── flat_tx.go │ ├── nftoken_mint_metadata.go │ ├── path_step.go │ ├── did_delete.go │ ├── oracle_delete.go │ ├── amm_common.go │ └── offer_cancel.go ├── queries │ ├── account │ │ ├── types │ │ │ ├── errors.go │ │ │ ├── offer_result.go │ │ │ ├── queue_transaction.go │ │ │ ├── nft.go │ │ │ ├── queue_data.go │ │ │ ├── trust_line.go │ │ │ └── channel_result.go │ │ ├── v1 │ │ │ ├── types │ │ │ │ └── account_data.go │ │ │ ├── offers_test.go │ │ │ ├── objects_test.go │ │ │ ├── transactions_test.go │ │ │ └── currencies_test.go │ │ ├── offers_test.go │ │ ├── objects_test.go │ │ └── currencies_test.go │ ├── server │ │ ├── types │ │ │ ├── port.go │ │ │ ├── feature.go │ │ │ ├── job.go │ │ │ ├── fee_drops.go │ │ │ ├── fee_levels.go │ │ │ ├── ledger.go │ │ │ └── state_accounting.go │ │ ├── server_info.go │ │ ├── fee_test.go │ │ ├── server_state.go │ │ ├── feature_test.go │ │ └── manifest.go │ ├── version │ │ └── api.go │ ├── oracle │ │ └── types │ │ │ ├── oracle.go │ │ │ └── set.go │ ├── path │ │ ├── types │ │ │ ├── ripple_path.go │ │ │ └── path.go │ │ ├── path_find_test.go │ │ ├── v1 │ │ │ ├── path_find_test.go │ │ │ └── deposit_authorized_test.go │ │ └── deposit_authorized_test.go │ ├── common │ │ ├── request.go │ │ └── ledger.go │ ├── ledger │ │ ├── types │ │ │ └── state.go │ │ ├── v1 │ │ │ ├── types │ │ │ │ └── state.go │ │ │ ├── ledger_current_test.go │ │ │ ├── ledger_closed_test.go │ │ │ ├── ledger_data_test.go │ │ │ ├── ledger_current.go │ │ │ └── ledger_closed.go │ │ ├── ledger_current_test.go │ │ ├── ledger_closed_test.go │ │ ├── ledger_data_test.go │ │ ├── ledger_current.go │ │ └── ledger_closed.go │ ├── subscription │ │ ├── types │ │ │ ├── type.go │ │ │ └── consensus.go │ │ ├── v1 │ │ │ ├── types │ │ │ │ ├── type.go │ │ │ │ └── consensus.go │ │ │ └── unsubscribe_test.go │ │ └── unsubscribe_test.go │ ├── utility │ │ ├── v1 │ │ │ ├── random_test.go │ │ │ ├── ping.go │ │ │ └── random.go │ │ ├── random_test.go │ │ ├── ping.go │ │ └── random.go │ ├── nft │ │ ├── types │ │ │ └── nftoken_offer.go │ │ ├── nftoken_buy_offers.go │ │ ├── nftoken_sell_offers.go │ │ └── v1 │ │ │ ├── nftoken_buy_offers.go │ │ │ └── nftoken_sell_offers.go │ ├── clio │ │ ├── nft_history_test.go │ │ ├── v1 │ │ │ ├── nft_history_test.go │ │ │ └── nft_info_test.go │ │ ├── types │ │ │ ├── nft.go │ │ │ └── ledger.go │ │ └── nft_info_test.go │ ├── transactions │ │ ├── v1 │ │ │ ├── submit_test.go │ │ │ └── transaction_entry.go │ │ ├── submit_test.go │ │ └── transaction_entry.go │ └── channel │ │ ├── v1 │ │ ├── verify_test.go │ │ └── verify.go │ │ ├── verify_test.go │ │ └── verify.go ├── websocket │ ├── interfaces │ │ └── request.go │ ├── types │ │ ├── client_options.go │ │ ├── message.go │ │ └── message_test.go │ ├── connection_test.go │ ├── testutil │ │ └── mock-webserver.go │ ├── errors.go │ └── response.go ├── hash │ ├── errors.go │ └── constants.go ├── rpc │ ├── types │ │ └── client_options.go │ ├── errors_test.go │ ├── request.go │ ├── testutil │ │ └── client_mock.go │ ├── response.go │ └── errors.go ├── ledger-entry-types │ ├── did_test.go │ ├── bridge_test.go │ ├── xchain_owned_claim_id_test.go │ ├── xchain_owned_create_account_claim_id_test.go │ ├── fee_settings_test.go │ ├── ticket_test.go │ ├── negative_unl_test.go │ ├── deposit_preauth_test.go │ ├── nftoken_offer_test.go │ └── nftoken_page_test.go ├── interfaces │ └── crypto.go ├── wallet │ └── types │ │ ├── batch_account_test.go │ │ ├── batch_account.go │ │ └── batch_signable_test.go ├── common │ ├── constants.go │ └── interfaces.go ├── testutil │ ├── integration │ │ ├── interfaces.go │ │ ├── config.go │ │ ├── flag.go │ │ └── env.go │ ├── serializer.go │ └── flatten.go └── currency │ └── native.go ├── binary-codec ├── definitions │ ├── init.go │ ├── field_instance_test.go │ ├── field_instance.go │ └── errors.go ├── serdes │ ├── interfaces │ │ ├── field_id_codec.go │ │ └── definitions.go │ └── field_id_codec_benchmark_test.go ├── types │ ├── hash128_test.go │ ├── hash160_test.go │ ├── hash192_test.go │ ├── hash256_test.go │ ├── hash192.go │ ├── errors.go │ ├── hash128.go │ ├── hash160.go │ ├── hash256.go │ ├── interfaces │ │ ├── binary_serializer.go │ │ └── binary_parser.go │ ├── testutil │ │ └── helpers.go │ ├── uint32.go │ └── blob.go ├── testutil │ └── mockgen.sh └── README.md ├── pkg ├── crypto │ ├── types.go │ ├── sha512.go │ └── sha512_test.go ├── map_utils │ └── map_utils.go └── random │ ├── main.go │ └── main_test.go ├── keypairs ├── testutil │ └── mockgen.sh ├── interfaces │ ├── random.go │ └── crypto.go ├── crypto.go └── crypto_test.go ├── .github ├── dependabot.yml ├── workflows │ ├── xrpl-go-ci-lint-test.yml │ ├── xrpl-go-docs-test-deploy.yml │ ├── xrpl-go-release.yml │ ├── xrpl-go-ci-coverage.yml │ └── xrpl-go-docs-deploy.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ ├── bug_report.md │ └── enhancement.md └── pull_request_template.md ├── Dockerfile ├── address-codec ├── interfaces │ └── crypto.go ├── sha256.go ├── base58check.go └── errors.go ├── .golangci.yml ├── examples ├── ledger │ ├── rpc │ │ └── main.go │ └── ws │ │ └── main.go └── queries │ └── account-tx │ ├── rpc │ └── main.go │ └── ws │ └── main.go ├── .gitignore ├── LICENSE └── go.mod /docs/.nvmrc: -------------------------------------------------------------------------------- 1 | v18 -------------------------------------------------------------------------------- /.go-version: -------------------------------------------------------------------------------- 1 | 1.23.0 2 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CODEOWNERS.md: -------------------------------------------------------------------------------- 1 | * @Peersyst/xrpl-go 2 | -------------------------------------------------------------------------------- /xrpl/faucet/constants.go: -------------------------------------------------------------------------------- 1 | package faucet 2 | 3 | const ( 4 | UserAgent = "xrpl.go" 5 | ) 6 | -------------------------------------------------------------------------------- /docs/static/img/bg-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-go/HEAD/docs/static/img/bg-top.png -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-go/HEAD/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /binary-codec/definitions/init.go: -------------------------------------------------------------------------------- 1 | package definitions 2 | 3 | func init() { 4 | loadDefinitions() 5 | } 6 | -------------------------------------------------------------------------------- /docs/static/img/bg-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-go/HEAD/docs/static/img/bg-bottom.png -------------------------------------------------------------------------------- /docs/static/img/xrpl-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-go/HEAD/docs/static/img/xrpl-logo.png -------------------------------------------------------------------------------- /docs/static/img/xrpl-go-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XRPLF/xrpl-go/HEAD/docs/static/img/xrpl-go-logo.png -------------------------------------------------------------------------------- /pkg/crypto/types.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | type Algorithm interface { 4 | Prefix() byte 5 | FamilySeedPrefix() byte 6 | } 7 | -------------------------------------------------------------------------------- /xrpl/transaction/types/asset_scale.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | func AssetScale(value uint8) *uint8 { 4 | return &value 5 | } 6 | -------------------------------------------------------------------------------- /xrpl/transaction/types/expiration.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | func Expiration(value uint32) *uint32 { 4 | return &value 5 | } 6 | -------------------------------------------------------------------------------- /xrpl/transaction/types/holder.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | func Holder(address Address) *Address { 4 | return &address 5 | } 6 | -------------------------------------------------------------------------------- /xrpl/transaction/types/transfer_fee.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | func TransferFee(value uint16) *uint16 { 4 | return &value 5 | } 6 | -------------------------------------------------------------------------------- /xrpl/transaction/integration/types.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | const ( 4 | ErrInvalidTransaction = "invalidTransaction" 5 | ) 6 | -------------------------------------------------------------------------------- /xrpl/transaction/types/destination_tag.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | func DestinationTag(value uint32) *uint32 { 4 | return &value 5 | } 6 | -------------------------------------------------------------------------------- /xrpl/transaction/types/mptoken_metadata.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | func MPTokenMetadata(value string) *string { 4 | return &value 5 | } 6 | -------------------------------------------------------------------------------- /keypairs/testutil/mockgen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mockgen -source=interfaces/random.go -destination=testutil/random_mock.go -package=interfaces -------------------------------------------------------------------------------- /xrpl/transaction/types/address.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Address string 4 | 5 | func (a Address) String() string { 6 | return string(a) 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/transaction/types/hash128.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Hash128 string 4 | 5 | func (h *Hash128) String() string { 6 | return string(*h) 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/transaction/types/hash256.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Hash256 string 4 | 5 | func (h *Hash256) String() string { 6 | return string(*h) 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/transaction/types/nftoken.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type NFToken struct { 4 | NFTokenID NFTokenID 5 | NFTokenURI NFTokenURI `json:"URI"` 6 | } 7 | -------------------------------------------------------------------------------- /xrpl/queries/account/types/errors.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrNoAccountID = errors.New("no account ID specified") 7 | ) 8 | -------------------------------------------------------------------------------- /xrpl/websocket/interfaces/request.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | type Request interface { 4 | Method() string 5 | Validate() error 6 | APIVersion() int 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/queries/server/types/port.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type ServerPort struct { 4 | Port string `json:"port"` 5 | Protocol []string `json:"protocol"` 6 | } 7 | -------------------------------------------------------------------------------- /docs/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | open-pull-requests-limit: 10 -------------------------------------------------------------------------------- /xrpl/queries/version/api.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | // Defines the API versions supported by the Ripple API. 4 | 5 | const ( 6 | RippledAPIV1 int = 1 7 | RippledAPIV2 int = 2 8 | ) 9 | -------------------------------------------------------------------------------- /xrpl/transaction/types/message_key.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Public key for sending encrypted messages to this account. 4 | func MessageKey(value string) *string { 5 | return &value 6 | } 7 | -------------------------------------------------------------------------------- /binary-codec/serdes/interfaces/field_id_codec.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | type FieldIDCodec interface { 4 | Encode(fieldName string) ([]byte, error) 5 | Decode(h string) (string, error) 6 | } 7 | -------------------------------------------------------------------------------- /xrpl/queries/oracle/types/oracle.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Oracle struct { 4 | Account string `json:"account"` 5 | OracleDocumentID interface{} `json:"oracle_document_id"` 6 | } 7 | -------------------------------------------------------------------------------- /xrpl/hash/errors.go: -------------------------------------------------------------------------------- 1 | package hash 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrNonSignedTransaction = errors.New("transaction must have at least one of TxnSignature, Signers, or SigningPubKey") 7 | ) 8 | -------------------------------------------------------------------------------- /xrpl/queries/server/types/feature.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type FeatureStatus struct { 4 | Enabled bool `json:"enabled"` 5 | Name string `json:"name"` 6 | Supported bool `json:"supported"` 7 | } 8 | -------------------------------------------------------------------------------- /keypairs/interfaces/random.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | // Randomizer is an interface that defines the methods for a randomizer. 4 | type Randomizer interface { 5 | GenerateBytes(n int) ([]byte, error) 6 | } 7 | -------------------------------------------------------------------------------- /docs/docs/xrpl/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "xrpl", 3 | "position": 6, 4 | "link": { 5 | "description": "Here you can find the documentation for the xrpl package, including its subpackages." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/transaction/types/wallet_size.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // (Optional) Not used. This field is valid in AccountSet transactions but does nothing. 4 | func WalletSize(value uint32) *uint32 { 5 | return &value 6 | } 7 | -------------------------------------------------------------------------------- /xrpl/transaction/types/nftoken_id.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type NFTokenID Hash256 4 | 5 | // String returns the string representation of a NFTokenID. 6 | func (n *NFTokenID) String() string { 7 | return string(*n) 8 | } 9 | -------------------------------------------------------------------------------- /xrpl/queries/oracle/types/set.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Set struct { 4 | Mean string `json:"mean"` 5 | Size uint32 `json:"size"` 6 | StandardDeviation string `json:"standard_deviation"` 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/transaction/types/nftoken_uri.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type NFTokenURI string 4 | 5 | // String returns the string representation of a NFTokenURI. 6 | func (n *NFTokenURI) String() string { 7 | return string(*n) 8 | } 9 | -------------------------------------------------------------------------------- /xrpl/rpc/types/client_options.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/wallet" 5 | ) 6 | 7 | type SubmitOptions struct { 8 | Autofill bool 9 | Wallet *wallet.Wallet 10 | FailHard bool 11 | } 12 | -------------------------------------------------------------------------------- /xrpl/transaction/types/domain.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // The domain that owns this account, as a string of hex representing the. 4 | // ASCII for the domain in lowercase. 5 | func Domain(value string) *string { 6 | return &value 7 | } 8 | -------------------------------------------------------------------------------- /docs/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /pkg/crypto/sha512.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import "crypto/sha512" 4 | 5 | // Returns the first 32 bytes of a sha512 hash of a message 6 | func Sha512Half(msg []byte) []byte { 7 | h := sha512.Sum512(msg) 8 | return h[:32] 9 | } 10 | -------------------------------------------------------------------------------- /xrpl/websocket/types/client_options.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/wallet" 5 | ) 6 | 7 | type SubmitOptions struct { 8 | Autofill bool 9 | Wallet *wallet.Wallet 10 | FailHard bool 11 | } 12 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | }, 7 | "exclude": [".docusaurus", "build"] 8 | } 9 | -------------------------------------------------------------------------------- /xrpl/queries/account/v1/types/account_data.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" 4 | 5 | type AccountData struct { 6 | ledger.AccountRoot 7 | SignerLists []ledger.SignerList `json:"signer_lists,omitempty"` 8 | } 9 | -------------------------------------------------------------------------------- /binary-codec/types/hash128_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestNewHash128(t *testing.T) { 10 | hash := NewHash128() 11 | require.Equal(t, 16, hash.getLength()) 12 | } 13 | -------------------------------------------------------------------------------- /binary-codec/types/hash160_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestNewHash160(t *testing.T) { 10 | hash := NewHash160() 11 | require.Equal(t, 20, hash.getLength()) 12 | } 13 | -------------------------------------------------------------------------------- /binary-codec/types/hash192_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestNewHash192(t *testing.T) { 10 | hash := NewHash192() 11 | require.Equal(t, 24, hash.getLength()) 12 | } 13 | -------------------------------------------------------------------------------- /binary-codec/types/hash256_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestNewHash256(t *testing.T) { 10 | hash := NewHash256() 11 | require.Equal(t, 32, hash.getLength()) 12 | } 13 | -------------------------------------------------------------------------------- /xrpl/transaction/types/nftoken_minter.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Sets an alternate account that is allowed to mint NFTokens on this 4 | // account's behalf using NFTokenMint's `Issuer` field. 5 | func NFTokenMinter(value string) *string { 6 | return &value 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/did_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestDID_EntryType(t *testing.T) { 10 | did := &DID{} 11 | assert.Equal(t, did.EntryType(), DIDEntry) 12 | } 13 | -------------------------------------------------------------------------------- /xrpl/queries/path/types/ripple_path.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 4 | 5 | type RipplePathFindCurrency struct { 6 | Currency string `json:"currency"` 7 | Issuer types.Address `json:"issuer,omitempty"` 8 | } 9 | -------------------------------------------------------------------------------- /xrpl/transaction/types/email_hash.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // An arbitrary 128-bit value. Conventionally, clients treat this as the md5 hash of an email address to use for displaying a Gravatar image. 4 | func EmailHash(value Hash128) *Hash128 { 5 | return &value 6 | } 7 | -------------------------------------------------------------------------------- /xrpl/transaction/types/wallet_locator.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // (Optional) An arbitrary 256-bit value. If specified, the value is stored as part of the account but has no inherent meaning or requirements. 4 | func WalletLocator(value Hash256) *Hash256 { 5 | return &value 6 | } 7 | -------------------------------------------------------------------------------- /pkg/map_utils/map_utils.go: -------------------------------------------------------------------------------- 1 | package maputils 2 | 3 | // GetKeys returns the keys of the given map. 4 | func GetKeys(m map[string]interface{}) []string { 5 | keys := make([]string, 0, len(m)) 6 | for key := range m { 7 | keys = append(keys, key) 8 | } 9 | return keys 10 | } 11 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/bridge_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestBridge_EntryType(t *testing.T) { 10 | entry := &Bridge{} 11 | assert.Equal(t, BridgeEntry, entry.EntryType()) 12 | } 13 | -------------------------------------------------------------------------------- /xrpl/rpc/errors_test.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestClientError(t *testing.T) { 10 | err := &ClientError{ErrorString: "test error"} 11 | require.Equal(t, err.Error(), "test error") 12 | } 13 | -------------------------------------------------------------------------------- /binary-codec/types/hash192.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Hash192 struct represents a 192-bit hash. 4 | type Hash192 struct { 5 | hashI 6 | } 7 | 8 | // NewHash192 is a constructor for creating a new 192-bit hash. 9 | func NewHash192() *Hash192 { 10 | return &Hash192{newHash(24)} 11 | } 12 | -------------------------------------------------------------------------------- /binary-codec/types/errors.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "errors" 4 | 5 | var ( 6 | errNotValidJSON = errors.New("not a valid json") 7 | errDecodeClassicAddress = errors.New("unable to decode classic address") 8 | errReadBytes = errors.New("read bytes error") 9 | ) 10 | -------------------------------------------------------------------------------- /xrpl/interfaces/crypto.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import "github.com/Peersyst/xrpl-go/address-codec/interfaces" 4 | 5 | // CryptoImplementation is an interface that defines the methods for a crypto implementation. 6 | type CryptoImplementation interface { 7 | interfaces.CryptoImplementation 8 | } 9 | -------------------------------------------------------------------------------- /binary-codec/types/hash128.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Hash128 struct represents a 128-bit hash. 4 | type Hash128 struct { 5 | hashI 6 | } 7 | 8 | // NewHash128 is a constructor for creating a new 128-bit hash. 9 | func NewHash128() *Hash128 { 10 | return &Hash128{ 11 | newHash(16), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /binary-codec/types/hash160.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Hash160 struct represents a 160-bit hash. 4 | type Hash160 struct { 5 | hashI 6 | } 7 | 8 | // NewHash160 is a constructor for creating a new 160-bit hash. 9 | func NewHash160() *Hash160 { 10 | return &Hash160{ 11 | newHash(20), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /binary-codec/types/hash256.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Hash256 struct represents a 256-bit hash. 4 | type Hash256 struct { 5 | hashI 6 | } 7 | 8 | // NewHash256 is a constructor for creating a new 256-bit hash. 9 | func NewHash256() *Hash256 { 10 | return &Hash256{ 11 | newHash(32), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/src/components/LinkButton/styles.module.css: -------------------------------------------------------------------------------- 1 | .linkButton{ 2 | display: inline-block; 3 | padding: 1rem 2rem; 4 | background-color: var(--ifm-color-primary); 5 | color: white !important; 6 | border-radius: 8px; 7 | text-decoration: none; 8 | font-size: 1.2rem; 9 | font-weight: bold; 10 | } -------------------------------------------------------------------------------- /xrpl/queries/common/request.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | type BaseRequest struct { 4 | Version int `json:"api_version,omitempty"` 5 | } 6 | 7 | func (r *BaseRequest) APIVersion() int { 8 | return r.Version 9 | } 10 | 11 | func (r *BaseRequest) SetAPIVersion(apiVersion int) { 12 | r.Version = apiVersion 13 | } 14 | -------------------------------------------------------------------------------- /xrpl/queries/server/types/job.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type JobType struct { 4 | JobType string `json:"job_type"` 5 | PerSecond int `json:"per_second"` 6 | PeakTime int `json:"peak_time,omitempty"` 7 | AvgTime int `json:"avg_time,omitempty"` 8 | InProgress int `json:"in_progress,omitempty"` 9 | } 10 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/xchain_owned_claim_id_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestXChainOwnedClaimID_EntryType(t *testing.T) { 10 | entry := &XChainOwnedClaimID{} 11 | assert.Equal(t, XChainOwnedClaimIDEntry, entry.EntryType()) 12 | } 13 | -------------------------------------------------------------------------------- /xrpl/transaction/flat_tx.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | var _ Tx = (*FlatTransaction)(nil) 4 | 5 | type FlatTransaction map[string]interface{} 6 | 7 | func (f FlatTransaction) TxType() TxType { 8 | txType, ok := f["TransactionType"].(string) 9 | if !ok { 10 | return TxType("") 11 | } 12 | return TxType(txType) 13 | } 14 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /xrpl/transaction/types/ticksize.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // (Optional) Tick size to use for offers involving a currency issued by this address. 4 | // The exchange rates of those offers is rounded to this many significant digits. Valid values are 3 to 15 inclusive, or 0 to disable. 5 | func TickSize(value uint8) *uint8 { 6 | return &value 7 | } 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23-alpine AS install 2 | RUN apk add --no-cache make git ca-certificates 3 | 4 | WORKDIR /app 5 | COPY go.mod go.sum ./ 6 | RUN go mod download 7 | COPY . . 8 | 9 | FROM install AS lint 10 | RUN go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8 11 | RUN make lint 12 | 13 | FROM lint AS test 14 | RUN make test-ci -------------------------------------------------------------------------------- /xrpl/transaction/types/transfer_rate.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // (Optional) Sets the TransferRate. The fee to charge when users transfer this account's tokens, represented as billionths of a unit. 4 | // Cannot be more than 2000000000 or less than 1000000000, except for the special case 0 meaning no fee. 5 | func TransferRate(value uint32) *uint32 { 6 | return &value 7 | } 8 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/xchain_owned_create_account_claim_id_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestXChainOwnedCreateAccountClaimID_EntryType(t *testing.T) { 10 | entry := &XChainOwnedCreateAccountClaimID{} 11 | assert.Equal(t, XChainOwnedCreateAccountClaimIDEntry, entry.EntryType()) 12 | } 13 | -------------------------------------------------------------------------------- /binary-codec/types/interfaces/binary_serializer.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import "github.com/Peersyst/xrpl-go/binary-codec/definitions" 4 | 5 | // BinarySerializer is an interface that defines the methods for a binary serializer. 6 | type BinarySerializer interface { 7 | WriteFieldAndValue(fieldInstance definitions.FieldInstance, value []byte) error 8 | GetSink() []byte 9 | } 10 | -------------------------------------------------------------------------------- /xrpl/rpc/request.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | type Request struct { 4 | Method string `json:"method"` 5 | Params [1]interface{} `json:"params,omitempty"` 6 | } 7 | 8 | type APIVersionRequest interface { 9 | APIVersion() int 10 | SetAPIVersion(apiVersion int) 11 | } 12 | 13 | type XRPLRequest interface { 14 | APIVersionRequest 15 | Method() string 16 | Validate() error 17 | } 18 | -------------------------------------------------------------------------------- /address-codec/interfaces/crypto.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | // CryptoImplementation defines an interface for implementing cryptographic operations 4 | // required by address codec. 5 | type CryptoImplementation interface { 6 | DeriveKeypair(decodedSeed []byte, validator bool) (string, string, error) 7 | Sign(msg, privKey string) (string, error) 8 | Validate(msg, pubkey, sig string) bool 9 | } 10 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/types/state.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" 4 | 5 | type State struct { 6 | Data string `json:"data,omitempty"` 7 | LedgerEntryType ledger.EntryType `json:",omitempty"` 8 | LedgerObject ledger.FlatLedgerObject `json:"-"` 9 | Index string `json:"index"` 10 | } 11 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/v1/types/state.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" 4 | 5 | type State struct { 6 | Data string `json:"data,omitempty"` 7 | LedgerEntryType ledger.EntryType `json:",omitempty"` 8 | LedgerObject ledger.FlatLedgerObject `json:"-"` 9 | Index string `json:"index"` 10 | } 11 | -------------------------------------------------------------------------------- /binary-codec/testutil/mockgen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mockgen -source=types/interfaces/binary_parser.go -destination=types/testutil/binary_parser_mock.go -package=testutil 4 | mockgen -source=serdes/interfaces/definitions.go -destination=serdes/testutil/definitions_mock.go -package=testutil 5 | mockgen -source=serdes/interfaces/field_id_codec.go -destination=serdes/testutil/field_id_codec_mock.go -package=testutil -------------------------------------------------------------------------------- /xrpl/transaction/types/issued_currency.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type IssuedCurrency struct { 4 | Currency string `json:"currency"` 5 | Issuer Address `json:"issuer"` 6 | } 7 | 8 | func (i *IssuedCurrency) Flatten() map[string]interface{} { 9 | flattened := make(map[string]interface{}) 10 | flattened["currency"] = i.Currency 11 | flattened["issuer"] = i.Issuer.String() 12 | return flattened 13 | } 14 | -------------------------------------------------------------------------------- /xrpl/queries/server/types/fee_drops.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 4 | 5 | type FeeDrops struct { 6 | BaseFee types.XRPCurrencyAmount `json:"base_fee"` 7 | MedianFee types.XRPCurrencyAmount `json:"median_fee"` 8 | MinimumFee types.XRPCurrencyAmount `json:"minimum_fee"` 9 | OpenLedgerFee types.XRPCurrencyAmount `json:"open_ledger_fee"` 10 | } 11 | -------------------------------------------------------------------------------- /xrpl/queries/subscription/types/type.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Type string 4 | 5 | const ( 6 | LedgerStreamType Type = "ledgerClosed" 7 | ValidationStreamType Type = "validationReceived" 8 | TransactionStreamType Type = "transaction" 9 | PeerStatusStreamType Type = "peerStatusChange" 10 | OrderBookStreamType Type = TransactionStreamType 11 | ConsensusStreamType Type = "consensusPhase" 12 | ) 13 | -------------------------------------------------------------------------------- /xrpl/queries/subscription/v1/types/type.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Type string 4 | 5 | const ( 6 | LedgerStreamType Type = "ledgerClosed" 7 | ValidationStreamType Type = "validationReceived" 8 | TransactionStreamType Type = "transaction" 9 | PeerStatusStreamType Type = "peerStatusChange" 10 | OrderBookStreamType Type = TransactionStreamType 11 | ConsensusStreamType Type = "consensusPhase" 12 | ) 13 | -------------------------------------------------------------------------------- /xrpl/wallet/types/batch_account_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestBatchAccount_String(t *testing.T) { 10 | value := "r9cZA1mLK5R5Am25ArfXFmqgNQW4RdFp" 11 | empty := BatchAccount{} 12 | ba := BatchAccount{ 13 | value: value, 14 | } 15 | 16 | require.Equal(t, empty.String(), "") 17 | require.Equal(t, ba.String(), value) 18 | } 19 | -------------------------------------------------------------------------------- /xrpl/queries/server/types/fee_levels.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 4 | 5 | type FeeLevels struct { 6 | MedianLevel types.XRPCurrencyAmount `json:"median_level"` 7 | MinimumLevel types.XRPCurrencyAmount `json:"minimum_level"` 8 | OpenLedgerLevel types.XRPCurrencyAmount `json:"open_ledger_level"` 9 | ReferenceLevel types.XRPCurrencyAmount `json:"reference_level"` 10 | } 11 | -------------------------------------------------------------------------------- /xrpl/transaction/nftoken_mint_metadata.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 5 | ) 6 | 7 | type NFTokenMintMetadata struct { 8 | TxObjMeta 9 | // rippled 1.11.0 or later 10 | NFTokenID *types.NFTokenID `json:"nftoken_id,omitempty"` 11 | // if Amount is present 12 | OfferID *types.Hash256 `json:"offer_id,omitempty"` 13 | } 14 | 15 | func (NFTokenMintMetadata) TxMeta() {} 16 | -------------------------------------------------------------------------------- /xrpl/transaction/types/credential_ids.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/pkg/typecheck" 4 | 5 | type CredentialIDs []string 6 | 7 | func (c CredentialIDs) IsValid() bool { 8 | if len(c) == 0 { 9 | return false 10 | } 11 | 12 | for _, id := range c { 13 | if !typecheck.IsHex(id) { 14 | return false 15 | } 16 | } 17 | 18 | return true 19 | } 20 | 21 | func (c CredentialIDs) Flatten() []string { 22 | return c 23 | } 24 | -------------------------------------------------------------------------------- /binary-codec/definitions/field_instance_test.go: -------------------------------------------------------------------------------- 1 | package definitions 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestDefinitions_CreateFieldHeader(t *testing.T) { 10 | loadDefinitions() 11 | require.Equal(t, FieldHeader{ 12 | TypeCode: 1, 13 | FieldCode: 2, 14 | }, Get().CreateFieldHeader(1, 2)) 15 | } 16 | 17 | func TestFieldInstanceMap_CodecDecodeSelf(t *testing.T) { 18 | loadDefinitions() 19 | } 20 | -------------------------------------------------------------------------------- /binary-codec/types/testutil/helpers.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "testing" 5 | 6 | definitions "github.com/Peersyst/xrpl-go/binary-codec/definitions" 7 | ) 8 | 9 | func GetFieldInstance(t *testing.T, fieldName string) definitions.FieldInstance { 10 | t.Helper() 11 | fi, err := definitions.Get().GetFieldInstanceByFieldName(fieldName) 12 | if err != nil { 13 | t.Fatalf("FieldInstance with FieldName %v", fieldName) 14 | } 15 | return *fi 16 | } 17 | -------------------------------------------------------------------------------- /docs/src/theme/SearchBar.tsx: -------------------------------------------------------------------------------- 1 | import React, {type ReactNode} from 'react'; 2 | import SearchBar from '@theme-original/SearchBar'; 3 | import type SearchBarType from '@theme/SearchBar'; 4 | import type {WrapperProps} from '@docusaurus/types'; 5 | 6 | type Props = WrapperProps; 7 | 8 | export default function SearchBarWrapper(props: Props): ReactNode { 9 | return ( 10 | <> 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /binary-codec/types/interfaces/binary_parser.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import "github.com/Peersyst/xrpl-go/binary-codec/definitions" 4 | 5 | // BinaryParser is an interface that defines the methods for a binary parser. 6 | type BinaryParser interface { 7 | ReadByte() (byte, error) 8 | ReadField() (*definitions.FieldInstance, error) 9 | Peek() (byte, error) 10 | ReadBytes(n int) ([]byte, error) 11 | HasMore() bool 12 | ReadVariableLength() (int, error) 13 | } 14 | -------------------------------------------------------------------------------- /xrpl/queries/server/types/ledger.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 4 | 5 | type ClosedLedger struct { 6 | Age uint `json:"age"` 7 | BaseFeeXRP float32 `json:"base_fee_xrp"` 8 | Hash types.Hash256 `json:"hash"` 9 | ReserveBaseXRP float32 `json:"reserve_base_xrp"` 10 | ReserveIncXRP float32 `json:"reserve_inc_xrp"` 11 | Seq uint `json:"seq"` 12 | } 13 | -------------------------------------------------------------------------------- /xrpl/transaction/types/credential.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Credential struct { 4 | // The issuer of the credential. 5 | Issuer Address 6 | // A hex-encoded value to identify the type of credential from the issuer. 7 | CredentialType CredentialType 8 | } 9 | 10 | func (c Credential) Flatten() map[string]interface{} { 11 | m := make(map[string]interface{}) 12 | m["Issuer"] = c.Issuer.String() 13 | m["CredentialType"] = c.CredentialType.String() 14 | return m 15 | } 16 | -------------------------------------------------------------------------------- /binary-codec/serdes/interfaces/definitions.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | import "github.com/Peersyst/xrpl-go/binary-codec/definitions" 4 | 5 | type Definitions interface { 6 | GetFieldNameByFieldHeader(fh definitions.FieldHeader) (string, error) 7 | GetFieldInstanceByFieldName(fieldName string) (*definitions.FieldInstance, error) 8 | GetFieldHeaderByFieldName(fieldName string) (*definitions.FieldHeader, error) 9 | CreateFieldHeader(typecode, fieldcode int32) definitions.FieldHeader 10 | } 11 | -------------------------------------------------------------------------------- /docs/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 996px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/ledger_current_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | // Ledger Current request has no fields to test 10 | 11 | func TestLedgerCurrentResponse(t *testing.T) { 12 | s := CurrentResponse{ 13 | LedgerCurrentIndex: 123, 14 | } 15 | j := `{ 16 | "ledger_current_index": 123 17 | }` 18 | 19 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 20 | t.Error(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/v1/ledger_current_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | // Ledger Current request has no fields to test 10 | 11 | func TestLedgerCurrentResponse(t *testing.T) { 12 | s := CurrentResponse{ 13 | LedgerCurrentIndex: 123, 14 | } 15 | j := `{ 16 | "ledger_current_index": 123 17 | }` 18 | 19 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 20 | t.Error(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /xrpl/queries/server/types/state_accounting.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type StateAccountingFinal struct { 4 | Disconnected InfoAccounting `json:"disconnected"` 5 | Connected InfoAccounting `json:"connected"` 6 | Full InfoAccounting `json:"full"` 7 | Syncing InfoAccounting `json:"syncing"` 8 | Tracking InfoAccounting `json:"tracking"` 9 | } 10 | 11 | type InfoAccounting struct { 12 | DurationUS string `json:"duration_us"` 13 | Transitions string `json:"transitions"` 14 | } 15 | -------------------------------------------------------------------------------- /xrpl/transaction/types/message_key_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestMessageKey(t *testing.T) { 10 | tests := []struct { 11 | input string 12 | expected string 13 | }{ 14 | {"testKey1", "testKey1"}, 15 | {"anotherKey", "anotherKey"}, 16 | {"", ""}, 17 | } 18 | 19 | for _, test := range tests { 20 | result := MessageKey(test.input) 21 | require.Equal(t, test.expected, *result) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /address-codec/sha256.go: -------------------------------------------------------------------------------- 1 | package addresscodec 2 | 3 | import ( 4 | "crypto/sha256" 5 | 6 | "github.com/decred/dcrd/crypto/ripemd160" 7 | ) 8 | 9 | // Returns byte slice of a double hashed given byte slice. 10 | // The given byte slice is SHA256 hashed, then the result is RIPEMD160 hashed. 11 | func Sha256RipeMD160(b []byte) []byte { 12 | sha256 := sha256.New() 13 | sha256.Write(b) 14 | 15 | ripemd160 := ripemd160.New() 16 | ripemd160.Write(sha256.Sum(nil)) 17 | 18 | return ripemd160.Sum(nil) 19 | } 20 | -------------------------------------------------------------------------------- /xrpl/common/constants.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "time" 4 | 5 | const ( 6 | // Ledger constants 7 | LedgerOffset uint32 = 20 8 | 9 | // Config constants 10 | DefaultHost = "localhost" 11 | DefaultMaxRetries = 10 12 | DefaultMaxReconnects = 3 13 | DefaultRetryDelay = 1 * time.Second 14 | DefaultFeeCushion float32 = 1.2 15 | DefaultMaxFeeXRP float32 = 2 16 | 17 | // 5 seconds default timeout 18 | DefaultTimeout = 5 * time.Second 19 | ) 20 | -------------------------------------------------------------------------------- /xrpl/queries/account/types/offer_result.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type OfferResultFlags uint 4 | 5 | type OfferResult struct { 6 | Flags OfferResultFlags `json:"flags"` 7 | Sequence uint `json:"seq"` 8 | // TakerGets types.CurrencyAmount `json:"taker_gets"` 9 | TakerGets any `json:"taker_gets"` 10 | // TakerPays types.CurrencyAmount `json:"taker_pays"` 11 | TakerPays any `json:"taker_pays"` 12 | Quality string `json:"quality"` 13 | Expiration uint `json:"expiration,omitempty"` 14 | } 15 | -------------------------------------------------------------------------------- /xrpl/queries/account/types/queue_transaction.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 4 | 5 | type QueueTransaction struct { 6 | AuthChange bool `json:"auth_change"` 7 | Fee types.XRPCurrencyAmount `json:"fee,omitempty"` 8 | FeeLevel types.XRPCurrencyAmount `json:"fee_level,omitempty"` 9 | MaxSpendDrops types.XRPCurrencyAmount `json:"max_spend_drops,omitempty"` 10 | Seq int `json:"seq,omitempty"` 11 | } 12 | -------------------------------------------------------------------------------- /docs/docs/xrpl/hash.md: -------------------------------------------------------------------------------- 1 | # hash 2 | 3 | ## Overview 4 | 5 | The `hash` package contains functions and types related to the XRPL hash types. Currently, it only contains the function `SignTxBlob` that hashes a signed transaction blob, which is mainly used for multisigning. 6 | 7 | ## Usage 8 | 9 | To import the package, you can use the following code: 10 | 11 | ```go 12 | import "github.com/Peersyst/xrpl-go/xrpl/hash" 13 | ``` 14 | 15 | ## API 16 | 17 | ```go 18 | func SignTxBlob(blob []byte, secret string) ([]byte, error) 19 | ``` -------------------------------------------------------------------------------- /xrpl/queries/subscription/types/consensus.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // The consensus stream sends consensusPhase messages when the consensus process changes phase. 4 | // The message contains the new phase of consensus the server is in. 5 | type ConsensusStream struct { 6 | // The value `consensusPhase` indicates this is from the consensus stream 7 | Type Type `json:"type"` 8 | // The new consensus phase the server is in. Possible values are `open`, `establish`, and `accepted`. 9 | Consensus string `json:"consensus"` 10 | } 11 | -------------------------------------------------------------------------------- /xrpl/queries/utility/v1/random_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestRandomResponse(t *testing.T) { 10 | s := RandomResponse{ 11 | Random: "8ED765AEBBD6767603C2C9375B2679AEC76E6A8133EF59F04F9FC1AAA70E41AF", 12 | } 13 | 14 | j := `{ 15 | "random": "8ED765AEBBD6767603C2C9375B2679AEC76E6A8133EF59F04F9FC1AAA70E41AF" 16 | }` 17 | 18 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 19 | t.Error(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /xrpl/queries/nft/types/nftoken_offer.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 5 | ) 6 | 7 | type NFTokenOffer struct { 8 | Amount any `json:"amount"` 9 | Flags uint `json:"flags"` 10 | NFTokenOfferIndex string `json:"nft_offer_index"` 11 | Owner types.Address `json:"owner"` 12 | Destination types.Address `json:"destination,omitempty"` 13 | Expiration int `json:"expiration,omitempty"` 14 | } 15 | -------------------------------------------------------------------------------- /xrpl/queries/subscription/v1/types/consensus.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // The consensus stream sends consensusPhase messages when the consensus process changes phase. 4 | // The message contains the new phase of consensus the server is in. 5 | type ConsensusStream struct { 6 | // The value `consensusPhase` indicates this is from the consensus stream 7 | Type Type `json:"type"` 8 | // The new consensus phase the server is in. Possible values are `open`, `establish`, and `accepted`. 9 | Consensus string `json:"consensus"` 10 | } 11 | -------------------------------------------------------------------------------- /xrpl/queries/utility/random_test.go: -------------------------------------------------------------------------------- 1 | package utility 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestRandomResponse(t *testing.T) { 10 | s := RandomResponse{ 11 | Random: "8ED765AEBBD6767603C2C9375B2679AEC76E6A8133EF59F04F9FC1AAA70E41AF", 12 | } 13 | 14 | j := `{ 15 | "random": "8ED765AEBBD6767603C2C9375B2679AEC76E6A8133EF59F04F9FC1AAA70E41AF" 16 | }` 17 | 18 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 19 | t.Error(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/ledger_closed_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | // Ledger closed request does not have any fields to test 10 | 11 | func TestLedgerClosedResponse(t *testing.T) { 12 | s := ClosedResponse{ 13 | LedgerHash: "abc", 14 | LedgerIndex: 123, 15 | } 16 | j := `{ 17 | "ledger_hash": "abc", 18 | "ledger_index": 123 19 | }` 20 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 21 | t.Error(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/v1/ledger_closed_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | // Ledger closed request does not have any fields to test 10 | 11 | func TestLedgerClosedResponse(t *testing.T) { 12 | s := ClosedResponse{ 13 | LedgerHash: "abc", 14 | LedgerIndex: 123, 15 | } 16 | j := `{ 17 | "ledger_hash": "abc", 18 | "ledger_index": 123 19 | }` 20 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 21 | t.Error(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/transaction/types/nftoken_minter_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestNFTokenMinter(t *testing.T) { 10 | tests := []struct { 11 | input string 12 | expected string 13 | }{ 14 | {"rExampleAddress1", "rExampleAddress1"}, 15 | {"rExampleAddress2", "rExampleAddress2"}, 16 | {"", ""}, 17 | } 18 | 19 | for _, test := range tests { 20 | result := NFTokenMinter(test.input) 21 | require.Equal(t, test.expected, *result) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/wallet/types/batch_account.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // BatchAccount is a type that represents a batch account. 4 | // It is used to sign a batch transaction. 5 | type BatchAccount struct { 6 | value string 7 | } 8 | 9 | // NewBatchAccount creates a new batch account. 10 | func NewBatchAccount(value string) *BatchAccount { 11 | return &BatchAccount{ 12 | value: value, 13 | } 14 | } 15 | 16 | // String returns the string representation of the batch account. 17 | func (b *BatchAccount) String() string { 18 | return b.value 19 | } 20 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/ledger_data_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestLedgerDataRequest(t *testing.T) { 11 | s := DataRequest{ 12 | LedgerIndex: common.Closed, 13 | Binary: true, 14 | Limit: 5, 15 | } 16 | j := `{ 17 | "ledger_index": "closed", 18 | "binary": true, 19 | "limit": 5 20 | }` 21 | if err := testutil.Serialize(t, s, j); err != nil { 22 | t.Error(err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/v1/ledger_data_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestLedgerDataRequest(t *testing.T) { 11 | s := DataRequest{ 12 | LedgerIndex: common.Closed, 13 | Binary: true, 14 | Limit: 5, 15 | } 16 | j := `{ 17 | "ledger_index": "closed", 18 | "binary": true, 19 | "limit": 5 20 | }` 21 | if err := testutil.Serialize(t, s, j); err != nil { 22 | t.Error(err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/src/components/LinkButton/index.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | import styles from './styles.module.css'; 3 | import clsx from 'clsx'; 4 | 5 | interface LinkButtonProps extends React.AnchorHTMLAttributes { 6 | children: ReactNode; 7 | className?: string; 8 | } 9 | 10 | export function LinkButton({ children, className, ...props }: LinkButtonProps): ReactNode { 11 | return ( 12 | 16 | {children} 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /xrpl/queries/account/v1/offers_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestAccountOffersRequest(t *testing.T) { 11 | s := OffersRequest{ 12 | Account: "abc", 13 | LedgerIndex: common.LedgerIndex(10), 14 | Marker: "123", 15 | } 16 | j := `{ 17 | "account": "abc", 18 | "ledger_index": 10, 19 | "marker": "123" 20 | }` 21 | if err := testutil.Serialize(t, s, j); err != nil { 22 | t.Error(err) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /xrpl/transaction/types/domain_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestDomain(t *testing.T) { 10 | tests := []struct { 11 | input string 12 | expected string 13 | }{ 14 | {"example.com", "example.com"}, 15 | {"testdomain.org", "testdomain.org"}, 16 | {"", ""}, 17 | } 18 | 19 | for _, test := range tests { 20 | result := Domain(test.input) 21 | require.Equal(t, test.expected, *result, "Domain(%s) = %s; expected %s", test.input, *result, test.expected) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/transaction/types/ticksize_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestTickSize(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | value uint8 13 | want uint8 14 | }{ 15 | {"Valid tick size 3", 3, 3}, 16 | {"Valid tick size 15", 15, 15}, 17 | {"Valid tick size 0", 0, 0}, 18 | } 19 | 20 | for _, tt := range tests { 21 | t.Run(tt.name, func(t *testing.T) { 22 | got := TickSize(tt.value) 23 | require.Equal(t, tt.want, *got) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /xrpl/queries/account/offers_test.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestAccountOffersRequest(t *testing.T) { 11 | s := OffersRequest{ 12 | Account: "abc", 13 | LedgerIndex: common.LedgerIndex(10), 14 | Marker: "123", 15 | } 16 | j := `{ 17 | "account": "abc", 18 | "ledger_index": 10, 19 | "marker": "123" 20 | }` 21 | if err := testutil.Serialize(t, s, j); err != nil { 22 | t.Error(err) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /docs/src/components/HeroSection/styles.module.css: -------------------------------------------------------------------------------- 1 | .heroSection { 2 | height: 100vh; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | justify-content: center; 7 | padding: 2rem; 8 | } 9 | 10 | .heroLogo { 11 | max-width: 300px; 12 | margin-bottom: 2rem; 13 | } 14 | 15 | .heroTitle { 16 | font-size: 3rem; 17 | margin-bottom: 1.5rem; 18 | text-align: center; 19 | } 20 | 21 | .heroDescription { 22 | font-size: 1.5rem; 23 | max-width: 800px; 24 | text-align: center; 25 | line-height: 1.6; 26 | margin-bottom: 2rem; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /xrpl/transaction/types/wallet_size_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestWalletSize(t *testing.T) { 10 | tests := []struct { 11 | input uint32 12 | expected uint32 13 | }{ 14 | {input: 0, expected: 0}, 15 | {input: 1, expected: 1}, 16 | {input: 100, expected: 100}, 17 | {input: 4294967295, expected: 4294967295}, // Max uint32 value 18 | } 19 | 20 | for _, test := range tests { 21 | result := WalletSize(test.input) 22 | require.Equal(t, test.expected, *result) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /xrpl/common/interfaces.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 4 | 5 | // FaucetProvider defines an interface for interacting with XRPL faucets. 6 | // Implementations of this interface can be used to fund wallets on different 7 | // XRPL networks (e.g., Devnet, Testnet) by requesting XRP from their respective faucets. 8 | type FaucetProvider interface { 9 | // FundWallet sends a request to the faucet to fund the specified wallet address. 10 | // It returns an error if the funding request fails. 11 | FundWallet(address types.Address) error 12 | } 13 | -------------------------------------------------------------------------------- /keypairs/interfaces/crypto.go: -------------------------------------------------------------------------------- 1 | package interfaces 2 | 3 | // KeypairCryptoAlg is an interface that defines the methods for a keypair crypto algorithm. 4 | type KeypairCryptoAlg interface { 5 | DeriveKeypair(decodedSeed []byte, validator bool) (string, string, error) 6 | Sign(msg, privKey string) (string, error) 7 | Validate(msg, pubkey, sig string) bool 8 | } 9 | 10 | // NodeDerivationCryptoAlg is an interface that defines the methods for a node derivation crypto algorithm. 11 | type NodeDerivationCryptoAlg interface { 12 | DerivePublicKeyFromPublicGenerator(pubKey []byte) ([]byte, error) 13 | } 14 | -------------------------------------------------------------------------------- /xrpl/transaction/types/transfer_fee_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestTransferFee(t *testing.T) { 10 | tests := []struct { 11 | input uint16 12 | expected uint16 13 | }{ 14 | {input: 0, expected: 0}, 15 | {input: 314, expected: 314}, 16 | {input: 50000, expected: 50000}, // Max transfer fee 17 | {input: 65535, expected: 65535}, // Max uint16 value 18 | } 19 | 20 | for _, test := range tests { 21 | result := TransferFee(test.input) 22 | require.Equal(t, test.expected, *result) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /xrpl/transaction/types/destination_tag_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestDestinationTag(t *testing.T) { 10 | tests := []struct { 11 | input uint32 12 | expected uint32 13 | }{ 14 | {input: 12345, expected: 12345}, 15 | {input: 0, expected: 0}, 16 | {input: 4294967295, expected: 4294967295}, 17 | } 18 | 19 | for _, test := range tests { 20 | result := DestinationTag(test.input) 21 | require.Equal(t, test.expected, *result, "DestinationTag(%d) = %d; expected %d", test.input, *result, test.expected) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/queries/account/types/nft.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 5 | ) 6 | 7 | const ( 8 | Burnable NFTokenFlag = 0x0001 9 | OnlyXRP NFTokenFlag = 0x0002 10 | Transferable NFTokenFlag = 0x0008 11 | ReservedFlag NFTokenFlag = 0x8000 12 | ) 13 | 14 | type NFTokenFlag uint32 15 | 16 | type NFT struct { 17 | Flags NFTokenFlag `json:",omitempty"` 18 | Issuer types.Address 19 | NFTokenID types.NFTokenID 20 | NFTokenTaxon uint 21 | URI types.NFTokenURI `json:",omitempty"` 22 | NFTSerial uint `json:"nft_serial"` 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/transaction/types/flags.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "math/big" 4 | 5 | // Perform bitwise AND (&) to check if a flag is enabled within Flags (as a number). 6 | // @param Flags - A number that represents flags enabled. 7 | // @param checkFlag - A specific flag to check if it's enabled within Flags. 8 | // @returns True if checkFlag is enabled within Flags. 9 | func IsFlagEnabled(flags, checkFlag uint32) bool { 10 | flagsBigInt := new(big.Int).SetUint64(uint64(flags)) 11 | checkFlagBigInt := new(big.Int).SetUint64(uint64(checkFlag)) 12 | return new(big.Int).And(flagsBigInt, checkFlagBigInt).Cmp(checkFlagBigInt) == 0 13 | } 14 | -------------------------------------------------------------------------------- /xrpl/transaction/types/expiration_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestExpiration(t *testing.T) { 10 | tests := []struct { 11 | input uint32 12 | expected uint32 13 | }{ 14 | {input: 0, expected: 0}, 15 | {input: 1234567890, expected: 1234567890}, 16 | {input: 946684800, expected: 946684800}, // Year 2000 timestamp 17 | {input: 4294967295, expected: 4294967295}, // Max uint32 value 18 | } 19 | 20 | for _, test := range tests { 21 | result := Expiration(test.input) 22 | require.Equal(t, test.expected, *result) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /xrpl/queries/account/types/queue_data.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 4 | 5 | type QueueData struct { 6 | TxnCount uint64 `json:"txn_count"` 7 | AuthChangeQueued bool `json:"auth_change_queued,omitempty"` 8 | LowestSequence uint64 `json:"lowest_sequence,omitempty"` 9 | HighestSequence uint64 `json:"highest_sequence,omitempty"` 10 | MaxSpendDropsTotal types.XRPCurrencyAmount `json:"max_spend_drops_total,omitempty"` 11 | Transactions []QueueTransaction `json:"transactions,omitempty"` 12 | } 13 | -------------------------------------------------------------------------------- /xrpl/queries/account/objects_test.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestAccountObjectsRequest(t *testing.T) { 11 | s := ObjectsRequest{ 12 | Account: "rsuHaTvJh1bDmDoxX9QcKP7HEBSBt4XsHx", 13 | Type: SignerListObject, 14 | LedgerIndex: common.LedgerIndex(123), 15 | } 16 | 17 | j := `{ 18 | "account": "rsuHaTvJh1bDmDoxX9QcKP7HEBSBt4XsHx", 19 | "type": "signer_list", 20 | "ledger_index": 123 21 | }` 22 | if err := testutil.Serialize(t, s, j); err != nil { 23 | t.Error(err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /xrpl/queries/account/v1/objects_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestAccountObjectsRequest(t *testing.T) { 11 | s := ObjectsRequest{ 12 | Account: "rsuHaTvJh1bDmDoxX9QcKP7HEBSBt4XsHx", 13 | Type: SignerListObject, 14 | LedgerIndex: common.LedgerIndex(123), 15 | } 16 | 17 | j := `{ 18 | "account": "rsuHaTvJh1bDmDoxX9QcKP7HEBSBt4XsHx", 19 | "type": "signer_list", 20 | "ledger_index": 123 21 | }` 22 | if err := testutil.Serialize(t, s, j); err != nil { 23 | t.Error(err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/workflows/xrpl-go-ci-lint-test.yml: -------------------------------------------------------------------------------- 1 | name: XRPL-GO Lint and Test 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ '**' ] 7 | jobs: 8 | build: 9 | name: Lint and Test 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-go@v3 14 | with: 15 | go-version: '1.23' 16 | cache: true 17 | 18 | - name: Install golangci-lint 19 | run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8 20 | 21 | - name: Run linter 22 | run: make lint 23 | 24 | - name: Run tests 25 | run: make test-ci -------------------------------------------------------------------------------- /xrpl/hash/constants.go: -------------------------------------------------------------------------------- 1 | package hash 2 | 3 | // Prefix for hashing functions. 4 | // 5 | // These prefixes are inserted before the source material used to 6 | // generate various hashes. This is done to put each hash in its own 7 | // "space." This way, two different types of objects with the 8 | // same binary data will produce different hashes. 9 | // 10 | // Each prefix is a 4-byte value with the last byte set to zero 11 | // and the first three bytes formed from the ASCII equivalent of 12 | // some arbitrary string. For example "TXN". 13 | 14 | const ( 15 | // Transaction plus signature to give transaction ID 'TXN' 16 | TransactionPrefix uint32 = 0x54584E00 17 | ) 18 | -------------------------------------------------------------------------------- /xrpl/transaction/types/email_hash_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestEmailHash(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | input Hash128 13 | want Hash128 14 | }{ 15 | { 16 | name: "ValidHash", 17 | input: Hash128("validCustomHash"), 18 | want: Hash128("validCustomHash"), 19 | }, 20 | { 21 | name: "EmptyHash", 22 | input: "", 23 | want: "", 24 | }, 25 | } 26 | 27 | for _, tt := range tests { 28 | t.Run(tt.name, func(t *testing.T) { 29 | result := EmailHash(tt.input) 30 | require.Equal(t, tt.want, *result) 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /xrpl/queries/path/path_find_test.go: -------------------------------------------------------------------------------- 1 | package path 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestPathFindCloseRequest(t *testing.T) { 10 | s := FindCloseRequest{ 11 | Subcommand: Close, 12 | } 13 | 14 | j := `{ 15 | "subcommand": "close" 16 | }` 17 | 18 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 19 | t.Error(err) 20 | } 21 | } 22 | 23 | func TestPathFindStatusRequest(t *testing.T) { 24 | s := FindStatusRequest{ 25 | Subcommand: Status, 26 | } 27 | 28 | j := `{ 29 | "subcommand": "status" 30 | }` 31 | 32 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 33 | t.Error(err) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /xrpl/queries/path/v1/path_find_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestPathFindCloseRequest(t *testing.T) { 10 | s := FindCloseRequest{ 11 | Subcommand: Close, 12 | } 13 | 14 | j := `{ 15 | "subcommand": "close" 16 | }` 17 | 18 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 19 | t.Error(err) 20 | } 21 | } 22 | 23 | func TestPathFindStatusRequest(t *testing.T) { 24 | s := FindStatusRequest{ 25 | Subcommand: Status, 26 | } 27 | 28 | j := `{ 29 | "subcommand": "status" 30 | }` 31 | 32 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 33 | t.Error(err) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /xrpl/transaction/types/flags_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestIsFlagEnabled(t *testing.T) { 8 | var flags uint32 9 | const flag1 = 0x00010000 10 | const flag2 = 0x00020000 11 | 12 | setup := func() { 13 | flags = 0x00000000 14 | } 15 | 16 | t.Run("verifies a flag is enabled", func(t *testing.T) { 17 | setup() 18 | flags |= flag1 | flag2 19 | if !IsFlagEnabled(flags, flag1) { 20 | t.Errorf("expected flag1 to be enabled") 21 | } 22 | }) 23 | 24 | t.Run("verifies a flag is not enabled", func(t *testing.T) { 25 | setup() 26 | flags |= flag2 27 | if IsFlagEnabled(flags, flag1) { 28 | t.Errorf("expected flag1 to be not enabled") 29 | } 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /xrpl/queries/path/types/path.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction" 5 | ) 6 | 7 | type Alternative struct { 8 | PathsComputed [][]transaction.PathStep `json:"paths_computed"` 9 | // SourceAmount types.CurrencyAmount `json:"source_amount"` 10 | SourceAmount any `json:"source_amount"` 11 | // DestinationAmount types.CurrencyAmount `json:"destination_amount,omitempty"` 12 | DestinationAmount any `json:"destination_amount,omitempty"` 13 | } 14 | 15 | type RippleAlternative struct { 16 | PathsComputed [][]transaction.PathStep `json:"paths_computed"` 17 | // SourceAmount types.CurrencyAmount `json:"source_amount"` 18 | SourceAmount any `json:"source_amount"` 19 | } 20 | -------------------------------------------------------------------------------- /xrpl/transaction/path_step.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 5 | ) 6 | 7 | type PathStep struct { 8 | Account types.Address `json:"account,omitempty"` 9 | Currency string `json:"currency,omitempty"` 10 | Issuer types.Address `json:"issuer,omitempty"` 11 | } 12 | 13 | func (p *PathStep) Flatten() map[string]interface{} { 14 | flattened := make(map[string]interface{}) 15 | 16 | if p.Account != "" { 17 | flattened["account"] = p.Account.String() 18 | } 19 | 20 | if p.Currency != "" { 21 | flattened["currency"] = p.Currency 22 | } 23 | 24 | if p.Issuer != "" { 25 | flattened["issuer"] = p.Issuer.String() 26 | } 27 | 28 | return flattened 29 | 30 | } 31 | -------------------------------------------------------------------------------- /xrpl/transaction/types/nftoken_id_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "testing" 4 | 5 | func TestNFTokenIDString(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | nfTokenID NFTokenID 9 | want string 10 | }{ 11 | { 12 | name: "Empty NFTokenID", 13 | nfTokenID: NFTokenID(""), 14 | want: "", 15 | }, 16 | { 17 | name: "Non-empty NFTokenID", 18 | nfTokenID: NFTokenID("1234567890abcdef"), 19 | want: "1234567890abcdef", 20 | }, 21 | } 22 | 23 | for _, tt := range tests { 24 | t.Run(tt.name, func(t *testing.T) { 25 | if got := tt.nfTokenID.String(); got != tt.want { 26 | t.Errorf("NFTokenID.String(), got: %v but we want %v", got, tt.want) 27 | } 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /xrpl/transaction/types/wallet_locator_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestWalletLocator(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | value Hash256 13 | expected Hash256 14 | }{ 15 | { 16 | name: "Test with non-zero value", 17 | value: Hash256("locator1"), 18 | expected: Hash256("locator1"), 19 | }, 20 | { 21 | name: "Test with empty value", 22 | value: Hash256(""), 23 | expected: Hash256(""), 24 | }, 25 | } 26 | 27 | for _, tt := range tests { 28 | t.Run(tt.name, func(t *testing.T) { 29 | got := WalletLocator(tt.value) 30 | require.Equal(t, tt.expected, *got) 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - gofmt 4 | - govet 5 | # - dupl TODO: enable 6 | - gocritic 7 | - errcheck 8 | - staticcheck 9 | - ineffassign 10 | - typecheck 11 | - gosimple 12 | - misspell 13 | - unparam 14 | - unused 15 | - gosec 16 | - revive 17 | 18 | run: 19 | timeout: 1m 20 | tests: false 21 | 22 | issues: 23 | exclude-rules: 24 | - path: examples/ 25 | linters: 26 | - gosec 27 | - path: _test\.go 28 | linters: 29 | - errcheck 30 | - path: _mock\.go 31 | linters: 32 | - errcheck 33 | - unused 34 | 35 | output: 36 | formats: 37 | - format: colored-line-number 38 | print-issued-lines: true 39 | print-linter-name: true 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Specs** 27 | - OS: [e.g. iOS] 28 | - Project version [e.g. v1.x.x] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /xrpl/queries/account/v1/transactions_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestAccountTransactionsRequest(t *testing.T) { 11 | s := TransactionsRequest{ 12 | Account: "abc", 13 | LedgerIndexMin: 100, 14 | LedgerIndexMax: 120, 15 | LedgerHash: "def", 16 | LedgerIndex: common.LedgerIndex(10), 17 | Marker: "123", 18 | } 19 | 20 | j := `{ 21 | "account": "abc", 22 | "ledger_index_min": 100, 23 | "ledger_index_max": 120, 24 | "ledger_hash": "def", 25 | "ledger_index": 10, 26 | "marker": "123" 27 | }` 28 | 29 | if err := testutil.Serialize(t, s, j); err != nil { 30 | t.Error(err) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/fee_settings_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestFeeSettings(t *testing.T) { 10 | var s Object = &FeeSettings{ 11 | BaseFee: "000000000000000A", 12 | Flags: 0, 13 | LedgerEntryType: FeeSettingsEntry, 14 | ReferenceFeeUnits: 10, 15 | ReserveBase: 20000000, 16 | ReserveIncrement: 5000000, 17 | } 18 | 19 | j := `{ 20 | "Flags": 0, 21 | "LedgerEntryType": "FeeSettings", 22 | "BaseFee": "000000000000000A", 23 | "ReferenceFeeUnits": 10, 24 | "ReserveBase": 20000000, 25 | "ReserveIncrement": 5000000 26 | }` 27 | 28 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 29 | t.Error(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pkg/crypto/sha512_test.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestSha512Half(t *testing.T) { 10 | tt := []struct { 11 | description string 12 | input []byte 13 | expected []byte 14 | }{ 15 | { 16 | description: "hash of fakeRandomString", 17 | input: []byte{102, 97, 107, 101, 82, 97, 110, 100, 111, 109, 83, 116, 114, 105, 110, 103}, 18 | expected: []byte{187, 62, 202, 137, 133, 225, 72, 79, 166, 162, 140, 75, 48, 251, 0, 66, 162, 204, 93, 243, 236, 141, 195, 123, 95, 61, 18, 109, 223, 211, 202, 20}, 19 | }, 20 | } 21 | 22 | for _, tc := range tt { 23 | t.Run(tc.description, func(t *testing.T) { 24 | got := Sha512Half(tc.input) 25 | require.Equal(t, tc.expected, got) 26 | }) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /xrpl/websocket/types/message.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/subscription/types" 5 | ) 6 | 7 | // Message is a struct that represents a message from the websocket. 8 | // It contains every field that can be found in a websocket message. 9 | type Message struct { 10 | // Type field from all streams 11 | Type types.Type `json:"type"` 12 | // ID field from all websocket requests 13 | ID int `json:"id"` 14 | } 15 | 16 | // IsRequest returns true if the message has an ID. 17 | // This is true for all websocket requests. 18 | func (m *Message) IsRequest() bool { 19 | return m.ID != 0 20 | } 21 | 22 | // IsStream returns true if the message has a Type. 23 | // This is true for all websocket streams. 24 | func (m *Message) IsStream() bool { 25 | return m.Type != "" 26 | } 27 | -------------------------------------------------------------------------------- /docs/docs/xrpl/time.md: -------------------------------------------------------------------------------- 1 | # time 2 | 3 | ## Overview 4 | 5 | This package contains functions to handle with XRPL time conversions. It enables conversions between RippleTime and UnixTime. To learn more about RippleTime and UnixTime, you can read the 6 | [official documentation](https://xrpl.org/docs/references/protocol/data-types/basic-data-types#specifying-time). 7 | 8 | ## Usage 9 | 10 | To import the package, you can use the following code: 11 | 12 | ```go 13 | import "github.com/Peersyst/xrpl-go/xrpl/time" 14 | ``` 15 | 16 | ## API 17 | 18 | The following functions are available: 19 | 20 | ```go 21 | func RippleTimeToUnixTime(rpepoch int64) int64 22 | func UnixTimeToRippleTime(timestamp int64) int64 23 | func RippleTimeToISOTime(rippleTime int64) string 24 | func IsoTimeToRippleTime(isoTime string) (int64, error) 25 | ``` -------------------------------------------------------------------------------- /examples/ledger/rpc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/faucet" 7 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 8 | ledgerqueries "github.com/Peersyst/xrpl-go/xrpl/queries/ledger" 9 | "github.com/Peersyst/xrpl-go/xrpl/rpc" 10 | ) 11 | 12 | func main() { 13 | cfg, err := rpc.NewClientConfig( 14 | "https://s.altnet.rippletest.net:51234/", 15 | rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), 16 | ) 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | client := rpc.NewClient(cfg) 22 | 23 | ledger, err := client.GetLedger(&ledgerqueries.Request{ 24 | LedgerIndex: common.LedgerIndex(5115183), 25 | }) 26 | if err != nil { 27 | panic(err) 28 | } 29 | fmt.Println(ledger.Ledger.LedgerHash) 30 | fmt.Println(ledger.Ledger.LedgerIndex) 31 | } 32 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Title 2 | 3 | ## Description 4 | This PR aims to . (Mark tags that apply) 5 | 6 | ## Type of change 7 | - [ ] Bug fix 8 | - [ ] New feature 9 | - [ ] Breaking change 10 | - [ ] Documentation update 11 | - [ ] Refactoring 12 | 13 | ## Checklist: 14 | - [ ] My code follows the style guidelines of this project 15 | - [ ] I have performed a self-review of my own code 16 | - [ ] I have commented my code where needed 17 | - [ ] I have made corresponding changes to the documentation 18 | - [ ] My changes generate no new warnings 19 | - [ ] I have added tests that prove my fix is effective 20 | - [ ] New and existing unit tests pass locally with my changes 21 | 22 | ## Changes 23 | 24 | - Change 1 25 | - Change 2 26 | 27 | ## Notes (optional) 28 | 29 | Describe any additional notes here. 30 | -------------------------------------------------------------------------------- /pkg/random/main.go: -------------------------------------------------------------------------------- 1 | package random 2 | 3 | import ( 4 | "crypto/rand" 5 | "io" 6 | ) 7 | 8 | // Randomizer implements the io.Reader interface. A Randomizer can be used to generate random bytes. 9 | type Randomizer struct { 10 | io.Reader 11 | } 12 | 13 | // NewRandomizer returns a new Randomizer instance. It uses the crypto/rand package to generate random bytes. 14 | func NewRandomizer() Randomizer { 15 | return Randomizer{ 16 | Reader: rand.Reader, 17 | } 18 | } 19 | 20 | // GenerateBytes generates a n bytes slice of random bytes. It can return an error if the random bytes cannot be read. 21 | // For further information, see the io.Reader interface. 22 | func (r Randomizer) GenerateBytes(n int) ([]byte, error) { 23 | b := make([]byte, n) 24 | _, err := r.Read(b) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return b, nil 29 | } 30 | -------------------------------------------------------------------------------- /xrpl/queries/clio/nft_history_test.go: -------------------------------------------------------------------------------- 1 | package clio 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestNFTHistoryRequest(t *testing.T) { 10 | s := NFTHistoryRequest{ 11 | NFTokenID: "0000000000000000000000000000000000000000000000000000000000000000", 12 | LedgerIndexMin: 100, 13 | LedgerIndexMax: 200, 14 | Binary: true, 15 | Forward: true, 16 | Limit: 100, 17 | Marker: "marker", 18 | } 19 | 20 | j := `{ 21 | "nft_id": "0000000000000000000000000000000000000000000000000000000000000000", 22 | "ledger_index_min": 100, 23 | "ledger_index_max": 200, 24 | "binary": true, 25 | "forward": true, 26 | "limit": 100, 27 | "marker": "marker" 28 | }` 29 | 30 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 31 | t.Fatal(err) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /xrpl/queries/clio/v1/nft_history_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestNFTHistoryRequest(t *testing.T) { 10 | s := NFTHistoryRequest{ 11 | NFTokenID: "0000000000000000000000000000000000000000000000000000000000000000", 12 | LedgerIndexMin: 100, 13 | LedgerIndexMax: 200, 14 | Binary: true, 15 | Forward: true, 16 | Limit: 100, 17 | Marker: "marker", 18 | } 19 | 20 | j := `{ 21 | "nft_id": "0000000000000000000000000000000000000000000000000000000000000000", 22 | "ledger_index_min": 100, 23 | "ledger_index_max": 200, 24 | "binary": true, 25 | "forward": true, 26 | "limit": 100, 27 | "marker": "marker" 28 | }` 29 | 30 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 31 | t.Fatal(err) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/xrpl-go-docs-test-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Test deployment 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | # Review gh actions docs if you want to further define triggers, paths, etc 8 | # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on 9 | 10 | jobs: 11 | test-deploy: 12 | name: Test deployment 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - uses: actions/setup-node@v4 19 | working-directory: ./docs 20 | with: 21 | node-version: 18 22 | cache: yarn 23 | 24 | - name: Install dependencies 25 | working-directory: ./docs 26 | run: yarn install --frozen-lockfile 27 | - name: Test build website 28 | working-directory: ./docs 29 | run: yarn build -------------------------------------------------------------------------------- /xrpl/rpc/testutil/client_mock.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "net/http" 7 | ) 8 | 9 | type JSONRPCMockClient struct { 10 | DoFunc func(req *http.Request) (*http.Response, error) 11 | Spy *http.Request 12 | RequestCount int 13 | } 14 | 15 | func (m *JSONRPCMockClient) Do(req *http.Request) (*http.Response, error) { 16 | if m.DoFunc != nil { 17 | return m.DoFunc(req) 18 | } 19 | // just in case you want default correct return value 20 | return &http.Response{}, nil 21 | } 22 | 23 | func MockResponse(resString string, statusCode int, m *JSONRPCMockClient) func(req *http.Request) (*http.Response, error) { 24 | return func(req *http.Request) (*http.Response, error) { 25 | m.Spy = req 26 | return &http.Response{ 27 | StatusCode: statusCode, 28 | Body: io.NopCloser(bytes.NewReader([]byte(resString))), 29 | }, nil 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /xrpl/transaction/types/signer.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type Signer struct { 4 | SignerData SignerData `json:"Signer"` 5 | } 6 | 7 | func (s *Signer) Flatten() map[string]interface{} { 8 | flattened := make(map[string]interface{}) 9 | flattened["Signer"] = s.SignerData.Flatten() 10 | return flattened 11 | } 12 | 13 | type SignerData struct { 14 | Account Address 15 | TxnSignature string 16 | SigningPubKey string 17 | } 18 | 19 | type FlatSignerData map[string]interface{} 20 | 21 | func (sd *SignerData) Flatten() map[string]interface{} { 22 | flattened := make(map[string]interface{}) 23 | if sd.Account != "" { 24 | flattened["Account"] = sd.Account.String() 25 | } 26 | if sd.TxnSignature != "" { 27 | flattened["TxnSignature"] = sd.TxnSignature 28 | } 29 | if sd.SigningPubKey != "" { 30 | flattened["SigningPubKey"] = sd.SigningPubKey 31 | } 32 | return flattened 33 | } 34 | -------------------------------------------------------------------------------- /xrpl/transaction/types/memo.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type MemoWrapper struct { 4 | Memo Memo 5 | } 6 | 7 | type Memo struct { 8 | MemoData string `json:",omitempty"` 9 | MemoFormat string `json:",omitempty"` 10 | MemoType string `json:",omitempty"` 11 | } 12 | 13 | func (mw *MemoWrapper) Flatten() map[string]interface{} { 14 | if mw.Memo != (Memo{}) { 15 | flattened := make(map[string]interface{}) 16 | flattened["Memo"] = mw.Memo.Flatten() 17 | return flattened 18 | } 19 | return nil 20 | } 21 | 22 | func (m *Memo) Flatten() map[string]interface{} { 23 | flattened := make(map[string]interface{}) 24 | 25 | if m.MemoData != "" { 26 | flattened["MemoData"] = m.MemoData 27 | } 28 | 29 | if m.MemoFormat != "" { 30 | flattened["MemoFormat"] = m.MemoFormat 31 | } 32 | 33 | if m.MemoType != "" { 34 | flattened["MemoType"] = m.MemoType 35 | } 36 | 37 | return flattened 38 | } 39 | -------------------------------------------------------------------------------- /xrpl/transaction/types/transfer_rate_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestTransferRate(t *testing.T) { 10 | tests := []struct { 11 | name string 12 | value uint32 13 | want uint32 14 | }{ 15 | { 16 | name: "Valid transfer rate", 17 | value: 1500000000, 18 | want: 1500000000, 19 | }, 20 | { 21 | name: "Minimum transfer rate", 22 | value: 1000000000, 23 | want: 1000000000, 24 | }, 25 | { 26 | name: "Maximum transfer rate", 27 | value: 2000000000, 28 | want: 2000000000, 29 | }, 30 | { 31 | name: "No fee transfer rate", 32 | value: 0, 33 | want: 0, 34 | }, 35 | } 36 | 37 | for _, tt := range tests { 38 | t.Run(tt.name, func(t *testing.T) { 39 | result := TransferRate(tt.value) 40 | require.Equal(t, tt.want, *result) 41 | }) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /xrpl/testutil/integration/interfaces.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/transactions" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction" 7 | "github.com/Peersyst/xrpl-go/xrpl/wallet" 8 | ) 9 | 10 | type FaucetProvider interface { 11 | common.FaucetProvider 12 | } 13 | 14 | type Client interface { 15 | FaucetProvider() common.FaucetProvider 16 | 17 | FundWallet(wallet *wallet.Wallet) error 18 | Autofill(tx *transaction.FlatTransaction) error 19 | SubmitTxBlob(txBlob string, failHard bool) (*transactions.SubmitResponse, error) 20 | SubmitTxBlobAndWait(txBlob string, failHard bool) (*transactions.TxResponse, error) 21 | SubmitMultisigned(blob string, validate bool) (*transactions.SubmitMultisignedResponse, error) 22 | } 23 | 24 | type Connectable interface { 25 | Connect() error 26 | Disconnect() error 27 | } 28 | -------------------------------------------------------------------------------- /xrpl/queries/account/types/trust_line.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 5 | ) 6 | 7 | type TrustLine struct { 8 | Account types.Address `json:"account"` 9 | Balance string `json:"balance"` 10 | Currency string `json:"currency"` 11 | Limit string `json:"limit"` 12 | LimitPeer string `json:"limit_peer"` 13 | QualityIn uint `json:"quality_in"` 14 | QualityOut uint `json:"quality_out"` 15 | NoRipple bool `json:"no_ripple,omitempty"` 16 | NoRipplePeer bool `json:"no_ripple_peer,omitempty"` 17 | Authorized bool `json:"authorized,omitempty"` 18 | PeerAuthorized bool `json:"peer_authorized,omitempty"` 19 | Freeze bool `json:"freeze,omitempty"` 20 | FreezePeer bool `json:"freeze_peer,omitempty"` 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | # Go workspace file 18 | go.work 19 | 20 | # IDE-specific files 21 | .idea/ 22 | .vscode/ 23 | *.swp 24 | *.swo 25 | 26 | # OS-specific files 27 | .DS_Store 28 | Thumbs.db 29 | 30 | # Log files 31 | *.log 32 | 33 | # Binary output directory 34 | /bin/ 35 | 36 | # Environment variables file 37 | .env 38 | 39 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 40 | *.o 41 | *.a 42 | 43 | # Debug files 44 | debug 45 | 46 | # Project-specific build artifacts 47 | /build/ 48 | 49 | # Temporary files 50 | *.tmp 51 | *.temp 52 | 53 | # Coverage report 54 | coverage.html 55 | -------------------------------------------------------------------------------- /xrpl/faucet/devnet_test.go: -------------------------------------------------------------------------------- 1 | package faucet 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/pkg/crypto" 7 | "github.com/Peersyst/xrpl-go/xrpl/wallet" 8 | ) 9 | 10 | // Note: This test interacts with the actual Devnet faucet. 11 | // The result and behavior may vary based on the faucet's current state and rate limits. 12 | // Manual verification of the printed result is recommended. 13 | func TestDevnetFaucetProvider_FundWallet(t *testing.T) { 14 | 15 | // Create a new DevnetFaucetProvider 16 | provider := NewDevnetFaucetProvider() 17 | 18 | // Test wallet address 19 | testWallet, err := wallet.New(crypto.ED25519()) 20 | if err != nil { 21 | t.Errorf("Wallet creation error: %v", err) 22 | } 23 | 24 | // Call FundWallet 25 | err = provider.FundWallet(testWallet.ClassicAddress) 26 | 27 | // Check for errors 28 | if err != nil { 29 | t.Errorf("FundWallet returned an error: %v", err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /xrpl/faucet/testnet_test.go: -------------------------------------------------------------------------------- 1 | package faucet 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/pkg/crypto" 7 | "github.com/Peersyst/xrpl-go/xrpl/wallet" 8 | ) 9 | 10 | // Note: This test interacts with the actual Testnet faucet. 11 | // The result and behavior may vary based on the faucet's current state and rate limits. 12 | // Manual verification of the printed result is recommended. 13 | func TestTestnetFaucetProvider_FundWallet(t *testing.T) { 14 | 15 | // Create a new TestnetFaucetProvider 16 | provider := NewTestnetFaucetProvider() 17 | 18 | // Test wallet address 19 | testWallet, err := wallet.New(crypto.ED25519()) 20 | if err != nil { 21 | t.Errorf("Wallet creation error: %v", err) 22 | } 23 | 24 | // Call FundWallet 25 | err = provider.FundWallet(testWallet.ClassicAddress) 26 | 27 | // Check for errors 28 | if err != nil { 29 | t.Errorf("FundWallet returned an error: %v", err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /xrpl/wallet/types/batch_signable_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestBatchSignable_Flatten(t *testing.T) { 10 | tc := []struct { 11 | name string 12 | bs BatchSignable 13 | want map[string]interface{} 14 | }{ 15 | { 16 | name: "pass - empty batch signable", 17 | bs: BatchSignable{}, 18 | want: map[string]interface{}{ 19 | "flags": uint32(0), 20 | }, 21 | }, 22 | { 23 | name: "pass - batch signable with flags and txids", 24 | bs: BatchSignable{ 25 | Flags: 0, 26 | TxIDs: []string{"tx1", "tx2"}, 27 | }, 28 | want: map[string]interface{}{ 29 | "flags": uint32(0), 30 | "txIDs": []string{"tx1", "tx2"}, 31 | }, 32 | }, 33 | } 34 | 35 | for _, tt := range tc { 36 | t.Run(tt.name, func(t *testing.T) { 37 | got := tt.bs.Flatten() 38 | require.Equal(t, tt.want, got) 39 | }) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /docs/src/components/HeroSection/index.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | import styles from './styles.module.css'; 3 | import clsx from 'clsx'; 4 | 5 | interface HeroSectionProps { 6 | title: string; 7 | description: string; 8 | imageSrc: string; 9 | imageAlt: string; 10 | className?: string; 11 | children?: ReactNode; 12 | } 13 | 14 | export function HeroSection({ 15 | title, 16 | description, 17 | imageSrc, 18 | imageAlt, 19 | className, 20 | children 21 | }: HeroSectionProps): ReactNode { 22 | return ( 23 |
24 | {imageAlt} 29 |

30 | {title} 31 |

32 |

33 | {description} 34 |

35 | {children} 36 |
37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /pkg/random/main_test.go: -------------------------------------------------------------------------------- 1 | package random 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestRandomizer_GenerateBytes(t *testing.T) { 11 | testcases := []struct { 12 | name string 13 | input int 14 | expected []byte 15 | expectedErr error 16 | }{ 17 | { 18 | name: "pass - 0 bytes", 19 | input: 0, 20 | expected: []byte{}, 21 | }, 22 | { 23 | name: "pass - 10 bytes", 24 | input: 10, 25 | expected: make([]byte, 10), 26 | }, 27 | } 28 | 29 | for _, tc := range testcases { 30 | t.Run(tc.name, func(t *testing.T) { 31 | randomizer := NewRandomizer() 32 | bytes, err := randomizer.GenerateBytes(tc.input) 33 | fmt.Println(bytes) 34 | if tc.expectedErr != nil { 35 | require.Equal(t, tc.expectedErr, err) 36 | } 37 | if len(bytes) != tc.input { 38 | t.Errorf("expected %d bytes, got %d", tc.input, len(bytes)) 39 | } 40 | }) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /xrpl/transaction/types/nftoken_uri_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestNFTokenURI_String(t *testing.T) { 8 | tests := []struct { 9 | name string 10 | input NFTokenURI 11 | expected string 12 | }{ 13 | { 14 | name: "valid URI", 15 | input: NFTokenURI("https://example.com/nft/1"), 16 | expected: "https://example.com/nft/1", 17 | }, 18 | { 19 | name: "empty URI", 20 | input: NFTokenURI(""), 21 | expected: "", 22 | }, 23 | { 24 | name: "URI with special characters", 25 | input: NFTokenURI("https://example.com/nft/1?query=param&another=param"), 26 | expected: "https://example.com/nft/1?query=param&another=param", 27 | }, 28 | } 29 | 30 | for _, tt := range tests { 31 | t.Run(tt.name, func(t *testing.T) { 32 | if got := tt.input.String(); got != tt.expected { 33 | t.Errorf("NFTokenURI.String(), got: %v but we want: %v", got, tt.expected) 34 | } 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /xrpl/queries/account/types/channel_result.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 5 | ) 6 | 7 | type ChannelResult struct { 8 | Account types.Address `json:"account,omitempty"` 9 | Amount string `json:"amount,omitempty"` 10 | Balance string `json:"balance,omitempty"` 11 | ChannelID string `json:"channel_id,omitempty"` 12 | DestinationAccount types.Address `json:"destination_account,omitempty"` 13 | SettleDelay uint `json:"settle_delay,omitempty"` 14 | PublicKey string `json:"public_key,omitempty"` 15 | PublicKeyHex string `json:"public_key_hex,omitempty"` 16 | Expiration uint `json:"expiration,omitempty"` 17 | CancelAfter uint `json:"cancel_after,omitempty"` 18 | SourceTag uint `json:"source_tag,omitempty"` 19 | DestinationTag uint `json:"destination_tag,omitempty"` 20 | } 21 | -------------------------------------------------------------------------------- /docs/sidebars.ts: -------------------------------------------------------------------------------- 1 | import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; 2 | 3 | // This runs in Node.js - Don't use client-side code here (browser APIs, JSX...) 4 | 5 | /** 6 | * Creating a sidebar enables you to: 7 | - create an ordered group of docs 8 | - render a sidebar for each doc of that group 9 | - provide next/previous navigation 10 | 11 | The sidebars can be generated from the filesystem, or explicitly defined here. 12 | 13 | Create as many sidebars as you want. 14 | */ 15 | const sidebars: SidebarsConfig = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | }; 32 | 33 | export default sidebars; 34 | -------------------------------------------------------------------------------- /examples/queries/account-tx/rpc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/faucet" 7 | "github.com/Peersyst/xrpl-go/xrpl/queries/account" 8 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 9 | "github.com/Peersyst/xrpl-go/xrpl/rpc" 10 | ) 11 | 12 | func main() { 13 | cfg, err := rpc.NewClientConfig( 14 | "https://s.altnet.rippletest.net:51234/", 15 | rpc.WithMaxFeeXRP(5.0), 16 | rpc.WithFeeCushion(1.5), 17 | rpc.WithFaucetProvider(faucet.NewTestnetFaucetProvider()), 18 | ) 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | client := rpc.NewClient(cfg) 24 | 25 | txs, err := client.GetAccountTransactions(&account.TransactionsRequest{ 26 | Account: "rMCcNuTcajgw7YTgBy1sys3b89QqjUrMpH", 27 | LedgerIndex: common.LedgerIndex(4976692), 28 | }) 29 | if err != nil { 30 | fmt.Println(err) 31 | return 32 | } 33 | 34 | fmt.Println("Number of transactions:", len(txs.Transactions)) 35 | fmt.Println(txs.Transactions[0].Tx) 36 | } 37 | -------------------------------------------------------------------------------- /xrpl/transaction/did_delete.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | // ```json 4 | // 5 | // { 6 | // "TransactionType": "DIDDelete", 7 | // "Account": "rp4pqYgrTAtdPHuZd1ZQWxrzx45jxYcZex", 8 | // "Fee": "12", 9 | // "Sequence": 391, 10 | // "SigningPubKey":"0293A815C095DBA82FAC597A6BB9D338674DB93168156D84D18417AD509FFF5904", 11 | // "TxnSignature":"3044022011E9A7EE3C7AE9D202848390522E6840F7F3ED098CD13E..." 12 | // } 13 | // 14 | // ``` 15 | type DIDDelete struct { 16 | BaseTx 17 | } 18 | 19 | // TxType returns the type of the transaction. 20 | func (tx *DIDDelete) TxType() TxType { 21 | return DIDDeleteTx 22 | } 23 | 24 | // Flatten returns a flattened version of the transaction. 25 | func (tx *DIDDelete) Flatten() FlatTransaction { 26 | flattened := tx.BaseTx.Flatten() 27 | flattened["TransactionType"] = tx.TxType().String() 28 | return flattened 29 | } 30 | 31 | // Validate validates the transaction. 32 | func (tx *DIDDelete) Validate() (bool, error) { 33 | return tx.BaseTx.Validate() 34 | } 35 | -------------------------------------------------------------------------------- /xrpl/testutil/serializer.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "reflect" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func Deserialize(s interface{}, d string) error { 13 | decode := reflect.New(reflect.TypeOf(s)) 14 | err := json.Unmarshal([]byte(d), decode.Interface()) 15 | if err != nil { 16 | return err 17 | } 18 | if !reflect.DeepEqual(s, decode.Elem().Interface()) { 19 | return fmt.Errorf("json decoding does not match expected struct") 20 | } 21 | return nil 22 | 23 | } 24 | 25 | func Serialize(t *testing.T, s interface{}, d string) error { 26 | j, err := json.MarshalIndent(s, "", "\t") 27 | if err != nil { 28 | return err 29 | } 30 | require.Equal(t, d, string(j), "json encoding does not match expected string") 31 | return nil 32 | } 33 | 34 | func SerializeAndDeserialize(t *testing.T, s interface{}, d string) error { 35 | if err := Serialize(t, s, d); err != nil { 36 | return err 37 | } 38 | return Deserialize(s, d) 39 | } 40 | -------------------------------------------------------------------------------- /xrpl/transaction/oracle_delete.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | // Deletes a price oracle for the Account. 4 | // ```json 5 | // 6 | // { 7 | // "TransactionType": "OracleDelete", 8 | // "Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW", 9 | // "OracleDocumentID": 34 10 | // } 11 | // 12 | // ``` 13 | type OracleDelete struct { 14 | BaseTx 15 | // A unique identifier of the price oracle for the Account. By default, it is 0. 16 | OracleDocumentID uint32 17 | } 18 | 19 | // Returns the type of the transaction. 20 | func (tx *OracleDelete) TxType() TxType { 21 | return OracleDeleteTx 22 | } 23 | 24 | // Returns a flattened transaction. 25 | func (tx *OracleDelete) Flatten() FlatTransaction { 26 | flattened := tx.BaseTx.Flatten() 27 | 28 | flattened["TransactionType"] = tx.TxType().String() 29 | 30 | flattened["OracleDocumentID"] = tx.OracleDocumentID 31 | 32 | return flattened 33 | } 34 | 35 | // Validates the transaction. 36 | func (tx *OracleDelete) Validate() (bool, error) { 37 | return tx.BaseTx.Validate() 38 | } 39 | -------------------------------------------------------------------------------- /examples/ledger/ws/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/faucet" 7 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 8 | ledgerqueries "github.com/Peersyst/xrpl-go/xrpl/queries/ledger" 9 | "github.com/Peersyst/xrpl-go/xrpl/websocket" 10 | ) 11 | 12 | func main() { 13 | client := websocket.NewClient( 14 | websocket.NewClientConfig(). 15 | WithHost("wss://s.altnet.rippletest.net:51233"). 16 | WithFaucetProvider(faucet.NewTestnetFaucetProvider()), 17 | ) 18 | defer client.Disconnect() 19 | 20 | fmt.Println("⏳ Connecting to server...") 21 | if err := client.Connect(); err != nil { 22 | fmt.Println(err) 23 | return 24 | } 25 | 26 | fmt.Println("✅ Connected to server") 27 | fmt.Println() 28 | 29 | ledger, err := client.GetLedger(&ledgerqueries.Request{ 30 | LedgerIndex: common.LedgerIndex(5115183), 31 | }) 32 | if err != nil { 33 | fmt.Println(err) 34 | return 35 | } 36 | fmt.Println(ledger.Ledger.LedgerHash) 37 | fmt.Println(ledger.Ledger.LedgerIndex) 38 | } 39 | -------------------------------------------------------------------------------- /xrpl/websocket/connection_test.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestConnection_Connect(t *testing.T) { 10 | conn := NewConnection("wss://s.altnet.rippletest.net") 11 | err := conn.Connect() 12 | require.NoError(t, err) 13 | require.True(t, conn.IsConnected()) 14 | } 15 | 16 | func TestConnection_Disconnect(t *testing.T) { 17 | conn := NewConnection("wss://s.altnet.rippletest.net") 18 | err := conn.Connect() 19 | require.NoError(t, err) 20 | require.True(t, conn.IsConnected()) 21 | err = conn.Disconnect() 22 | require.NoError(t, err) 23 | require.False(t, conn.IsConnected()) 24 | } 25 | 26 | func TestConnection_IsConnected(t *testing.T) { 27 | conn := NewConnection("wss://s.altnet.rippletest.net") 28 | require.False(t, conn.IsConnected()) 29 | err := conn.Connect() 30 | require.NoError(t, err) 31 | require.True(t, conn.IsConnected()) 32 | err = conn.Disconnect() 33 | require.NoError(t, err) 34 | require.False(t, conn.IsConnected()) 35 | } 36 | -------------------------------------------------------------------------------- /keypairs/crypto.go: -------------------------------------------------------------------------------- 1 | package keypairs 2 | 3 | import ( 4 | "encoding/hex" 5 | "errors" 6 | 7 | "github.com/Peersyst/xrpl-go/keypairs/interfaces" 8 | "github.com/Peersyst/xrpl-go/pkg/crypto" 9 | ) 10 | 11 | var ( 12 | // Static errors 13 | 14 | // ErrInvalidCryptoImplementation is returned when the key does not match any crypto implementation. 15 | ErrInvalidCryptoImplementation = errors.New("not a valid crypto implementation") 16 | ) 17 | 18 | // GetCryptoImplementationFromKey returns the CryptoImplementation based on the key. 19 | // It returns nil if the key does not match any crypto implementation. 20 | // Currently, only ED25519 and SECP256K1 are supported. 21 | func getCryptoImplementationFromKey(k string) interfaces.KeypairCryptoAlg { 22 | prefix, err := hex.DecodeString(k[:2]) 23 | if err != nil { 24 | return nil 25 | } 26 | 27 | if ed25519 := crypto.ED25519(); prefix[0] == ed25519.Prefix() { 28 | return ed25519 29 | } 30 | if secp256k1 := crypto.SECP256K1(); prefix[0] == secp256k1.Prefix() { 31 | return secp256k1 32 | } 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /.github/workflows/xrpl-go-release.yml: -------------------------------------------------------------------------------- 1 | name: XRPL-GO Release 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | commit_branch: 6 | description: The branch or the commit sha to push tag to 7 | required: true 8 | tag: 9 | description: The tag of the release 10 | required: true 11 | is_pre_release: 12 | description: Is this a pre-release? 13 | type: boolean 14 | required: true 15 | jobs: 16 | release: 17 | runs-on: ubuntu-latest 18 | name: Release 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | ref: ${{ github.event.inputs.commit_branch }} 23 | fetch-depth: 0 24 | fetch-tags: true 25 | - name: Publish the Release 26 | uses: softprops/action-gh-release@v1 27 | with: 28 | tag_name: ${{ github.event.inputs.tag }} 29 | prerelease: github.event.inputs.is_pre_release 30 | target_commitish: ${{ github.event.inputs.commit_branch }} 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /xrpl/queries/clio/types/nft.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 6 | ) 7 | 8 | // NFToken is a struct that represents an NFToken. 9 | // It contains the information about the NFToken, such as the ID, 10 | // the ledger index, the owner, if it is burned, the flags, the transfer fee, 11 | // the issuer, the taxon, the sequence, the URI, and the URI JSON. 12 | type NFToken struct { 13 | NFTokenID types.NFTokenID `json:"nft_id"` 14 | LedgerIndex common.LedgerIndex `json:"ledger_index"` 15 | Owner types.Address `json:"owner"` 16 | IsBurned bool `json:"is_burned"` 17 | Flags uint `json:"flags"` 18 | TransferFee uint `json:"transfer_fee"` 19 | Issuer types.Address `json:"issuer"` 20 | NFTokenTaxon uint `json:"nft_taxon"` 21 | NFTokenSequence uint `json:"nft_sequence"` 22 | URI types.NFTokenURI `json:"uri,omitempty"` 23 | } 24 | -------------------------------------------------------------------------------- /xrpl/websocket/testutil/mock-webserver.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "net/http/httptest" 7 | "net/url" 8 | 9 | "github.com/gorilla/websocket" 10 | ) 11 | 12 | type MockWebSocketServer struct { 13 | Msgs []map[string]any 14 | } 15 | 16 | type connFn func(*websocket.Conn) 17 | 18 | func (ms *MockWebSocketServer) TestWebSocketServer(writeFunc connFn) *httptest.Server { 19 | var upgrader = websocket.Upgrader{} 20 | 21 | s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 22 | upgrader.CheckOrigin = func(_ *http.Request) bool { return true } 23 | c, err := upgrader.Upgrade(w, r, nil) 24 | if err != nil { 25 | log.Println("Upgrade:", err) 26 | } 27 | 28 | writeFunc(c) 29 | })) 30 | 31 | return s 32 | } 33 | 34 | func ConvertHTTPToWS(u string) (string, error) { 35 | s, err := url.Parse(u) 36 | if err != nil { 37 | return "", err 38 | } 39 | switch s.Scheme { 40 | case "http": 41 | s.Scheme = "ws" 42 | case "https": 43 | s.Scheme = "wss" 44 | } 45 | 46 | return s.String(), nil 47 | } 48 | -------------------------------------------------------------------------------- /xrpl/testutil/flatten.go: -------------------------------------------------------------------------------- 1 | package testutil 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | // Func to compare a flatten object and a JSON string 9 | func CompareFlattenAndExpected(flattened map[string]interface{}, expected []byte) error { 10 | // Convert flattened to JSON 11 | flattenedJSON, err := json.Marshal(flattened) 12 | if err != nil { 13 | return fmt.Errorf("error marshaling payment flattened, error: %v", err) 14 | } 15 | 16 | // Normalize expected JSON 17 | var expectedMap map[string]interface{} 18 | if err := json.Unmarshal([]byte(expected), &expectedMap); err != nil { 19 | return fmt.Errorf("error unmarshaling expected, error: %v", err) 20 | } 21 | expectedJSON, err := json.Marshal(expectedMap) 22 | if err != nil { 23 | return fmt.Errorf("error marshaling expected payment object: %v", err) 24 | } 25 | 26 | // Compare JSON strings 27 | if string(flattenedJSON) != string(expectedJSON) { 28 | return fmt.Errorf("the flattened and expected JSON are not equal.\nGot: %v\nExpected: %v", string(flattenedJSON), string(expectedJSON)) 29 | } 30 | 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /xrpl/transaction/types/credential_type.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/Peersyst/xrpl-go/pkg/typecheck" 4 | 5 | const ( 6 | // Minimum length of a credential type is 1 byte (1 byte = 2 hex characters). 7 | MinCredentialTypeLength = 2 8 | 9 | // Maximum length of a credential type is 64 bytes (1 byte = 2 hex characters). 10 | MaxCredentialTypeLength = 128 11 | ) 12 | 13 | type CredentialType string 14 | 15 | // String returns the string representation of a CredentialType. 16 | func (c *CredentialType) String() string { 17 | return string(*c) 18 | } 19 | 20 | // IsValidCredentialType checks if a credential type meets all the requirements: 21 | // - Not empty 22 | // - Valid hex string 23 | // - Length between MinCredentialTypeLength and MaxCredentialTypeLength 24 | func (c *CredentialType) IsValid() bool { 25 | if c.String() == "" { 26 | return false 27 | } 28 | 29 | credTypeStr := c.String() 30 | if !typecheck.IsHex(credTypeStr) { 31 | return false 32 | } 33 | 34 | length := len(credTypeStr) 35 | return length >= MinCredentialTypeLength && length <= MaxCredentialTypeLength 36 | } 37 | -------------------------------------------------------------------------------- /binary-codec/README.md: -------------------------------------------------------------------------------- 1 | # Binary Codec 2 | 3 | This package contains functions to encode/decode to/from the [ripple binary serialization format](https://xrpl.org/serialization.html). 4 | 5 | ## API 6 | 7 | ### Encode 8 | 9 | ```go 10 | encoded, err := binarycodec.Encode(jsonObject) 11 | ``` 12 | 13 | ### Decode 14 | 15 | ```go 16 | json, err := binarycodec.Decode(hexEncodedString) 17 | ``` 18 | ### EncodeForMultisigning 19 | 20 | ```go 21 | encoded, err := binarycodec.EncodeForMultisigning(jsonObject, xrpAccountID) 22 | ``` 23 | 24 | ### EncodeForSigning 25 | 26 | ```go 27 | encoded, err := binarycodec.EncodeForSigning(jsonObject) 28 | ``` 29 | 30 | ### EncodeForSigningClaim 31 | 32 | ```go 33 | encoded, err := binarycodec.EncodeForSigningClaim(jsonObject) 34 | ``` 35 | 36 | ### EncodeQuality 37 | 38 | ```go 39 | encoded, err := binarycodec.EncodeQuality(amountString) 40 | ``` 41 | 42 | ### DecodeQuality 43 | 44 | ```go 45 | decoded, err := binarycodec.DecodeQuality(encoded) 46 | ``` 47 | 48 | ### DecodeLedgerData 49 | 50 | ```go 51 | ledgerData, err := binarycodec.DecodeLedgerData(hexEncodedString) 52 | ``` 53 | -------------------------------------------------------------------------------- /.github/workflows/xrpl-go-ci-coverage.yml: -------------------------------------------------------------------------------- 1 | name: XRPL-GO Coverage 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ '**' ] 7 | jobs: 8 | build: 9 | name: Test Coverage 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-go@v3 14 | 15 | - name: Generate unit test coverage 16 | run: make coverage-unit 17 | 18 | - name: Check unit test coverage 19 | uses: vladopajic/go-test-coverage@v2 20 | with: 21 | # Configure action using config file (option 1) 22 | config: ./.testcoverage.yml 23 | 24 | # Configure action by specifying input parameters individually (option 2). 25 | # If you are using config file (option 1) you shouldn't use these parameters, however 26 | # specifing these action parameters will override appropriate config values. 27 | profile: coverage.out 28 | local-prefix: github.com/Peersyst/xrpl-go 29 | threshold-file: 0 30 | threshold-package: 0 31 | threshold-total: 0 -------------------------------------------------------------------------------- /xrpl/currency/native.go: -------------------------------------------------------------------------------- 1 | package currency 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | const ( 10 | DropsPerXrp float64 = 1000000 11 | MaxFractionLength uint = 6 12 | NativeCurrencySymbol string = "XRP" 13 | ) 14 | 15 | // Convert an amount in XRP to an amount in drops. 16 | func XrpToDrops(value string) (string, error) { 17 | if i := strings.IndexByte(value, '.'); i != -1 && len(value[i+1:]) > int(MaxFractionLength) { 18 | return "", errors.New("xrp to drops: value has too many decimals") 19 | } 20 | 21 | xrpFloat, err := strconv.ParseFloat(value, 64) 22 | if err != nil { 23 | return "", err 24 | } 25 | 26 | dropsFloat := xrpFloat * DropsPerXrp 27 | return strconv.FormatFloat(dropsFloat, 'f', -1, 64), nil 28 | 29 | } 30 | 31 | // Convert an amount of drops into an amount of xrp 32 | func DropsToXrp(value string) (string, error) { 33 | dropUint, err := strconv.ParseUint(value, 10, 64) 34 | if err != nil { 35 | return "", err 36 | } 37 | 38 | xrpFloat := float64(dropUint) / DropsPerXrp 39 | 40 | return strconv.FormatFloat(xrpFloat, 'f', -1, 64), nil 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Peersyst 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/ticket_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestTicket(t *testing.T) { 11 | var s Object = &Ticket{ 12 | Account: "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 13 | Flags: 0, 14 | LedgerEntryType: TicketEntry, 15 | OwnerNode: "0000000000000000", 16 | PreviousTxnID: "F19AD4577212D3BEACA0F75FE1BA1644F2E854D46E8D62E9C95D18E9708CBFB1", 17 | PreviousTxnLgrSeq: 4, 18 | TicketSequence: 3, 19 | } 20 | 21 | j := `{ 22 | "Account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 23 | "Flags": 0, 24 | "LedgerEntryType": "Ticket", 25 | "OwnerNode": "0000000000000000", 26 | "PreviousTxnID": "F19AD4577212D3BEACA0F75FE1BA1644F2E854D46E8D62E9C95D18E9708CBFB1", 27 | "PreviousTxnLgrSeq": 4, 28 | "TicketSequence": 3 29 | }` 30 | 31 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 32 | t.Error(err) 33 | } 34 | } 35 | 36 | func TestTicket_EntryType(t *testing.T) { 37 | s := &Ticket{} 38 | require.Equal(t, s.EntryType(), TicketEntry) 39 | } 40 | -------------------------------------------------------------------------------- /xrpl/queries/utility/ping.go: -------------------------------------------------------------------------------- 1 | package utility 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The ping command returns an acknowledgement, so that clients can test the 13 | // connection status and latency. 14 | type PingRequest struct { 15 | common.BaseRequest 16 | } 17 | 18 | func (*PingRequest) Method() string { 19 | return "ping" 20 | } 21 | 22 | func (*PingRequest) APIVersion() int { 23 | return version.RippledAPIV2 24 | } 25 | 26 | func (*PingRequest) Validate() error { 27 | return nil 28 | } 29 | 30 | // ############################################################################ 31 | // Response 32 | // ############################################################################ 33 | 34 | // The expected response from the ping method. 35 | type PingResponse struct { 36 | Role string `json:"role,omitempty"` 37 | Unlimited bool `json:"unlimited,omitempty"` 38 | } 39 | -------------------------------------------------------------------------------- /xrpl/queries/utility/v1/ping.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The ping command returns an acknowledgement, so that clients can test the 13 | // connection status and latency. 14 | type PingRequest struct { 15 | common.BaseRequest 16 | } 17 | 18 | func (*PingRequest) Method() string { 19 | return "ping" 20 | } 21 | 22 | func (*PingRequest) APIVersion() int { 23 | return version.RippledAPIV1 24 | } 25 | 26 | func (*PingRequest) Validate() error { 27 | return nil 28 | } 29 | 30 | // ############################################################################ 31 | // Response 32 | // ############################################################################ 33 | 34 | // The expected response from the ping method. 35 | type PingResponse struct { 36 | Role string `json:"role,omitempty"` 37 | Unlimited bool `json:"unlimited,omitempty"` 38 | } 39 | -------------------------------------------------------------------------------- /xrpl/transaction/types/credential_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestCredential_Flatten(t *testing.T) { 9 | tests := []struct { 10 | name string 11 | input Credential 12 | expected interface{} 13 | }{ 14 | { 15 | name: "pass - empty credential", 16 | input: Credential{ 17 | CredentialType: CredentialType(""), 18 | Issuer: "", 19 | }, 20 | expected: map[string]string{ 21 | "Issuer": "", 22 | "CredentialType": "", 23 | }, 24 | }, 25 | { 26 | name: "pass - valid credential", 27 | input: Credential{ 28 | CredentialType: CredentialType("0123"), 29 | Issuer: "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe", 30 | }, 31 | expected: map[string]string{ 32 | "Issuer": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe", 33 | "CredentialType": "0123", 34 | }, 35 | }, 36 | } 37 | 38 | for _, tt := range tests { 39 | t.Run(tt.name, func(t *testing.T) { 40 | result := tt.input.Flatten() 41 | if reflect.DeepEqual(result, tt.expected) { 42 | t.Errorf("Flatten() = %v, want %v", result, tt.expected) 43 | } 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /xrpl/websocket/errors.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import "errors" 4 | 5 | // Static errors 6 | var ( 7 | ErrMissingTxSignatureOrSigningPubKey = errors.New("transaction must have a TxSignature or SigningPubKey set") 8 | ErrMissingLastLedgerSequenceInTransaction = errors.New("missing LastLedgerSequence in transaction") 9 | ErrMissingWallet = errors.New("wallet must be provided when submitting an unsigned transaction") 10 | 11 | ErrRawTransactionsFieldIsNotAnArray = errors.New("RawTransactions field is not an array") 12 | ErrRawTransactionFieldIsNotAnObject = errors.New("RawTransaction field is not an object") 13 | 14 | ErrSigningPubKeyFieldMustBeEmpty = errors.New("SigningPubKey field must be empty") 15 | ErrTxnSignatureFieldMustBeEmpty = errors.New("TxnSignature field must be empty") 16 | ErrSignersFieldMustBeEmpty = errors.New("Signers field must be empty") 17 | ErrAccountFieldIsNotAString = errors.New("Account field is not a string") 18 | ) 19 | 20 | // Dynamic errors 21 | 22 | type ClientError struct { 23 | ErrorString string 24 | } 25 | 26 | func (e *ClientError) Error() string { 27 | return e.ErrorString 28 | } 29 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/negative_unl_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestNegativeUNL(t *testing.T) { 11 | var s Object = &NegativeUNL{ 12 | DisabledValidators: []DisabledValidatorEntry{ 13 | { 14 | DisabledValidator: DisabledValidator{ 15 | FirstLedgerSequence: 1609728, 16 | PublicKey: "ED6629D456285AE3613B285F65BBFF168D695BA3921F309949AFCD2CA7AFEC16FE", 17 | }, 18 | }, 19 | }, 20 | Flags: 0, 21 | LedgerEntryType: NegativeUNLEntry, 22 | } 23 | 24 | j := `{ 25 | "Flags": 0, 26 | "LedgerEntryType": "NegativeUNL", 27 | "DisabledValidators": [ 28 | { 29 | "DisabledValidator": { 30 | "FirstLedgerSequence": 1609728, 31 | "PublicKey": "ED6629D456285AE3613B285F65BBFF168D695BA3921F309949AFCD2CA7AFEC16FE" 32 | } 33 | } 34 | ] 35 | }` 36 | 37 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 38 | t.Error(err) 39 | } 40 | } 41 | 42 | func TestNegativeUNL_EntryType(t *testing.T) { 43 | s := &NegativeUNL{} 44 | require.Equal(t, s.EntryType(), NegativeUNLEntry) 45 | } 46 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/v1/ledger_current.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The ledger_current method returns the unique identifiers of the current 13 | // in-progress ledger. 14 | type CurrentRequest struct { 15 | common.BaseRequest 16 | } 17 | 18 | func (*CurrentRequest) Method() string { 19 | return "ledger_current" 20 | } 21 | 22 | func (*CurrentRequest) APIVersion() int { 23 | return version.RippledAPIV1 24 | } 25 | 26 | // TODO: Implement V2 27 | func (*CurrentRequest) Validate() error { 28 | return nil 29 | } 30 | 31 | // ############################################################################ 32 | // Response 33 | // ############################################################################ 34 | 35 | // The expected response from the ledger_current method. 36 | type CurrentResponse struct { 37 | LedgerCurrentIndex common.LedgerIndex `json:"ledger_current_index"` 38 | } 39 | -------------------------------------------------------------------------------- /xrpl/queries/utility/v1/random.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 7 | ) 8 | 9 | // ############################################################################ 10 | // Request 11 | // ############################################################################ 12 | 13 | // The random command provides a random number to be used as a source of 14 | // entropy for random number generation by clients. 15 | type RandomRequest struct { 16 | common.BaseRequest 17 | } 18 | 19 | func (*RandomRequest) Method() string { 20 | return "random" 21 | } 22 | 23 | func (*RandomRequest) APIVersion() int { 24 | return version.RippledAPIV1 25 | } 26 | 27 | func (*RandomRequest) Validate() error { 28 | return nil 29 | } 30 | 31 | // ############################################################################ 32 | // Response 33 | // ############################################################################ 34 | 35 | // The expected response from the random method. 36 | type RandomResponse struct { 37 | Random types.Hash256 `json:"random"` 38 | } 39 | -------------------------------------------------------------------------------- /binary-codec/serdes/field_id_codec_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package serdes 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/Peersyst/xrpl-go/binary-codec/definitions" 9 | ) 10 | 11 | // nolint 12 | func BenchmarkEncode(b *testing.B) { 13 | 14 | tt := []struct { 15 | input string 16 | }{ 17 | { 18 | input: "LedgerEntry", 19 | }, 20 | { 21 | input: "yurt", 22 | }, 23 | } 24 | 25 | codec := NewFieldIDCodec(definitions.Get()) 26 | for _, test := range tt { 27 | b.Run(fmt.Sprintf("input_name_%v", test.input), func(b *testing.B) { 28 | for i := 0; i < b.N; i++ { 29 | codec.Encode(test.input) 30 | } 31 | }) 32 | } 33 | } 34 | 35 | // nolint 36 | func BenchmarkDecode(b *testing.B) { 37 | 38 | tt := []struct { 39 | input []byte 40 | }{ 41 | { 42 | input: []byte{1, 18}, 43 | }, 44 | { 45 | input: []byte{255}, 46 | }, 47 | } 48 | 49 | codec := NewFieldIDCodec(definitions.Get()) 50 | for _, test := range tt { 51 | b.Run(fmt.Sprintf("input_name_%v", test.input), func(b *testing.B) { 52 | for i := 0; i < b.N; i++ { 53 | hex := hex.EncodeToString(test.input) 54 | codec.Decode(hex) 55 | } 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /binary-codec/types/uint32.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | 7 | "github.com/Peersyst/xrpl-go/binary-codec/types/interfaces" 8 | ) 9 | 10 | // UInt32 represents a 32-bit unsigned integer. 11 | type UInt32 struct{} 12 | 13 | // FromJSON converts a JSON value into a serialized byte slice representing a 32-bit unsigned integer. 14 | // The input value is assumed to be an integer. If the serialization fails, an error is returned. 15 | func (u *UInt32) FromJSON(value any) ([]byte, error) { 16 | buf := new(bytes.Buffer) 17 | err := binary.Write(buf, binary.BigEndian, value.(uint32)) 18 | 19 | if err != nil { 20 | return nil, err 21 | } 22 | return buf.Bytes(), nil 23 | } 24 | 25 | // ToJSON takes a BinaryParser and optional parameters, and converts the serialized byte data 26 | // back into a JSON integer value. This method assumes the parser contains data representing 27 | // a 32-bit unsigned integer. If the parsing fails, an error is returned. 28 | func (u *UInt32) ToJSON(p interfaces.BinaryParser, _ ...int) (any, error) { 29 | b, err := p.ReadBytes(4) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return binary.BigEndian.Uint32(b), nil 34 | } 35 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/ledger_current.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The ledger_current method returns the unique identifiers of the current 13 | // in-progress ledger. 14 | type CurrentRequest struct { 15 | common.BaseRequest 16 | } 17 | 18 | func (*CurrentRequest) Method() string { 19 | return "ledger_current" 20 | } 21 | 22 | func (*CurrentRequest) APIVersion() int { 23 | return version.RippledAPIV2 24 | } 25 | 26 | // TODO: Implement V2 27 | func (*CurrentRequest) Validate() error { 28 | return nil 29 | } 30 | 31 | // ############################################################################ 32 | // Response 33 | // ############################################################################ 34 | 35 | // The expected response from the ledger_current method. 36 | type CurrentResponse struct { 37 | LedgerCurrentIndex common.LedgerIndex `json:"ledger_current_index"` 38 | } 39 | -------------------------------------------------------------------------------- /xrpl/queries/utility/random.go: -------------------------------------------------------------------------------- 1 | package utility 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 7 | ) 8 | 9 | // ############################################################################ 10 | // Request 11 | // ############################################################################ 12 | 13 | // The random command provides a random number to be used as a source of 14 | // entropy for random number generation by clients. 15 | type RandomRequest struct { 16 | common.BaseRequest 17 | } 18 | 19 | func (*RandomRequest) Method() string { 20 | return "random" 21 | } 22 | 23 | func (*RandomRequest) APIVersion() int { 24 | return version.RippledAPIV2 25 | } 26 | 27 | func (*RandomRequest) Validate() error { 28 | return nil 29 | } 30 | 31 | // ############################################################################ 32 | // Response 33 | // ############################################################################ 34 | 35 | // The expected response from the random method. 36 | type RandomResponse struct { 37 | Random types.Hash256 `json:"random"` 38 | } 39 | -------------------------------------------------------------------------------- /docs/docs/xrpl/faucet.md: -------------------------------------------------------------------------------- 1 | # faucet 2 | 3 | ## Overview 4 | 5 | `faucet` is a package that allows the user to get XRP for testing purposes on **testnet** and **devnet** ledgers and even from custom chains. To be able to fund your accounts programmatically, you can initialize the desired `FaucetProvider` for the ledger you want to use. 6 | 7 | The package already exposes the `TestnetFaucetProvider` and `DevnetFaucetProvider` providers. If you want to use a custom chain, you can implement the `FaucetProvider` interface and use your own provider. 8 | 9 | ## Usage 10 | 11 | To import the package, you can use the following code: 12 | 13 | ```go 14 | import "github.com/Peersyst/xrpl-go/xrpl/faucet" 15 | ``` 16 | 17 | For devnet, you can use the following code: 18 | 19 | ```go 20 | devnetFaucet := faucet.NewDevnetFaucetProvider() 21 | 22 | err := devnetFaucet.FundWallet("rJ96831v5JXxna35JYvsW9VRmENwq23ib9") 23 | if err != nil { 24 | // ... 25 | } 26 | ``` 27 | 28 | for testnet, you can use the following code: 29 | 30 | ```go 31 | testnetFaucet := faucet.NewTestnetFaucetProvider() 32 | 33 | err := testnetFaucet.FundWallet("rJ96831v5JXxna35JYvsW9VRmENwq23ib9") 34 | if err != nil { 35 | // ... 36 | } 37 | ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enhancement 3 | about: Propose an enhancement 4 | title: "[ENH]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description 11 | [Provide a clear and detailed description of the proposed enhancement. Explain what it is, how it would work, and why it's needed.] 12 | 13 | ## Implementation Approaches 14 | 15 | ### Approach 1: [Name] 16 | - Technical details: 17 | - Required resources: 18 | - Timeline estimate: 19 | - Dependencies: 20 | 21 | ### Approach 2: [Name] 22 | - Technical details: 23 | - Required resources: 24 | - Timeline estimate: 25 | - Dependencies: 26 | 27 | ## Benefits and Use Cases 28 | 29 | ### Key Benefits 30 | - [Benefit 1] 31 | - [Benefit 2] 32 | - [Benefit 3] 33 | 34 | ### Use Cases 35 | 1. **[Primary Use Case]** 36 | - Target users: 37 | - Problem solved: 38 | - Expected outcome: 39 | 40 | 2. **[Secondary Use Case]** 41 | - Target users: 42 | - Problem solved: 43 | - Expected outcome: 44 | 45 | ## Additional Considerations 46 | - Technical debt implications: 47 | - Maintenance requirements: 48 | - Security considerations: 49 | - Performance impact: 50 | 51 | ## Success Metrics 52 | - [Metric 1] 53 | - [Metric 2] 54 | -------------------------------------------------------------------------------- /address-codec/base58check.go: -------------------------------------------------------------------------------- 1 | package addresscodec 2 | 3 | import ( 4 | "crypto/sha256" 5 | ) 6 | 7 | // checksum: first four bytes of sha256^2 8 | func checksum(input []byte) (cksum [4]byte) { 9 | h := sha256.Sum256(input) 10 | h2 := sha256.Sum256(h[:]) 11 | copy(cksum[:], h2[:4]) 12 | return cksum 13 | } 14 | 15 | // CheckEncode prepends a version byte, appends a four byte checksum and returns 16 | // a base58 encoding of the byte slice. 17 | func Base58CheckEncode(input []byte, prefix ...byte) string { 18 | b := make([]byte, 0, 1+len(input)+4) 19 | b = append(b, prefix...) 20 | b = append(b, input...) 21 | 22 | cksum := checksum(b) 23 | b = append(b, cksum[:]...) 24 | return EncodeBase58(b) 25 | } 26 | 27 | // CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum. 28 | func Base58CheckDecode(input string) (result []byte, err error) { 29 | decoded := DecodeBase58(input) 30 | if len(decoded) < 5 { 31 | return nil, ErrInvalidFormat 32 | } 33 | 34 | var cksum [4]byte 35 | copy(cksum[:], decoded[len(decoded)-4:]) 36 | if checksum(decoded[:len(decoded)-4]) != cksum { 37 | return nil, ErrChecksum 38 | } 39 | 40 | result = decoded[:len(decoded)-4] 41 | return 42 | } 43 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/v1/ledger_closed.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The ledger_closed method returns the unique identifiers of the most recently 13 | // closed ledger. 14 | type ClosedRequest struct { 15 | common.BaseRequest 16 | } 17 | 18 | func (*ClosedRequest) Method() string { 19 | return "ledger_closed" 20 | } 21 | 22 | func (*ClosedRequest) APIVersion() int { 23 | return version.RippledAPIV1 24 | } 25 | 26 | // TODO: Implement V2 27 | func (*ClosedRequest) Validate() error { 28 | return nil 29 | } 30 | 31 | // ############################################################################ 32 | // Response 33 | // ############################################################################ 34 | 35 | // The expected response from the ledger_closed method. 36 | type ClosedResponse struct { 37 | LedgerHash string `json:"ledger_hash"` 38 | LedgerIndex common.LedgerIndex `json:"ledger_index"` 39 | } 40 | -------------------------------------------------------------------------------- /xrpl/queries/ledger/ledger_closed.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The ledger_closed method returns the unique identifiers of the most recently 13 | // closed ledger. 14 | type ClosedRequest struct { 15 | common.BaseRequest 16 | } 17 | 18 | func (*ClosedRequest) Method() string { 19 | return "ledger_closed" 20 | } 21 | 22 | func (*ClosedRequest) APIVersion() int { 23 | return version.RippledAPIV2 24 | } 25 | 26 | // TODO: Implement V2 27 | func (*ClosedRequest) Validate() error { 28 | return nil 29 | } 30 | 31 | // ############################################################################ 32 | // Response 33 | // ############################################################################ 34 | 35 | // The expected response from the ledger_closed method. 36 | type ClosedResponse struct { 37 | LedgerHash string `json:"ledger_hash"` 38 | LedgerIndex common.LedgerIndex `json:"ledger_index"` 39 | } 40 | -------------------------------------------------------------------------------- /xrpl/transaction/types/authorize_credential.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // Maximum number of accepted credentials. 8 | const MaxAcceptedCredentials int = 10 9 | 10 | var ( 11 | // Credential-specific errors 12 | 13 | ErrInvalidCredentialType = errors.New("invalid credential type, must be a hexadecimal string between 1 and 64 bytes") 14 | ErrInvalidCredentialIssuer = errors.New("credential type: missing field Issuer") 15 | ) 16 | 17 | // AuthorizeCredential represents an accepted credential for PermissionedDomainSet transactions. 18 | type AuthorizeCredential struct { 19 | Credential Credential 20 | } 21 | 22 | // Validate checks if the AuthorizeCredential is valid. 23 | func (a AuthorizeCredential) Validate() error { 24 | if a.Credential.Issuer.String() == "" { 25 | return ErrInvalidCredentialIssuer 26 | } 27 | if !a.Credential.CredentialType.IsValid() { 28 | return ErrInvalidCredentialType 29 | } 30 | return nil 31 | } 32 | 33 | // Flatten returns a flattened map representation of the AuthorizeCredential. 34 | func (a AuthorizeCredential) Flatten() map[string]interface{} { 35 | m := make(map[string]interface{}) 36 | m["Credential"] = a.Credential.Flatten() 37 | return m 38 | } 39 | -------------------------------------------------------------------------------- /xrpl/queries/server/server_info.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | servertypes "github.com/Peersyst/xrpl-go/xrpl/queries/server/types" 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 7 | ) 8 | 9 | // ############################################################################ 10 | // Request 11 | // ############################################################################ 12 | 13 | // The server_info command asks the server for a human-readable version of 14 | // various information about the rippled server being queried. 15 | type InfoRequest struct { 16 | common.BaseRequest 17 | } 18 | 19 | func (*InfoRequest) Method() string { 20 | return "server_info" 21 | } 22 | 23 | func (*InfoRequest) APIVersion() int { 24 | return version.RippledAPIV2 25 | } 26 | 27 | // TODO: Implement V2 28 | func (*InfoRequest) Validate() error { 29 | return nil 30 | } 31 | 32 | // ############################################################################ 33 | // Response 34 | // ############################################################################ 35 | 36 | // The expected response from the server_info method. 37 | type InfoResponse struct { 38 | Info servertypes.Info `json:"info"` 39 | } 40 | -------------------------------------------------------------------------------- /examples/queries/account-tx/ws/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/faucet" 7 | "github.com/Peersyst/xrpl-go/xrpl/queries/account" 8 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 9 | "github.com/Peersyst/xrpl-go/xrpl/websocket" 10 | ) 11 | 12 | func main() { 13 | fmt.Println("⏳ Connecting to testnet...") 14 | client := websocket.NewClient( 15 | websocket.NewClientConfig(). 16 | WithHost("wss://s.altnet.rippletest.net:51233"). 17 | WithFaucetProvider(faucet.NewTestnetFaucetProvider()), 18 | ) 19 | defer client.Disconnect() 20 | 21 | if err := client.Connect(); err != nil { 22 | fmt.Println(err) 23 | return 24 | } 25 | 26 | if !client.IsConnected() { 27 | fmt.Println("❌ Failed to connect to testnet") 28 | return 29 | } 30 | 31 | fmt.Println("✅ Connected to testnet") 32 | fmt.Println() 33 | 34 | txs, err := client.GetAccountTransactions(&account.TransactionsRequest{ 35 | Account: "rMCcNuTcajgw7YTgBy1sys3b89QqjUrMpH", 36 | LedgerIndex: common.LedgerIndex(4976692), 37 | }) 38 | if err != nil { 39 | fmt.Println(err) 40 | return 41 | } 42 | 43 | fmt.Println("Number of transactions:", len(txs.Transactions)) 44 | fmt.Println(txs.Transactions[0].Tx) 45 | } 46 | -------------------------------------------------------------------------------- /xrpl/rpc/response.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/transaction" 5 | "github.com/mitchellh/mapstructure" 6 | ) 7 | 8 | type Response struct { 9 | Result AnyJSON `json:"result"` 10 | Warning string `json:"warning,omitempty"` 11 | Warnings []XRPLResponseWarning `json:"warnings,omitempty"` 12 | Forwarded bool `json:"forwarded,omitempty"` 13 | } 14 | 15 | type XRPLResponseWarning struct { 16 | ID int `json:"id"` 17 | Message string `json:"message"` 18 | Details any `json:"details,omitempty"` 19 | } 20 | 21 | type AnyJSON transaction.FlatTransaction 22 | 23 | type APIWarning struct { 24 | ID int `json:"id"` 25 | Message string `json:"message"` 26 | Details interface{} `json:"details,omitempty"` 27 | } 28 | 29 | func (r Response) GetResult(v any) error { 30 | dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{TagName: "json", 31 | Result: &v, DecodeHook: mapstructure.TextUnmarshallerHookFunc()}) 32 | 33 | if err != nil { 34 | return err 35 | } 36 | err = dec.Decode(r.Result) 37 | if err != nil { 38 | return err 39 | } 40 | return nil 41 | } 42 | 43 | type XRPLResponse interface { 44 | GetResult(v any) error 45 | } 46 | -------------------------------------------------------------------------------- /xrpl/queries/transactions/v1/submit_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestSubmitRequest(t *testing.T) { 10 | s := SubmitRequest{ 11 | TxBlob: "1200002280000000240000016861D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA9684000000000002710732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F858081144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754", 12 | } 13 | 14 | j := `{ 15 | "tx_blob": "1200002280000000240000016861D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA9684000000000002710732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F858081144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754" 16 | }` 17 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 18 | t.Error(err) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /xrpl/queries/transactions/submit_test.go: -------------------------------------------------------------------------------- 1 | package transactions 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | ) 8 | 9 | func TestSubmitRequest(t *testing.T) { 10 | s := SubmitRequest{ 11 | TxBlob: "1200002280000000240000016861D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA9684000000000002710732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F858081144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754", 12 | } 13 | 14 | j := `{ 15 | "tx_blob": "1200002280000000240000016861D4838D7EA4C6800000000000000000000000000055534400000000004B4E9C06F24296074F7BC48F92A97916C6DC5EA9684000000000002710732103AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB7446304402200E5C2DD81FDF0BE9AB2A8D797885ED49E804DBF28E806604D878756410CA98B102203349581946B0DDA06B36B35DBC20EDA27552C1F167BCF5C6ECFF49C6A46F858081144B4E9C06F24296074F7BC48F92A97916C6DC5EA983143E9D4A2B8AA0780F682D136F7A56D6724EF53754" 16 | }` 17 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 18 | t.Error(err) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /docs/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Getting Started 6 | 7 | This documentation englobes the `xrpl-go` project, a Go SDK for interacting with the XRP Ledger. 8 | 9 | ## What is the XRP Ledger? 10 | 11 | The XRP Ledger (XRPL) is a decentralized, open-source blockchain optimized for fast, low-cost transactions and financial applications. It enables tokenization and seamless cross-border payments without intermediaries. 12 | 13 | To learn more about the XRP Ledger, you can visit the [official website](https://xrpl.org/). 14 | 15 | ## What is xrpl-go? 16 | 17 | The [`xrpl-go`](https://github.com/Peersyst/xrpl-go) project is an SDK written in Go for interacting with the XRP Ledger. It provides a set of tools and libraries for building applications on the XRP Ledger. 18 | 19 | The SDK can be split into the following packages: 20 | 21 | - `binary-codec`: A package for encoding and decoding XRPL binary messages, objects and transactions. 22 | - `address-codec`: A package for encoding and decoding XRPL addresses. 23 | - [`keypairs`](/docs/keypairs): A package for generating and managing cryptographic keypairs. 24 | - [`xrpl`](/docs/xrpl/currency): The biggest package of the SDK. It contains clients, types, transactions, and utils to interact with the XRP Ledger. 25 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/deposit_preauth_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestDepositPreauth(t *testing.T) { 11 | var s Object = &DepositPreauthObj{ 12 | LedgerEntryType: DepositPreauthObjEntry, 13 | Account: "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 14 | Authorize: "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 15 | Flags: 0, 16 | OwnerNode: "0000000000000000", 17 | PreviousTxnID: "3E8964D5A86B3CD6B9ECB33310D4E073D64C865A5B866200AD2B7E29F8326702", 18 | PreviousTxnLgrSeq: 7, 19 | } 20 | 21 | j := `{ 22 | "Flags": 0, 23 | "LedgerEntryType": "DepositPreauth", 24 | "Account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 25 | "Authorize": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 26 | "OwnerNode": "0000000000000000", 27 | "PreviousTxnID": "3E8964D5A86B3CD6B9ECB33310D4E073D64C865A5B866200AD2B7E29F8326702", 28 | "PreviousTxnLgrSeq": 7 29 | }` 30 | 31 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 32 | t.Error(err) 33 | } 34 | } 35 | 36 | func TestDepositPreauth_EntryType(t *testing.T) { 37 | dp := &DepositPreauthObj{} 38 | require.Equal(t, dp.EntryType(), DepositPreauthObjEntry) 39 | } 40 | -------------------------------------------------------------------------------- /xrpl/testutil/integration/config.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | const ( 4 | DefaultMaxRetries = 3 5 | DefaultWalletCount = 1 6 | ) 7 | 8 | // RunnerConfig is the configuration for the integration test runner. 9 | // It contains the configuration for the websocket client and the number of wallets to create. 10 | type RunnerConfig struct { 11 | WalletCount int 12 | Client Client 13 | MaxRetries int 14 | } 15 | 16 | // Option is a function that modifies the RunnerConfig. 17 | type Option func(*RunnerConfig) 18 | 19 | // WithWallets sets the number of wallets to create. 20 | func WithWallets(count int) Option { 21 | return func(c *RunnerConfig) { 22 | c.WalletCount = count 23 | } 24 | } 25 | 26 | // WithMaxRetries sets the maximum number of retries for a transaction. 27 | func WithMaxRetries(maxRetries int) Option { 28 | return func(c *RunnerConfig) { 29 | c.MaxRetries = maxRetries 30 | } 31 | } 32 | 33 | // NewRunnerConfig creates a new RunnerConfig with the given websocket configuration and options. 34 | func NewRunnerConfig(opts ...Option) *RunnerConfig { 35 | config := &RunnerConfig{ 36 | WalletCount: DefaultWalletCount, 37 | MaxRetries: DefaultMaxRetries, 38 | } 39 | 40 | for _, opt := range opts { 41 | opt(config) 42 | } 43 | 44 | return config 45 | } 46 | -------------------------------------------------------------------------------- /keypairs/crypto_test.go: -------------------------------------------------------------------------------- 1 | package keypairs 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/keypairs/interfaces" 7 | "github.com/Peersyst/xrpl-go/pkg/crypto" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestGetCryptoImplementationFromKey(t *testing.T) { 12 | testcases := []struct { 13 | name string 14 | input string 15 | expected interfaces.KeypairCryptoAlg 16 | }{ 17 | { 18 | name: "fail - invalid key", 19 | input: "invalid", 20 | expected: nil, 21 | }, 22 | { 23 | name: "pass - get ED25519 implementation", 24 | input: "ED4924A9045FE5ED8B22BAA7B6229A72A287CCF3EA287AADD3A032A24C0F008FA6", 25 | expected: crypto.ED25519(), 26 | }, 27 | { 28 | name: "pass - get SECP256K1 implementation", 29 | input: "0003540DE0F1438F58C4822F99795AD3D1F83C8D123C7767228E04185C542C41680D", 30 | expected: crypto.SECP256K1(), 31 | }, 32 | { 33 | name: "pass - get nil implementation", 34 | input: "0103540DE0F1438F58C4822F99795AD3D1F83C8D123C7767228E04185C542C41680D", 35 | expected: nil, 36 | }, 37 | } 38 | 39 | for _, tc := range testcases { 40 | t.Run(tc.name, func(t *testing.T) { 41 | require.Equal(t, tc.expected, getCryptoImplementationFromKey(tc.input)) 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /xrpl/queries/account/currencies_test.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestAccountCurrenciesRequest(t *testing.T) { 11 | s := CurrenciesRequest{ 12 | Account: "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", 13 | Strict: true, 14 | LedgerIndex: common.LedgerIndex(1234), 15 | } 16 | 17 | j := `{ 18 | "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", 19 | "ledger_index": 1234, 20 | "strict": true 21 | }` 22 | if err := testutil.Serialize(t, s, j); err != nil { 23 | t.Error(err) 24 | } 25 | } 26 | 27 | func TestAccountCurrenciesResponse(t *testing.T) { 28 | s := CurrenciesResponse{ 29 | LedgerHash: "abc", 30 | LedgerIndex: 123, 31 | ReceiveCurrencies: []string{ 32 | "USD", 33 | "JPY", 34 | }, 35 | SendCurrencies: []string{ 36 | "USD", 37 | "CAD", 38 | }, 39 | Validated: true, 40 | } 41 | j := `{ 42 | "ledger_hash": "abc", 43 | "ledger_index": 123, 44 | "receive_currencies": [ 45 | "USD", 46 | "JPY" 47 | ], 48 | "send_currencies": [ 49 | "USD", 50 | "CAD" 51 | ], 52 | "validated": true 53 | }` 54 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 55 | t.Error(err) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /xrpl/queries/account/v1/currencies_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestAccountCurrenciesRequest(t *testing.T) { 11 | s := CurrenciesRequest{ 12 | Account: "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", 13 | Strict: true, 14 | LedgerIndex: common.LedgerIndex(1234), 15 | } 16 | 17 | j := `{ 18 | "account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59", 19 | "ledger_index": 1234, 20 | "strict": true 21 | }` 22 | if err := testutil.Serialize(t, s, j); err != nil { 23 | t.Error(err) 24 | } 25 | } 26 | 27 | func TestAccountCurrenciesResponse(t *testing.T) { 28 | s := CurrenciesResponse{ 29 | LedgerHash: "abc", 30 | LedgerIndex: 123, 31 | ReceiveCurrencies: []string{ 32 | "USD", 33 | "JPY", 34 | }, 35 | SendCurrencies: []string{ 36 | "USD", 37 | "CAD", 38 | }, 39 | Validated: true, 40 | } 41 | j := `{ 42 | "ledger_hash": "abc", 43 | "ledger_index": 123, 44 | "receive_currencies": [ 45 | "USD", 46 | "JPY" 47 | ], 48 | "send_currencies": [ 49 | "USD", 50 | "CAD" 51 | ], 52 | "validated": true 53 | }` 54 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 55 | t.Error(err) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /xrpl/transaction/types/authorize_credential_list.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrEmptyCredentials = errors.New("credentials list cannot be empty") 7 | ErrInvalidCredentialCount = errors.New("accepted credentials list must contain at least one and no more than the maximum allowed number of items") 8 | ErrDuplicateCredentials = errors.New("credentials list cannot contain duplicate elements") 9 | ) 10 | 11 | type AuthorizeCredentialList []AuthorizeCredential 12 | 13 | func (ac *AuthorizeCredentialList) Validate() error { 14 | if len(*ac) == 0 { 15 | return ErrEmptyCredentials 16 | } 17 | if len(*ac) > MaxAcceptedCredentials { 18 | return ErrInvalidCredentialCount 19 | } 20 | seen := make(map[string]bool) 21 | for _, cred := range *ac { 22 | key := cred.Credential.Issuer.String() + cred.Credential.CredentialType.String() 23 | if seen[key] { 24 | return ErrDuplicateCredentials 25 | } 26 | seen[key] = true 27 | 28 | if err := cred.Validate(); err != nil { 29 | return err 30 | } 31 | } 32 | return nil 33 | } 34 | 35 | func (ac *AuthorizeCredentialList) Flatten() []map[string]interface{} { 36 | acs := make([]map[string]interface{}, len(*ac)) 37 | for i, c := range *ac { 38 | acs[i] = c.Flatten() 39 | } 40 | return acs 41 | } 42 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Peersyst/xrpl-go 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.10 6 | 7 | require ( 8 | github.com/btcsuite/btcd/btcec/v2 v2.3.4 9 | github.com/decred/dcrd/crypto/ripemd160 v1.0.2 10 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 11 | github.com/gorilla/websocket v1.5.0 12 | github.com/mitchellh/mapstructure v1.5.0 13 | github.com/stretchr/testify v1.8.4 14 | github.com/tyler-smith/go-bip32 v1.0.0 15 | github.com/tyler-smith/go-bip39 v1.1.0 16 | github.com/ugorji/go/codec v1.2.11 17 | ) 18 | 19 | require ( 20 | github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect 21 | github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect 22 | github.com/golang/mock v1.6.0 // direct 23 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect 24 | github.com/modern-go/reflect2 v1.0.2 // indirect 25 | ) 26 | 27 | require ( 28 | github.com/davecgh/go-spew v1.1.1 // indirect 29 | github.com/json-iterator/go v1.1.12 30 | github.com/pmezard/go-difflib v1.0.0 // indirect 31 | golang.org/x/crypto v0.23.0 // indirect 32 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 33 | gopkg.in/yaml.v3 v3.0.1 // indirect 34 | ) 35 | 36 | replace golang.org/x/crypto => golang.org/x/crypto v0.35.0 37 | -------------------------------------------------------------------------------- /docs/docs/xrpl/currency.md: -------------------------------------------------------------------------------- 1 | # currency 2 | 3 | ## Overview 4 | 5 | `currency` is a package that provides utility functions to handle XRPL ledger currency types. For **native currency**, it provides XRP and drops conversions. For **IOUs**, it provides utility functions to convert non-standard currency codes (you can learn more about it in the [official documentation](https://xrpl.org/docs/references/protocol/data-types/currency-formats#nonstandard-currency-codes)). 6 | 7 | ## XRP/Drops conversions 8 | 9 | The package provides the following functions to convert XRP to drops and vice versa: 10 | 11 | ```go 12 | func XrpToDrops(value string) (string, error) 13 | func DropsToXrp(value string) (string, error) 14 | ``` 15 | 16 | Both functions return the converted value as a string and an error if the value is not a valid number. 17 | 18 | ## Usage 19 | 20 | To import the package, you can use the following code: 21 | 22 | ```go 23 | import "github.com/Peersyst/xrpl-go/xrpl/currency" 24 | ``` 25 | 26 | ## API 27 | 28 | ```go 29 | // XRP <-> Drops conversions 30 | func XrpToDrops(value string) (string, error) 31 | func DropsToXrp(value string) (string, error) 32 | 33 | // Non-standard currency codes conversions 34 | func ConvertStringToHex(input string) string 35 | func ConvertHexToString(input string) (string, error) -------------------------------------------------------------------------------- /xrpl/testutil/integration/flag.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | const ( 9 | IntegrationEnvVar = "INTEGRATION" 10 | ) 11 | 12 | // GetWebsocketEnv returns the integration environment. 13 | // If the environment is not set, it skips the tests. 14 | // This function is intended to be used in tests that need to run against a specific environment. 15 | // Run it before creating the runner to retrieve the environment host and faucet provider. 16 | func GetWebsocketEnv(t *testing.T) Env { 17 | if _, ok := IntegrationWebsocketEnvs[EnvKey(os.Getenv(IntegrationEnvVar))]; !ok { 18 | t.Skip("skipping integration tests") 19 | } 20 | 21 | return IntegrationWebsocketEnvs[EnvKey(os.Getenv(IntegrationEnvVar))] 22 | } 23 | 24 | // GetRPCEnv returns the integration environment. 25 | // If the environment is not set, it skips the tests. 26 | // This function is intended to be used in tests that need to run against a specific environment. 27 | // Run it before creating the runner to retrieve the environment host and faucet provider. 28 | func GetRPCEnv(t *testing.T) Env { 29 | if _, ok := IntegrationRPCEnvs[EnvKey(os.Getenv(IntegrationEnvVar))]; !ok { 30 | t.Skip("skipping integration tests") 31 | } 32 | 33 | return IntegrationRPCEnvs[EnvKey(os.Getenv(IntegrationEnvVar))] 34 | } 35 | -------------------------------------------------------------------------------- /xrpl/transaction/amm_common.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | // Common flags for AMM transactions (Deposit and Withdraw). 9 | const ( 10 | // Perform a double-asset withdrawal/deposit and receive the specified amount of LP Tokens. 11 | tfLPToken uint32 = 65536 12 | // Perform a single-asset withdrawal/deposit with a specified amount of the asset to deposit. 13 | tfSingleAsset uint32 = 524288 14 | // Perform a double-asset withdrawal/deposit with specified amounts of both assets. 15 | tfTwoAsset uint32 = 1048576 16 | // Perform a single-asset withdrawal/deposit and receive the specified amount of LP Tokens. 17 | tfOneAssetLPToken uint32 = 2097152 18 | // Perform a single-asset withdrawal/deposit with a specified effective price. 19 | tfLimitLPToken uint32 = 4194304 20 | 21 | // The maximum value is 1000, indicating a 1% fee. The minimum value is 0. https://xrpl.org/docs/references/protocol/transactions/types/ammcreate#ammcreate-fields 22 | AmmMaxTradingFee = 1000 23 | ) 24 | 25 | var ( 26 | ErrAMMTradingFeeTooHigh = fmt.Errorf("trading fee is too high, max value is %d", AmmMaxTradingFee) 27 | ErrAMMMustSetAmountWithAmount2 = errors.New("must set Amount with Amount2") 28 | ErrAMMMustSetAmountWithEPrice = errors.New("must set Amount with EPrice") 29 | ) 30 | -------------------------------------------------------------------------------- /xrpl/transaction/types/authorize_credentials.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | addresscodec "github.com/Peersyst/xrpl-go/address-codec" 5 | ) 6 | 7 | type AuthorizeCredentialsWrapper struct { 8 | Credential AuthorizeCredentials 9 | } 10 | 11 | type AuthorizeCredentials struct { 12 | // The issuer of the credential. 13 | Issuer Address 14 | // The credential type of the credential. 15 | CredentialType CredentialType 16 | } 17 | 18 | // IsValid returns true if the authorize credentials are valid. 19 | func (a *AuthorizeCredentials) IsValid() bool { 20 | return addresscodec.IsValidAddress(a.Issuer.String()) && a.CredentialType.IsValid() 21 | } 22 | 23 | // Flatten returns a map of the authorize credentials. 24 | func (a *AuthorizeCredentialsWrapper) Flatten() map[string]interface{} { 25 | flattened := make(map[string]interface{}) 26 | 27 | flattened["Credential"] = a.Credential.Flatten() 28 | 29 | return flattened 30 | } 31 | 32 | // Flatten returns a map of the authorize credentials. 33 | func (a *AuthorizeCredentials) Flatten() map[string]interface{} { 34 | flattened := make(map[string]interface{}) 35 | 36 | if a.Issuer != "" { 37 | flattened["Issuer"] = a.Issuer.String() 38 | } 39 | if a.CredentialType != "" { 40 | flattened["CredentialType"] = a.CredentialType.String() 41 | } 42 | 43 | return flattened 44 | } 45 | -------------------------------------------------------------------------------- /binary-codec/definitions/field_instance.go: -------------------------------------------------------------------------------- 1 | package definitions 2 | 3 | import "github.com/ugorji/go/codec" 4 | 5 | // FieldInstance is a struct that represents a field instance. 6 | type FieldInstance struct { 7 | FieldName string 8 | *FieldInfo 9 | FieldHeader *FieldHeader 10 | Ordinal int32 11 | } 12 | 13 | // FieldInfo is a struct that represents the field info. 14 | type FieldInfo struct { 15 | Nth int32 16 | IsVLEncoded bool 17 | IsSerialized bool 18 | IsSigningField bool 19 | Type string 20 | } 21 | 22 | // FieldHeader is a struct that represents the field header. 23 | type FieldHeader struct { 24 | TypeCode int32 25 | FieldCode int32 26 | } 27 | 28 | // CreateFieldHeader creates a new field header. 29 | func (d *Definitions) CreateFieldHeader(tc, fc int32) FieldHeader { 30 | return FieldHeader{ 31 | TypeCode: tc, 32 | FieldCode: fc, 33 | } 34 | } 35 | 36 | type fieldInstanceMap map[string]*FieldInstance 37 | 38 | // CodecEncodeSelf implements the codec.SelfEncoder interface. 39 | func (fi *fieldInstanceMap) CodecEncodeSelf(_ *codec.Encoder) {} 40 | 41 | // CodecDecodeSelf implements the codec.SelfDecoder interface. 42 | func (fi *fieldInstanceMap) CodecDecodeSelf(d *codec.Decoder) { 43 | var x [][]interface{} 44 | d.MustDecode(&x) 45 | y := convertToFieldInstanceMap(x) 46 | *fi = y 47 | } 48 | -------------------------------------------------------------------------------- /binary-codec/definitions/errors.go: -------------------------------------------------------------------------------- 1 | package definitions 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | // Static errors 10 | 11 | // ErrUnableToCastFieldInfo is returned when the field info cannot be cast. 12 | ErrUnableToCastFieldInfo = errors.New("unable to cast to field info") 13 | ) 14 | 15 | // Dynamic errors 16 | 17 | // NotFoundError is an error that occurs when a value is not found. 18 | type NotFoundError struct { 19 | Instance string 20 | Input string 21 | } 22 | 23 | // Error implements the error interface. 24 | func (e *NotFoundError) Error() string { 25 | return fmt.Sprintf("%v %v not found", e.Instance, e.Input) 26 | } 27 | 28 | // NotFoundErrorInt is an error that occurs when a value is not found. 29 | type NotFoundErrorInt struct { 30 | Instance string 31 | Input int32 32 | } 33 | 34 | // Error implements the error interface. 35 | func (e *NotFoundErrorInt) Error() string { 36 | return fmt.Sprintf("%v %v not found", e.Instance, e.Input) 37 | } 38 | 39 | // NotFoundErrorFieldHeader is an error that occurs when a value is not found. 40 | type NotFoundErrorFieldHeader struct { 41 | Instance string 42 | Input FieldHeader 43 | } 44 | 45 | // Error implements the error interface. 46 | func (e *NotFoundErrorFieldHeader) Error() string { 47 | return fmt.Sprintf("%v %v not found", e.Instance, e.Input) 48 | } 49 | -------------------------------------------------------------------------------- /xrpl/queries/server/fee_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "testing" 5 | 6 | servertypes "github.com/Peersyst/xrpl-go/xrpl/queries/server/types" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestFeeResponse(t *testing.T) { 11 | s := FeeResponse{ 12 | CurrentLedgerSize: "14", 13 | CurrentQueueSize: "0", 14 | Drops: servertypes.FeeDrops{ 15 | BaseFee: 10, 16 | MedianFee: 11000, 17 | MinimumFee: 10, 18 | OpenLedgerFee: 10, 19 | }, 20 | ExpectedLedgerSize: "24", 21 | LedgerCurrentIndex: 26575101, 22 | Levels: servertypes.FeeLevels{ 23 | MedianLevel: 281600, 24 | MinimumLevel: 256, 25 | OpenLedgerLevel: 256, 26 | ReferenceLevel: 256, 27 | }, 28 | MaxQueueSize: "480", 29 | } 30 | 31 | j := `{ 32 | "current_ledger_size": "14", 33 | "current_queue_size": "0", 34 | "drops": { 35 | "base_fee": "10", 36 | "median_fee": "11000", 37 | "minimum_fee": "10", 38 | "open_ledger_fee": "10" 39 | }, 40 | "expected_ledger_size": "24", 41 | "ledger_current_index": 26575101, 42 | "levels": { 43 | "median_level": "281600", 44 | "minimum_level": "256", 45 | "open_ledger_level": "256", 46 | "reference_level": "256" 47 | }, 48 | "max_queue_size": "480" 49 | }` 50 | 51 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 52 | t.Error(err) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /docs/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type {ReactNode} from 'react'; 2 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 3 | import Layout from '@theme/Layout'; 4 | import {LinkButton} from '../components/LinkButton'; 5 | import config from '@site/docusaurus.config'; 6 | 7 | export default function Home(): ReactNode { 8 | const {siteConfig} = useDocusaurusContext(); 9 | return ( 10 | 13 |
14 |
15 | XRPL GO Logo 20 |

21 | XRPL GO 22 |

23 |

24 | A comprehensive Go library for interacting with the XRP Ledger. 25 | Built with performance and developer experience in mind, XRPL Go provides 26 | all the tools needed to build robust applications on the XRPL ecosystem. 27 |

28 | 29 | Getting Started 30 | 31 |
32 |
33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /xrpl/queries/transactions/v1/transaction_entry.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/transaction" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The transaction_entry method retrieves information on a single transaction 13 | // from a specific ledger version. 14 | type EntryRequest struct { 15 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 16 | LedgerIndex common.LedgerSpecifier `json:"ledger_index,omitempty"` 17 | TxHash string `json:"tx_hash"` 18 | } 19 | 20 | func (*EntryRequest) Method() string { 21 | return "transaction_entry" 22 | } 23 | 24 | // ############################################################################ 25 | // Response 26 | // ############################################################################ 27 | 28 | // The expected response from the transaction_entry method. 29 | type EntryResponse struct { 30 | LedgerIndex common.LedgerIndex `json:"ledger_index"` 31 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 32 | Metadata transaction.TxObjMeta `json:"metadata"` 33 | Tx transaction.FlatTransaction `json:"tx_json"` 34 | } 35 | -------------------------------------------------------------------------------- /xrpl/queries/transactions/transaction_entry.go: -------------------------------------------------------------------------------- 1 | package transactions 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/transaction" 6 | ) 7 | 8 | // ############################################################################ 9 | // Request 10 | // ############################################################################ 11 | 12 | // The transaction_entry method retrieves information on a single transaction 13 | // from a specific ledger version. 14 | type EntryRequest struct { 15 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 16 | LedgerIndex common.LedgerSpecifier `json:"ledger_index,omitempty"` 17 | TxHash string `json:"tx_hash"` 18 | } 19 | 20 | func (*EntryRequest) Method() string { 21 | return "transaction_entry" 22 | } 23 | 24 | // ############################################################################ 25 | // Response 26 | // ############################################################################ 27 | 28 | // The expected response from the transaction_entry method. 29 | type EntryResponse struct { 30 | LedgerIndex common.LedgerIndex `json:"ledger_index"` 31 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 32 | Metadata transaction.TxObjMeta `json:"metadata"` 33 | Tx transaction.FlatTransaction `json:"tx_json"` 34 | } 35 | -------------------------------------------------------------------------------- /xrpl/queries/server/server_state.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | servertypes "github.com/Peersyst/xrpl-go/xrpl/queries/server/types" 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 7 | ) 8 | 9 | // ############################################################################ 10 | // Request 11 | // ############################################################################ 12 | 13 | // The server_state command asks the server for various machine-readable 14 | // information about the rippled server's current state. The response is almost 15 | // the same as the server_info method, but uses units that are easier to process 16 | // instead of easier to read. 17 | type StateRequest struct { 18 | common.BaseRequest 19 | } 20 | 21 | func (*StateRequest) Method() string { 22 | return "server_state" 23 | } 24 | 25 | func (*StateRequest) APIVersion() int { 26 | return version.RippledAPIV2 27 | } 28 | 29 | // TODO: Implement V2 30 | func (*StateRequest) Validate() error { 31 | return nil 32 | } 33 | 34 | // ############################################################################ 35 | // Response 36 | // ############################################################################ 37 | 38 | // The expected response from the server_state method. 39 | type StateResponse struct { 40 | State servertypes.State `json:"state"` 41 | } 42 | -------------------------------------------------------------------------------- /xrpl/rpc/errors.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import "errors" 4 | 5 | // Static errors 6 | var ( 7 | ErrIncorrectID = errors.New("incorrect id") 8 | ErrMissingTxSignatureOrSigningPubKey = errors.New("transaction must have a TxSignature or SigningPubKey set") 9 | ErrSignerDataIsEmpty = errors.New("signer data is empty") 10 | ErrCannotFundWalletWithoutClassicAddress = errors.New("cannot fund wallet without classic address") 11 | ErrMissingLastLedgerSequenceInTransaction = errors.New("missing LastLedgerSequence in transaction") 12 | ErrMissingWallet = errors.New("wallet must be provided when submitting an unsigned transaction") 13 | 14 | ErrRawTransactionsFieldIsNotAnArray = errors.New("RawTransactions field is not an array") 15 | ErrRawTransactionFieldIsNotAnObject = errors.New("RawTransaction field is not an object") 16 | 17 | ErrSigningPubKeyFieldMustBeEmpty = errors.New("SigningPubKey field must be empty") 18 | ErrTxnSignatureFieldMustBeEmpty = errors.New("TxnSignature field must be empty") 19 | ErrSignersFieldMustBeEmpty = errors.New("Signers field must be empty") 20 | ErrAccountFieldIsNotAString = errors.New("Account field is not a string") 21 | ) 22 | 23 | // Dynamic errors 24 | 25 | type ClientError struct { 26 | ErrorString string 27 | } 28 | 29 | func (e *ClientError) Error() string { 30 | return e.ErrorString 31 | } 32 | -------------------------------------------------------------------------------- /xrpl/queries/channel/v1/verify_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | ) 9 | 10 | func TestChannelVerifyRequest(t *testing.T) { 11 | s := VerifyRequest{ 12 | Amount: types.XRPCurrencyAmount(1000000), 13 | ChannelID: "5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3", 14 | PublicKey: "aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3", 15 | Signature: "304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064", 16 | } 17 | 18 | j := `{ 19 | "amount": "1000000", 20 | "channel_id": "5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3", 21 | "public_key": "aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3", 22 | "signature": "304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064" 23 | }` 24 | 25 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 26 | t.Error(err) 27 | } 28 | } 29 | 30 | func TestChannelVerifyResponse(t *testing.T) { 31 | s := VerifyResponse{ 32 | SignatureVerified: false, 33 | } 34 | 35 | j := `{ 36 | "signature_verified": false 37 | }` 38 | 39 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 40 | t.Error(err) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /xrpl/queries/channel/verify_test.go: -------------------------------------------------------------------------------- 1 | package channel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | ) 9 | 10 | func TestChannelVerifyRequest(t *testing.T) { 11 | s := VerifyRequest{ 12 | Amount: types.XRPCurrencyAmount(1000000), 13 | ChannelID: "5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3", 14 | PublicKey: "aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3", 15 | Signature: "304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064", 16 | } 17 | 18 | j := `{ 19 | "amount": "1000000", 20 | "channel_id": "5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3", 21 | "public_key": "aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3", 22 | "signature": "304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064" 23 | }` 24 | 25 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 26 | t.Error(err) 27 | } 28 | } 29 | 30 | func TestChannelVerifyResponse(t *testing.T) { 31 | s := VerifyResponse{ 32 | SignatureVerified: false, 33 | } 34 | 35 | j := `{ 36 | "signature_verified": false 37 | }` 38 | 39 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 40 | t.Error(err) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /xrpl/websocket/types/message_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/subscription/types" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestMessage_IsRequest(t *testing.T) { 11 | tests := []struct { 12 | name string 13 | message Message 14 | want bool 15 | }{ 16 | { 17 | name: "message with ID is request", 18 | message: Message{ 19 | ID: 1, 20 | }, 21 | want: true, 22 | }, 23 | { 24 | name: "message without ID is not request", 25 | message: Message{ 26 | Type: types.LedgerStreamType, 27 | }, 28 | want: false, 29 | }, 30 | } 31 | 32 | for _, tt := range tests { 33 | t.Run(tt.name, func(t *testing.T) { 34 | require.Equal(t, tt.want, tt.message.IsRequest()) 35 | }) 36 | } 37 | } 38 | 39 | func TestMessage_IsStream(t *testing.T) { 40 | tests := []struct { 41 | name string 42 | message Message 43 | want bool 44 | }{ 45 | { 46 | name: "message with stream type is stream", 47 | message: Message{ 48 | Type: types.LedgerStreamType, 49 | }, 50 | want: true, 51 | }, 52 | { 53 | name: "message without stream type is not stream", 54 | message: Message{ 55 | ID: 1, 56 | }, 57 | want: false, 58 | }, 59 | } 60 | 61 | for _, tt := range tests { 62 | t.Run(tt.name, func(t *testing.T) { 63 | require.Equal(t, tt.want, tt.message.IsStream()) 64 | }) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /xrpl/queries/common/ledger.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "strconv" 7 | ) 8 | 9 | type LedgerSpecifier interface { 10 | Ledger() string 11 | } 12 | 13 | func UnmarshalLedgerSpecifier(data []byte) (LedgerSpecifier, error) { 14 | if len(data) == 0 { 15 | return nil, nil 16 | } 17 | switch data[0] { 18 | case '"': 19 | var s string 20 | if err := json.Unmarshal(data, &s); err != nil { 21 | return nil, err 22 | } 23 | switch s { 24 | case Current.Ledger(): 25 | return Current, nil 26 | case Validated.Ledger(): 27 | return Validated, nil 28 | case Closed.Ledger(): 29 | return Closed, nil 30 | } 31 | return nil, fmt.Errorf("decoding LedgerTitle: invalid string %s", s) 32 | default: 33 | var i LedgerIndex 34 | if err := json.Unmarshal(data, &i); err != nil { 35 | return nil, err 36 | } 37 | return i, nil 38 | } 39 | } 40 | 41 | type LedgerIndex uint32 42 | 43 | func (l LedgerIndex) Ledger() string { 44 | return strconv.FormatUint(uint64(l), 10) 45 | } 46 | 47 | func (l LedgerIndex) Uint32() uint32 { 48 | return uint32(l) 49 | } 50 | 51 | func (l LedgerIndex) Int() int { 52 | return int(l) 53 | } 54 | 55 | type LedgerTitle string 56 | 57 | const ( 58 | Current LedgerTitle = "current" 59 | Validated LedgerTitle = "validated" 60 | Closed LedgerTitle = "closed" 61 | ) 62 | 63 | func (l LedgerTitle) Ledger() string { 64 | return string(l) 65 | } 66 | 67 | type LedgerHash string 68 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "3.8.1", 19 | "@docusaurus/preset-classic": "3.8.1", 20 | "@easyops-cn/docusaurus-search-local": "^0.51.1", 21 | "@mdx-js/react": "^3.0.0", 22 | "clsx": "^2.0.0", 23 | "prism-react-renderer": "^2.3.0", 24 | "react": "^19.0.0", 25 | "react-dom": "^19.0.0" 26 | }, 27 | "devDependencies": { 28 | "@docusaurus/module-type-aliases": "3.8.1", 29 | "@docusaurus/tsconfig": "3.8.1", 30 | "@docusaurus/types": "3.8.1", 31 | "typescript": "~5.6.2" 32 | }, 33 | "resolutions": { 34 | "webpack-dev-server": "5.2.1" 35 | }, 36 | "browserslist": { 37 | "production": [ 38 | ">0.5%", 39 | "not dead", 40 | "not op_mini all" 41 | ], 42 | "development": [ 43 | "last 3 chrome version", 44 | "last 3 firefox version", 45 | "last 5 safari version" 46 | ] 47 | }, 48 | "engines": { 49 | "node": ">=18.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /xrpl/queries/clio/nft_info_test.go: -------------------------------------------------------------------------------- 1 | package clio 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestNFTInfoRequest(t *testing.T) { 11 | s := NFTInfoRequest{ 12 | NFTokenID: "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 13 | LedgerIndex: common.Validated, 14 | } 15 | 16 | j := `{ 17 | "nft_id": "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 18 | "ledger_index": "validated" 19 | }` 20 | 21 | if err := testutil.Serialize(t, s, j); err != nil { 22 | t.Error(err) 23 | } 24 | } 25 | 26 | func TestNFTInfoResponse(t *testing.T) { 27 | s := NFTInfoResponse{ 28 | NFTokenID: "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 29 | LedgerIndex: 270, 30 | Owner: "rG9gdNygQ6npA9JvDFWBoeXbiUcTYJnEnk", 31 | IsBurned: true, 32 | Flags: 8, 33 | TransferFee: 0, 34 | Issuer: "rHVokeuSnjPjz718qdb47bGXBBHNMP3KDQ", 35 | } 36 | j := `{ 37 | "nft_id": "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 38 | "ledger_index": 270, 39 | "owner": "rG9gdNygQ6npA9JvDFWBoeXbiUcTYJnEnk", 40 | "is_burned": true, 41 | "flags": 8, 42 | "transfer_fee": 0, 43 | "issuer": "rHVokeuSnjPjz718qdb47bGXBBHNMP3KDQ", 44 | "nft_taxon": 0, 45 | "nft_sequence": 0, 46 | "uri": "" 47 | }` 48 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 49 | t.Error(err) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /xrpl/queries/clio/v1/nft_info_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestNFTInfoRequest(t *testing.T) { 11 | s := NFTInfoRequest{ 12 | NFTokenID: "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 13 | LedgerIndex: common.Validated, 14 | } 15 | 16 | j := `{ 17 | "nft_id": "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 18 | "ledger_index": "validated" 19 | }` 20 | 21 | if err := testutil.Serialize(t, s, j); err != nil { 22 | t.Error(err) 23 | } 24 | } 25 | 26 | func TestNFTInfoResponse(t *testing.T) { 27 | s := NFTInfoResponse{ 28 | NFTokenID: "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 29 | LedgerIndex: 270, 30 | Owner: "rG9gdNygQ6npA9JvDFWBoeXbiUcTYJnEnk", 31 | IsBurned: true, 32 | Flags: 8, 33 | TransferFee: 0, 34 | Issuer: "rHVokeuSnjPjz718qdb47bGXBBHNMP3KDQ", 35 | } 36 | j := `{ 37 | "nft_id": "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE70000099B00000000", 38 | "ledger_index": 270, 39 | "owner": "rG9gdNygQ6npA9JvDFWBoeXbiUcTYJnEnk", 40 | "is_burned": true, 41 | "flags": 8, 42 | "transfer_fee": 0, 43 | "issuer": "rHVokeuSnjPjz718qdb47bGXBBHNMP3KDQ", 44 | "nft_taxon": 0, 45 | "nft_sequence": 0, 46 | "uri": "" 47 | }` 48 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 49 | t.Error(err) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /xrpl/queries/clio/types/ledger.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/ledger-entry-types" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | ) 9 | 10 | // Ledger is a struct that represents the ledger information. 11 | type Ledger struct { 12 | AccountHash string `json:"account_hash"` 13 | AccountState []ledger.FlatLedgerObject `json:"accountState,omitempty"` 14 | CloseFlags int `json:"close_flags"` 15 | CloseTime uint `json:"close_time"` 16 | CloseTimeHuman string `json:"close_time_human"` 17 | CloseTimeResolution int `json:"close_time_resolution"` 18 | Closed bool `json:"closed"` 19 | LedgerHash common.LedgerHash `json:"ledger_hash"` 20 | LedgerIndex string `json:"ledger_index"` 21 | ParentCloseTime uint `json:"parent_close_time"` 22 | ParentHash string `json:"parent_hash"` 23 | TotalCoins types.XRPCurrencyAmount `json:"total_coins"` 24 | TransactionHash string `json:"transaction_hash"` 25 | Transactions []transaction.FlatTransaction `json:"transactions,omitempty"` 26 | } 27 | -------------------------------------------------------------------------------- /xrpl/queries/channel/v1/verify.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 7 | ) 8 | 9 | // ############################################################################ 10 | // Request 11 | // ############################################################################ 12 | 13 | // The channel_verify method checks the validity of a signature that can be 14 | // used to redeem a specific amount of XRP from a payment channel. 15 | type VerifyRequest struct { 16 | common.BaseRequest 17 | Amount types.XRPCurrencyAmount `json:"amount"` 18 | ChannelID string `json:"channel_id"` 19 | PublicKey string `json:"public_key"` 20 | Signature string `json:"signature"` 21 | } 22 | 23 | func (*VerifyRequest) Method() string { 24 | return "channel_verify" 25 | } 26 | 27 | func (*VerifyRequest) APIVersion() int { 28 | return version.RippledAPIV1 29 | } 30 | 31 | // TODO: Implement V2 32 | func (*VerifyRequest) Validate() error { 33 | return nil 34 | } 35 | 36 | // ############################################################################ 37 | // Response 38 | // ############################################################################ 39 | 40 | // The expected response from the channel_verify method. 41 | type VerifyResponse struct { 42 | SignatureVerified bool `json:"signature_verified"` 43 | } 44 | -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/nftoken_offer_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestNFTokenOffer(t *testing.T) { 12 | var s Object = &NFTokenOffer{ 13 | Amount: types.XRPCurrencyAmount(1000000), 14 | Flags: 1, 15 | LedgerEntryType: NFTokenOfferEntry, 16 | NFTokenID: "00081B5825A08C22787716FA031B432EBBC1B101BB54875F0002D2A400000000", 17 | NFTokenOfferNode: "0", 18 | Owner: "rhRxL3MNvuKEjWjL7TBbZSDacb8PmzAd7m", 19 | OwnerNode: "17", 20 | PreviousTxnID: "BFA9BE27383FA315651E26FDE1FA30815C5A5D0544EE10EC33D3E92532993769", 21 | PreviousTxnLgrSeq: 75443565, 22 | } 23 | 24 | j := `{ 25 | "Flags": 1, 26 | "LedgerEntryType": "NFTokenOffer", 27 | "Amount": "1000000", 28 | "NFTokenID": "00081B5825A08C22787716FA031B432EBBC1B101BB54875F0002D2A400000000", 29 | "NFTokenOfferNode": "0", 30 | "Owner": "rhRxL3MNvuKEjWjL7TBbZSDacb8PmzAd7m", 31 | "OwnerNode": "17", 32 | "PreviousTxnID": "BFA9BE27383FA315651E26FDE1FA30815C5A5D0544EE10EC33D3E92532993769", 33 | "PreviousTxnLgrSeq": 75443565 34 | }` 35 | 36 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 37 | t.Error(err) 38 | } 39 | } 40 | 41 | func TestNFTokenOffer_EntryType(t *testing.T) { 42 | s := &NFTokenOffer{} 43 | require.Equal(t, s.EntryType(), NFTokenOfferEntry) 44 | } 45 | -------------------------------------------------------------------------------- /xrpl/queries/channel/verify.go: -------------------------------------------------------------------------------- 1 | package channel 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 7 | ) 8 | 9 | // ############################################################################ 10 | // Request 11 | // ############################################################################ 12 | 13 | // The channel_verify method checks the validity of a signature that can be 14 | // used to redeem a specific amount of XRP from a payment channel. 15 | type VerifyRequest struct { 16 | common.BaseRequest 17 | Amount types.XRPCurrencyAmount `json:"amount"` 18 | ChannelID string `json:"channel_id"` 19 | PublicKey string `json:"public_key"` 20 | Signature string `json:"signature"` 21 | } 22 | 23 | func (*VerifyRequest) Method() string { 24 | return "channel_verify" 25 | } 26 | 27 | func (*VerifyRequest) APIVersion() int { 28 | return version.RippledAPIV2 29 | } 30 | 31 | // TODO: Implement V2 32 | func (*VerifyRequest) Validate() error { 33 | return nil 34 | } 35 | 36 | // ############################################################################ 37 | // Response 38 | // ############################################################################ 39 | 40 | // The expected response from the channel_verify method. 41 | type VerifyResponse struct { 42 | SignatureVerified bool `json:"signature_verified"` 43 | } 44 | -------------------------------------------------------------------------------- /xrpl/transaction/offer_cancel.go: -------------------------------------------------------------------------------- 1 | package transaction 2 | 3 | import "errors" 4 | 5 | var ( 6 | ErrOfferCancelMissingOfferSequence = errors.New("missing offer sequence") 7 | ) 8 | 9 | // An OfferCancel transaction removes an Offer object from the XRP Ledger. 10 | // 11 | // Example: 12 | // 13 | // ```json 14 | // 15 | // { 16 | // "TransactionType": "OfferCancel", 17 | // "Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX", 18 | // "Fee": "12", 19 | // "Flags": 0, 20 | // "LastLedgerSequence": 7108629, 21 | // "OfferSequence": 6, 22 | // "Sequence": 7 23 | // } 24 | // 25 | // ``` 26 | type OfferCancel struct { 27 | BaseTx 28 | // The sequence number (or Ticket number) of a previous OfferCreate transaction. 29 | // If specified, cancel any offer object in the ledger that was created by that transaction. It is not considered an error if the offer specified does not exist. 30 | OfferSequence uint32 31 | } 32 | 33 | func (*OfferCancel) TxType() TxType { 34 | return OfferCancelTx 35 | } 36 | 37 | // Flatten returns the flattened map of the OfferCancel transaction. 38 | func (o *OfferCancel) Flatten() FlatTransaction { 39 | flattened := o.BaseTx.Flatten() 40 | 41 | flattened["TransactionType"] = o.TxType().String() 42 | 43 | flattened["OfferSequence"] = o.OfferSequence 44 | return flattened 45 | } 46 | 47 | // Validates the OfferCancel struct and makes sure all fields are correct. 48 | func (o *OfferCancel) Validate() (bool, error) { 49 | return o.BaseTx.Validate() 50 | } 51 | -------------------------------------------------------------------------------- /xrpl/queries/subscription/v1/unsubscribe_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | ) 9 | 10 | func TestUnsubscribeRequest(t *testing.T) { 11 | s := UnsubscribeRequest{ 12 | Streams: []string{"ledger", "server", "transactions", "transactions_proposed"}, 13 | Accounts: []types.Address{"rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1"}, 14 | AccountsProposed: []types.Address{"rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1"}, 15 | Books: []UnsubscribeOrderBook{ 16 | { 17 | TakerGets: types.IssuedCurrencyAmount{ 18 | Issuer: "rUQTpMqAF5jhykj4FExVeXakrZpiKF6cQV", 19 | Currency: "USD", 20 | }, 21 | TakerPays: types.IssuedCurrencyAmount{ 22 | Currency: "XRP", 23 | }, 24 | Both: true, 25 | }, 26 | }, 27 | } 28 | 29 | j := `{ 30 | "streams": [ 31 | "ledger", 32 | "server", 33 | "transactions", 34 | "transactions_proposed" 35 | ], 36 | "accounts": [ 37 | "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1" 38 | ], 39 | "accounts_proposed": [ 40 | "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1" 41 | ], 42 | "books": [ 43 | { 44 | "taker_gets": { 45 | "issuer": "rUQTpMqAF5jhykj4FExVeXakrZpiKF6cQV", 46 | "currency": "USD" 47 | }, 48 | "taker_pays": { 49 | "currency": "XRP" 50 | }, 51 | "both": true 52 | } 53 | ] 54 | }` 55 | 56 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 57 | t.Error(err) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /address-codec/errors.go: -------------------------------------------------------------------------------- 1 | package addresscodec 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | // Static errors 10 | 11 | // Invalid classic address 12 | ErrInvalidClassicAddress = errors.New("invalid classic address") 13 | // Invalid seed 14 | ErrInvalidSeed = errors.New("invalid seed; could not determine encoding algorithm") 15 | 16 | // Invalid x-address 17 | ErrInvalidXAddress = errors.New("invalid x-address") 18 | // Invalid tag 19 | ErrInvalidTag = errors.New("invalid tag") 20 | // Invalid accountId 21 | ErrInvalidAccountID = errors.New("invalid accountId") 22 | 23 | // Invalid xrpl address, general error 24 | ErrInvalidAddressFormat = errors.New("invalid address format") 25 | 26 | // ErrChecksum indicates that the checksum of a check-encoded string does not verify against 27 | // the checksum. 28 | ErrChecksum = errors.New("checksum error") 29 | // ErrInvalidFormat indicates that the check-encoded string has an invalid format. 30 | ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing") 31 | ) 32 | 33 | // Dynamic errors 34 | 35 | // EncodeLengthError is an error that occurs when the length of the input does not match the expected length. 36 | type EncodeLengthError struct { 37 | Instance string 38 | Input int 39 | Expected int 40 | } 41 | 42 | // Error implements the error interface. 43 | func (e *EncodeLengthError) Error() string { 44 | return fmt.Sprintf("`%v` length should be %v not %v", e.Instance, e.Expected, e.Input) 45 | } 46 | -------------------------------------------------------------------------------- /xrpl/queries/subscription/unsubscribe_test.go: -------------------------------------------------------------------------------- 1 | package subscribe 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | ) 9 | 10 | func TestUnsubscribeRequest(t *testing.T) { 11 | s := UnsubscribeRequest{ 12 | Streams: []string{"ledger", "server", "transactions", "transactions_proposed"}, 13 | Accounts: []types.Address{"rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1"}, 14 | AccountsProposed: []types.Address{"rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1"}, 15 | Books: []UnsubscribeOrderBook{ 16 | { 17 | TakerGets: types.IssuedCurrencyAmount{ 18 | Issuer: "rUQTpMqAF5jhykj4FExVeXakrZpiKF6cQV", 19 | Currency: "USD", 20 | }, 21 | TakerPays: types.IssuedCurrencyAmount{ 22 | Currency: "XRP", 23 | }, 24 | Both: true, 25 | }, 26 | }, 27 | } 28 | 29 | j := `{ 30 | "streams": [ 31 | "ledger", 32 | "server", 33 | "transactions", 34 | "transactions_proposed" 35 | ], 36 | "accounts": [ 37 | "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1" 38 | ], 39 | "accounts_proposed": [ 40 | "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1" 41 | ], 42 | "books": [ 43 | { 44 | "taker_gets": { 45 | "issuer": "rUQTpMqAF5jhykj4FExVeXakrZpiKF6cQV", 46 | "currency": "USD" 47 | }, 48 | "taker_pays": { 49 | "currency": "XRP" 50 | }, 51 | "both": true 52 | } 53 | ] 54 | }` 55 | 56 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 57 | t.Error(err) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /xrpl/testutil/integration/env.go: -------------------------------------------------------------------------------- 1 | package integration 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/faucet" 5 | ) 6 | 7 | // EnvKey is the key for the integration environment. 8 | type EnvKey string 9 | 10 | const ( 11 | LocalnetEnv EnvKey = "localnet" 12 | TestnetEnv EnvKey = "testnet" 13 | DevnetEnv EnvKey = "devnet" 14 | ) 15 | 16 | // IntegrationWebsocketEnvs is the map of integration environments. 17 | var IntegrationWebsocketEnvs = map[EnvKey]Env{ 18 | LocalnetEnv: { 19 | Host: "ws://0.0.0.0:6006", 20 | FaucetProvider: nil, 21 | }, 22 | TestnetEnv: { 23 | Host: "wss://s.altnet.rippletest.net:51233", 24 | FaucetProvider: faucet.NewTestnetFaucetProvider(), 25 | }, 26 | DevnetEnv: { 27 | Host: "wss://s.devnet.rippletest.net:51233", 28 | FaucetProvider: faucet.NewDevnetFaucetProvider(), 29 | }, 30 | } 31 | 32 | var IntegrationRPCEnvs = map[EnvKey]Env{ 33 | LocalnetEnv: { 34 | Host: "http://0.0.0.0:5005", 35 | FaucetProvider: nil, 36 | }, 37 | TestnetEnv: { 38 | Host: "https://s.altnet.rippletest.net:51234", 39 | FaucetProvider: faucet.NewTestnetFaucetProvider(), 40 | }, 41 | DevnetEnv: { 42 | Host: "https://s.devnet.rippletest.net:51234", 43 | FaucetProvider: faucet.NewDevnetFaucetProvider(), 44 | }, 45 | } 46 | 47 | // Env is the environment for the integration tests. 48 | // It contains the host and the faucet provider. 49 | type Env struct { 50 | Host string 51 | FaucetProvider FaucetProvider 52 | } 53 | -------------------------------------------------------------------------------- /xrpl/queries/server/feature_test.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/server/types" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestFeatureAllResponse(t *testing.T) { 11 | r := FeatureAllResponse{ 12 | Features: map[string]types.FeatureStatus{ 13 | "feature1": {Enabled: true, Name: "feature1", Supported: true}, 14 | "feature2": {Enabled: false, Name: "feature2", Supported: false}, 15 | }, 16 | } 17 | 18 | s := `{ 19 | "features": { 20 | "feature1": { 21 | "enabled": true, 22 | "name": "feature1", 23 | "supported": true 24 | }, 25 | "feature2": { 26 | "enabled": false, 27 | "name": "feature2", 28 | "supported": false 29 | } 30 | } 31 | }` 32 | 33 | if err := testutil.SerializeAndDeserialize(t, r, s); err != nil { 34 | t.Fatal(err) 35 | } 36 | } 37 | 38 | func TestFeatureOneRequest(t *testing.T) { 39 | r := FeatureOneRequest{ 40 | Feature: "feature1", 41 | } 42 | 43 | s := `{ 44 | "feature": "feature1" 45 | }` 46 | 47 | if err := testutil.Serialize(t, r, s); err != nil { 48 | t.Fatal(err) 49 | } 50 | } 51 | 52 | func TestFeatureOneResponse(t *testing.T) { 53 | r := FeatureResponse{ 54 | "feature1": {Enabled: true, Name: "feature1", Supported: true}, 55 | } 56 | 57 | s := `{ 58 | "feature1": { 59 | "enabled": true, 60 | "name": "feature1", 61 | "supported": true 62 | } 63 | }` 64 | 65 | if err := testutil.SerializeAndDeserialize(t, r, s); err != nil { 66 | t.Fatal(err) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /xrpl/transaction/types/permission.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "errors" 4 | 5 | var ( 6 | // ErrInvalidPermissionValue is returned when PermissionValue is empty or undefined. 7 | ErrInvalidPermissionValue = errors.New("permission value cannot be empty or undefined") 8 | ) 9 | 10 | // Permission represents a transaction permission that can be delegated to another account. 11 | // This matches the xrpl.js Permission interface structure. 12 | type Permission struct { 13 | Permission PermissionValue `json:"Permission"` 14 | } 15 | 16 | // PermissionValue represents the inner permission value structure. 17 | type PermissionValue struct { 18 | PermissionValue string `json:"PermissionValue"` 19 | } 20 | 21 | // Flatten returns the flattened map representation of the Permission. 22 | func (p *Permission) Flatten() map[string]interface{} { 23 | flattened := make(map[string]interface{}) 24 | flattened["Permission"] = p.Permission.Flatten() 25 | return flattened 26 | } 27 | 28 | // Validate validates the Permission structure. 29 | func (p *Permission) IsValid() bool { 30 | return p.Permission.IsValid() 31 | } 32 | 33 | // Flatten returns the flattened map representation of the PermissionValue. 34 | func (pv *PermissionValue) Flatten() map[string]interface{} { 35 | flattened := make(map[string]interface{}) 36 | flattened["PermissionValue"] = pv.PermissionValue 37 | return flattened 38 | } 39 | 40 | // IsValid validates the PermissionValue structure. 41 | func (pv *PermissionValue) IsValid() bool { 42 | return pv.PermissionValue != "" 43 | } 44 | -------------------------------------------------------------------------------- /binary-codec/types/blob.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/hex" 5 | "errors" 6 | "strings" 7 | 8 | "github.com/Peersyst/xrpl-go/binary-codec/types/interfaces" 9 | ) 10 | 11 | // ErrNoLengthPrefix error is raised when no length prefix size is given. 12 | var ErrNoLengthPrefix = errors.New("no length prefix size given") 13 | 14 | // Blob struct is used for manipulating hexadecimal data. 15 | type Blob struct{} 16 | 17 | // FromJSON method for Blob converts a hexadecimal string from JSON to a byte array. 18 | func (b *Blob) FromJSON(json any) ([]byte, error) { 19 | // Convert hexadecimal string to byte array. 20 | // Return an error if the conversion fails. 21 | v, err := hex.DecodeString(json.(string)) 22 | if err != nil { 23 | return nil, err 24 | } 25 | return v, nil 26 | } 27 | 28 | // ToJSON method for Blob reads a certain number of bytes from a BinaryParser 29 | // and converts it into a hexadecimal string. 30 | // It returns an error if no length prefix is specified or if the read operation fails. 31 | func (b *Blob) ToJSON(p interfaces.BinaryParser, opts ...int) (any, error) { 32 | // If no length prefix is specified, return an error. 33 | if opts == nil { 34 | return nil, ErrNoLengthPrefix 35 | } 36 | // Read the specified number of bytes. 37 | // If the read operation fails, return an error. 38 | val, err := p.ReadBytes(opts[0]) 39 | if err != nil { 40 | return nil, err 41 | } 42 | // Convert the bytes to a hexadecimal string and return it. 43 | return strings.ToUpper(hex.EncodeToString(val)), nil 44 | } 45 | -------------------------------------------------------------------------------- /.github/workflows/xrpl-go-docs-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | # Review gh actions docs if you want to further define triggers, paths, etc 8 | # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on 9 | 10 | jobs: 11 | build: 12 | name: Build Docusaurus 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: 18 21 | 22 | - name: Install dependencies 23 | run: cd docs && yarn install --frozen-lockfile 24 | - name: Build website 25 | run: cd docs && yarn build 26 | 27 | - name: Upload Build Artifact 28 | uses: actions/upload-pages-artifact@v3 29 | with: 30 | path: docs/build 31 | 32 | deploy: 33 | name: Deploy to GitHub Pages 34 | needs: build 35 | 36 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 37 | permissions: 38 | pages: write # to deploy to Pages 39 | id-token: write # to verify the deployment originates from an appropriate source 40 | 41 | # Deploy to the github-pages environment 42 | environment: 43 | name: github-pages 44 | url: ${{ steps.deployment.outputs.page_url }} 45 | 46 | runs-on: ubuntu-latest 47 | steps: 48 | - name: Deploy to GitHub Pages 49 | id: deployment 50 | uses: actions/deploy-pages@v4 -------------------------------------------------------------------------------- /xrpl/ledger-entry-types/nftoken_page_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestNFTokenPage(t *testing.T) { 12 | var s Object = &NFTokenPage{ 13 | LedgerEntryType: NFTokenPageEntry, 14 | PreviousTxnID: "95C8761B22894E328646F7A70035E9DFBECC90EDD83E43B7B973F626D21A0822", 15 | PreviousTxnLgrSeq: 42891441, 16 | NFTokens: []types.NFToken{ 17 | { 18 | NFTokenID: "000B013A95F14B0044F78A264E41713C64B5F89242540EE208C3098E00000D65", 19 | NFTokenURI: "697066733A2F2F62616679626569676479727A74357366703775646D37687537367568377932366E6634646675796C71616266336F636C67747179353566627A6469", 20 | }, 21 | }, 22 | } 23 | 24 | j := `{ 25 | "LedgerEntryType": "NFTokenPage", 26 | "Flags": 0, 27 | "PreviousTxnID": "95C8761B22894E328646F7A70035E9DFBECC90EDD83E43B7B973F626D21A0822", 28 | "PreviousTxnLgrSeq": 42891441, 29 | "NFTokens": [ 30 | { 31 | "NFTokenID": "000B013A95F14B0044F78A264E41713C64B5F89242540EE208C3098E00000D65", 32 | "URI": "697066733A2F2F62616679626569676479727A74357366703775646D37687537367568377932366E6634646675796C71616266336F636C67747179353566627A6469" 33 | } 34 | ] 35 | }` 36 | 37 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 38 | t.Error(err) 39 | } 40 | } 41 | 42 | func TestNFTokenPage_EntryType(t *testing.T) { 43 | s := &NFTokenPage{} 44 | require.Equal(t, s.EntryType(), NFTokenPageEntry) 45 | } 46 | -------------------------------------------------------------------------------- /xrpl/queries/nft/nftoken_buy_offers.go: -------------------------------------------------------------------------------- 1 | package nft 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 7 | 8 | nfttypes "github.com/Peersyst/xrpl-go/xrpl/queries/nft/types" 9 | ) 10 | 11 | // ############################################################################ 12 | // Request 13 | // ############################################################################ 14 | 15 | // The nft_buy_offers method retrieves all of buy offers for the specified 16 | // NFToken. 17 | type NFTokenBuyOffersRequest struct { 18 | common.BaseRequest 19 | NFTokenID types.NFTokenID `json:"nft_id"` 20 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 21 | LedgerIndex common.LedgerSpecifier `json:"ledger_index,omitempty"` 22 | } 23 | 24 | func (*NFTokenBuyOffersRequest) Method() string { 25 | return "nft_buy_offers" 26 | } 27 | 28 | func (*NFTokenBuyOffersRequest) APIVersion() int { 29 | return version.RippledAPIV2 30 | } 31 | 32 | // TODO: Implement V2 33 | func (*NFTokenBuyOffersRequest) Validate() error { 34 | return nil 35 | } 36 | 37 | // ############################################################################ 38 | // Response 39 | // ############################################################################ 40 | 41 | // The expected response from the nft_buy_offers method. 42 | type NFTokenBuyOffersResponse struct { 43 | NFTokenID types.NFTokenID `json:"nft_id"` 44 | Offers []nfttypes.NFTokenOffer `json:"offers"` 45 | } 46 | -------------------------------------------------------------------------------- /xrpl/queries/nft/nftoken_sell_offers.go: -------------------------------------------------------------------------------- 1 | package nft 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | nfttypes "github.com/Peersyst/xrpl-go/xrpl/queries/nft/types" 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | ) 9 | 10 | // ############################################################################ 11 | // Request 12 | // ############################################################################ 13 | 14 | // The nft_sell_offers method retrieves all of sell offers for the specified 15 | // NFToken. 16 | type NFTokenSellOffersRequest struct { 17 | common.BaseRequest 18 | NFTokenID types.NFTokenID `json:"nft_id"` 19 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 20 | LedgerIndex common.LedgerSpecifier `json:"ledger_index,omitempty"` 21 | } 22 | 23 | func (*NFTokenSellOffersRequest) Method() string { 24 | return "nft_sell_offers" 25 | } 26 | 27 | func (*NFTokenSellOffersRequest) APIVersion() int { 28 | return version.RippledAPIV2 29 | } 30 | 31 | // TODO: Implement V2 32 | func (*NFTokenSellOffersRequest) Validate() error { 33 | return nil 34 | } 35 | 36 | // ############################################################################ 37 | // Response 38 | // ############################################################################ 39 | 40 | // The expected response from the nft_sell_offers method. 41 | type NFTokenSellOffersResponse struct { 42 | NFTokenID types.NFTokenID `json:"nft_id"` 43 | Offers []nfttypes.NFTokenOffer `json:"offers"` 44 | } 45 | -------------------------------------------------------------------------------- /xrpl/queries/nft/v1/nftoken_buy_offers.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 7 | 8 | nfttypes "github.com/Peersyst/xrpl-go/xrpl/queries/nft/types" 9 | ) 10 | 11 | // ############################################################################ 12 | // Request 13 | // ############################################################################ 14 | 15 | // The nft_buy_offers method retrieves all of buy offers for the specified 16 | // NFToken. 17 | type NFTokenBuyOffersRequest struct { 18 | common.BaseRequest 19 | NFTokenID types.NFTokenID `json:"nft_id"` 20 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 21 | LedgerIndex common.LedgerSpecifier `json:"ledger_index,omitempty"` 22 | } 23 | 24 | func (*NFTokenBuyOffersRequest) Method() string { 25 | return "nft_buy_offers" 26 | } 27 | 28 | func (*NFTokenBuyOffersRequest) APIVersion() int { 29 | return version.RippledAPIV1 30 | } 31 | 32 | // TODO: Implement V2 33 | func (*NFTokenBuyOffersRequest) Validate() error { 34 | return nil 35 | } 36 | 37 | // ############################################################################ 38 | // Response 39 | // ############################################################################ 40 | 41 | // The expected response from the nft_buy_offers method. 42 | type NFTokenBuyOffersResponse struct { 43 | NFTokenID types.NFTokenID `json:"nft_id"` 44 | Offers []nfttypes.NFTokenOffer `json:"offers"` 45 | } 46 | -------------------------------------------------------------------------------- /xrpl/transaction/types/issued_currency_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "testing" 4 | 5 | func TestIssuedCurrency_Flatten(t *testing.T) { 6 | tests := []struct { 7 | name string 8 | currency IssuedCurrency 9 | want map[string]interface{} 10 | }{ 11 | { 12 | name: "pass - basic issued currency", 13 | currency: IssuedCurrency{ 14 | Currency: "FOO", 15 | Issuer: "rPdYxU9dNkbzC5Y2h4jLbVJ3rMRrk7WVRL", 16 | }, 17 | want: map[string]interface{}{ 18 | "currency": "FOO", 19 | "issuer": "rPdYxU9dNkbzC5Y2h4jLbVJ3rMRrk7WVRL", 20 | }, 21 | }, 22 | { 23 | name: "pass - empty currency", 24 | currency: IssuedCurrency{ 25 | Currency: "", 26 | Issuer: "rPdYxU9dNkbzC5Y2h4jLbVJ3rMRrk7WVRL", 27 | }, 28 | want: map[string]interface{}{ 29 | "currency": "", 30 | "issuer": "rPdYxU9dNkbzC5Y2h4jLbVJ3rMRrk7WVRL", 31 | }, 32 | }, 33 | { 34 | name: "pass - empty issuer", 35 | currency: IssuedCurrency{ 36 | Currency: "BAR", 37 | Issuer: "", 38 | }, 39 | want: map[string]interface{}{ 40 | "currency": "BAR", 41 | "issuer": "", 42 | }, 43 | }, 44 | } 45 | 46 | for _, tt := range tests { 47 | t.Run(tt.name, func(t *testing.T) { 48 | got := tt.currency.Flatten() 49 | if len(got) != len(tt.want) { 50 | t.Errorf("IssuedCurrency.Flatten() map length = %v, want %v", len(got), len(tt.want)) 51 | } 52 | for k, v := range tt.want { 53 | if got[k] != v { 54 | t.Errorf("IssuedCurrency.Flatten() got[%v] = %v, want %v", k, got[k], v) 55 | } 56 | } 57 | }) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /xrpl/queries/nft/v1/nftoken_sell_offers.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | nfttypes "github.com/Peersyst/xrpl-go/xrpl/queries/nft/types" 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 7 | "github.com/Peersyst/xrpl-go/xrpl/transaction/types" 8 | ) 9 | 10 | // ############################################################################ 11 | // Request 12 | // ############################################################################ 13 | 14 | // The nft_sell_offers method retrieves all of sell offers for the specified 15 | // NFToken. 16 | type NFTokenSellOffersRequest struct { 17 | common.BaseRequest 18 | NFTokenID types.NFTokenID `json:"nft_id"` 19 | LedgerHash common.LedgerHash `json:"ledger_hash,omitempty"` 20 | LedgerIndex common.LedgerSpecifier `json:"ledger_index,omitempty"` 21 | } 22 | 23 | func (*NFTokenSellOffersRequest) Method() string { 24 | return "nft_sell_offers" 25 | } 26 | 27 | func (*NFTokenSellOffersRequest) APIVersion() int { 28 | return version.RippledAPIV1 29 | } 30 | 31 | // TODO: Implement V2 32 | func (*NFTokenSellOffersRequest) Validate() error { 33 | return nil 34 | } 35 | 36 | // ############################################################################ 37 | // Response 38 | // ############################################################################ 39 | 40 | // The expected response from the nft_sell_offers method. 41 | type NFTokenSellOffersResponse struct { 42 | NFTokenID types.NFTokenID `json:"nft_id"` 43 | Offers []nfttypes.NFTokenOffer `json:"offers"` 44 | } 45 | -------------------------------------------------------------------------------- /xrpl/websocket/response.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "github.com/mitchellh/mapstructure" 5 | ) 6 | 7 | type ResponseWarning struct { 8 | ID int `json:"id"` 9 | Message string `json:"message"` 10 | Details any `json:"details,omitempty"` 11 | } 12 | 13 | type ErrorWebsocketClientXrplResponse struct { 14 | Type string 15 | Request map[string]any 16 | } 17 | 18 | func (e *ErrorWebsocketClientXrplResponse) Error() string { 19 | return e.Type 20 | } 21 | 22 | type ClientResponse struct { 23 | ID int `json:"id"` 24 | Status string `json:"status"` 25 | Type string `json:"type"` 26 | Error string `json:"error,omitempty"` 27 | Result map[string]any `json:"result,omitempty"` 28 | Value map[string]any `json:"value,omitempty"` 29 | Warning string `json:"warning,omitempty"` 30 | Warnings []ResponseWarning `json:"warnings,omitempty"` 31 | Forwarded bool `json:"forwarded,omitempty"` 32 | } 33 | 34 | func (r *ClientResponse) GetResult(v any) error { 35 | dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{TagName: "json", Result: &v, DecodeHook: mapstructure.TextUnmarshallerHookFunc()}) 36 | if err != nil { 37 | return err 38 | } 39 | err = dec.Decode(r.Result) 40 | if err != nil { 41 | return err 42 | } 43 | return nil 44 | } 45 | 46 | func (r *ClientResponse) CheckError() error { 47 | if r.Error != "" { 48 | return &ErrorWebsocketClientXrplResponse{ 49 | Type: r.Error, 50 | Request: r.Value, 51 | } 52 | } 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /xrpl/queries/path/deposit_authorized_test.go: -------------------------------------------------------------------------------- 1 | package path 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestDepositAuthorizedRequest(t *testing.T) { 11 | s := DepositAuthorizedRequest{ 12 | SourceAccount: "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 13 | DestinationAccount: "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 14 | LedgerIndex: common.Validated, 15 | } 16 | 17 | j := `{ 18 | "source_account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 19 | "destination_account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 20 | "ledger_index": "validated" 21 | }` 22 | 23 | if err := testutil.Serialize(t, s, j); err != nil { 24 | t.Error(err) 25 | } 26 | } 27 | 28 | func TestDepositAuthorizedResponse(t *testing.T) { 29 | s := DepositAuthorizedResponse{ 30 | DepositAuthorized: true, 31 | DestinationAccount: "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 32 | LedgerHash: "BD03A10653ED9D77DCA859B7A735BF0580088A8F287FA2C5403E0A19C58EF322", 33 | LedgerIndex: 8, 34 | SourceAccount: "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 35 | Validated: true, 36 | } 37 | 38 | j := `{ 39 | "deposit_authorized": true, 40 | "destination_account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 41 | "ledger_hash": "BD03A10653ED9D77DCA859B7A735BF0580088A8F287FA2C5403E0A19C58EF322", 42 | "ledger_index": 8, 43 | "source_account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 44 | "validated": true 45 | }` 46 | 47 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 48 | t.Error(err) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /xrpl/queries/path/v1/deposit_authorized_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 7 | "github.com/Peersyst/xrpl-go/xrpl/testutil" 8 | ) 9 | 10 | func TestDepositAuthorizedRequest(t *testing.T) { 11 | s := DepositAuthorizedRequest{ 12 | SourceAccount: "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 13 | DestinationAccount: "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 14 | LedgerIndex: common.Validated, 15 | } 16 | 17 | j := `{ 18 | "source_account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 19 | "destination_account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 20 | "ledger_index": "validated" 21 | }` 22 | 23 | if err := testutil.Serialize(t, s, j); err != nil { 24 | t.Error(err) 25 | } 26 | } 27 | 28 | func TestDepositAuthorizedResponse(t *testing.T) { 29 | s := DepositAuthorizedResponse{ 30 | DepositAuthorized: true, 31 | DestinationAccount: "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 32 | LedgerHash: "BD03A10653ED9D77DCA859B7A735BF0580088A8F287FA2C5403E0A19C58EF322", 33 | LedgerIndex: 8, 34 | SourceAccount: "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 35 | Validated: true, 36 | } 37 | 38 | j := `{ 39 | "deposit_authorized": true, 40 | "destination_account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8", 41 | "ledger_hash": "BD03A10653ED9D77DCA859B7A735BF0580088A8F287FA2C5403E0A19C58EF322", 42 | "ledger_index": 8, 43 | "source_account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de", 44 | "validated": true 45 | }` 46 | 47 | if err := testutil.SerializeAndDeserialize(t, s, j); err != nil { 48 | t.Error(err) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /xrpl/queries/server/manifest.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "github.com/Peersyst/xrpl-go/xrpl/queries/common" 5 | "github.com/Peersyst/xrpl-go/xrpl/queries/version" 6 | ) 7 | 8 | type ManifestDetails struct { 9 | Domain string `json:"domain"` 10 | EphemeralKey string `json:"ephemeral_key"` 11 | MasterKey string `json:"master_key"` 12 | Seq uint `json:"seq"` 13 | } 14 | 15 | // ############################################################################ 16 | // Request 17 | // ############################################################################ 18 | 19 | // The manifest method reports the current "manifest" information for a given 20 | // validator public key. The "manifest" is the public portion of that 21 | // validator's configured token. 22 | type ManifestRequest struct { 23 | common.BaseRequest 24 | PublicKey string `json:"public_key"` 25 | } 26 | 27 | func (*ManifestRequest) Method() string { 28 | return "manifest" 29 | } 30 | 31 | func (*ManifestRequest) APIVersion() int { 32 | return version.RippledAPIV2 33 | } 34 | 35 | // TODO: Implement V2 36 | func (*ManifestRequest) Validate() error { 37 | return nil 38 | } 39 | 40 | // ############################################################################ 41 | // Response 42 | // ############################################################################ 43 | 44 | // The expected response from the manifest method. 45 | type ManifestResponse struct { 46 | Details ManifestDetails `json:"details,omitempty"` 47 | Manifest string `json:"manifest,omitempty"` 48 | Requested string `json:"requested"` 49 | } 50 | --------------------------------------------------------------------------------