xrpl-ruby 0.2.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/LICENSE +21 -0
- data/README.md +94 -0
- data/lib/address-codec/address_codec.rb +21 -4
- data/lib/address-codec/codec.rb +15 -2
- data/lib/address-codec/xrp_codec.rb +29 -2
- data/lib/binary-codec/binary_codec.rb +47 -21
- data/lib/binary-codec/enums/definitions.json +592 -1
- data/lib/binary-codec/enums/definitions.rb +23 -9
- data/lib/binary-codec/enums/fields.rb +3 -1
- data/lib/binary-codec/serdes/binary_parser.rb +44 -10
- data/lib/binary-codec/serdes/binary_serializer.rb +29 -6
- data/lib/binary-codec/serdes/bytes_list.rb +12 -1
- data/lib/binary-codec/types/account_id.rb +18 -37
- data/lib/binary-codec/types/amount.rb +123 -77
- data/lib/binary-codec/types/blob.rb +14 -5
- data/lib/binary-codec/types/currency.rb +15 -4
- data/lib/binary-codec/types/hash.rb +37 -36
- data/lib/binary-codec/types/issue.rb +47 -0
- data/lib/binary-codec/types/path_set.rb +93 -0
- data/lib/binary-codec/types/serialized_type.rb +52 -28
- data/lib/binary-codec/types/st_array.rb +106 -0
- data/lib/binary-codec/types/st_object.rb +150 -14
- data/lib/binary-codec/types/uint.rb +166 -3
- data/lib/binary-codec/types/vector256.rb +53 -0
- data/lib/binary-codec/types/xchain_bridge.rb +47 -0
- data/lib/binary-codec/utilities.rb +18 -0
- data/lib/core/base_58_xrp.rb +2 -0
- data/lib/core/base_x.rb +10 -0
- data/lib/core/core.rb +44 -6
- data/lib/core/utilities.rb +38 -0
- data/lib/key-pairs/ed25519.rb +69 -0
- data/lib/key-pairs/key_pairs.rb +92 -0
- data/lib/key-pairs/secp256k1.rb +169 -0
- data/lib/wallet/wallet.rb +179 -0
- data/lib/xrpl/client.rb +498 -0
- data/lib/xrpl/faucet.rb +138 -0
- data/lib/xrpl/version.rb +5 -0
- data/lib/xrpl-ruby.rb +30 -1
- metadata +80 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a26ce8102c50640eec9433b64a9296c7d92635d66c42f2995456d913fff60d75
|
|
4
|
+
data.tar.gz: 60d3c026f1378a1d7cb79adcd6bbf830d518bb554b35286fe980010a14f4f11a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 975f1af5db2890d44ba6ac7266c2a927dc5e8bf4d3000a8e70bd864734dbba1e90495718b48300df5ca183077076de844b00c2844aa87c050d61263d5e43a12a
|
|
7
|
+
data.tar.gz: 85a70a5ebc31bde02941394182c93aeb1c09a57987fbadfcbac26efdd16e1b30fe786d1aefdefd2ee1fa3cf742b18dbde2edbb2983052869b8165411b6207fd5
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.6.0] - 2026-08-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Connection readiness**: `Client#connect!` (and `connect(wait: true)`) block until the
|
|
12
|
+
WebSocket connection is open; `#open?` and `#wait_until_open` expose the state, so requests
|
|
13
|
+
no longer race with connection setup.
|
|
14
|
+
- **Faucet helper**: `XRPL.fund_wallet(client)` / `XRPL::Faucet` creates and funds a wallet on
|
|
15
|
+
the Testnet and waits until the account is funded on the ledger.
|
|
16
|
+
- **Transaction lifecycle** on the client (client-centric design): `Client#autofill`,
|
|
17
|
+
`Client#submit`, and `Client#submit_and_wait` (reliable submission that polls until the
|
|
18
|
+
transaction is included in a validated ledger).
|
|
19
|
+
- **Optional logger**: `Client.new(url, logger:)` — the library is silent by default and only
|
|
20
|
+
emits diagnostics through an injected logger.
|
|
21
|
+
- Example scripts for funding a wallet, querying account info, and sending a payment.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- The library no longer writes to `stdout` on its own; connection messages go through the
|
|
25
|
+
optional logger instead.
|
|
26
|
+
|
|
27
|
+
## [0.5.2]
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- Binary codec, address codec, key pairs (secp256k1 / ed25519), wallet, and a WebSocket
|
|
31
|
+
client with account and ledger public API wrappers.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Alexander Busse
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# XRPL-Ruby
|
|
2
|
+
|
|
3
|
+
A pure-Ruby library to interact with the [XRP Ledger](https://xrpl.org) (XRPL) blockchain.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Key and wallet management (secp256k1 and ed25519)
|
|
8
|
+
- Address codec and binary (transaction) codec
|
|
9
|
+
- WebSocket client for the XRP Ledger public API
|
|
10
|
+
- Testnet faucet helper to create and fund wallets
|
|
11
|
+
- Transaction lifecycle: autofill, sign, submit, and reliable "submit and wait"
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Ruby 3.0 or later
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Install the gem:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
gem install xrpl-ruby
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or add it to your `Gemfile`:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
gem 'xrpl-ruby'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick start
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require 'xrpl-ruby'
|
|
35
|
+
|
|
36
|
+
# 1. Connect to the Testnet (blocks until the connection is ready)
|
|
37
|
+
client = XRPL::Client.new(:testnet)
|
|
38
|
+
client.connect!
|
|
39
|
+
|
|
40
|
+
# 2. Create and fund a wallet using the Testnet faucet
|
|
41
|
+
wallet = XRPL.fund_wallet(client)[:wallet]
|
|
42
|
+
puts wallet.classic_address
|
|
43
|
+
|
|
44
|
+
# 3. Look up the account on the ledger
|
|
45
|
+
info = client.account_info_response(
|
|
46
|
+
account: wallet.classic_address,
|
|
47
|
+
ledger_index: 'validated'
|
|
48
|
+
)
|
|
49
|
+
puts info.dig('result', 'account_data', 'Balance')
|
|
50
|
+
|
|
51
|
+
# 4. Send 1 XRP (1,000,000 drops) and wait for validation
|
|
52
|
+
receiver = XRPL.fund_wallet(client)[:wallet]
|
|
53
|
+
payment = {
|
|
54
|
+
'TransactionType' => 'Payment',
|
|
55
|
+
'Account' => wallet.classic_address,
|
|
56
|
+
'Destination' => receiver.classic_address,
|
|
57
|
+
'Amount' => '1000000'
|
|
58
|
+
}
|
|
59
|
+
result = client.submit_and_wait(payment, wallet: wallet)
|
|
60
|
+
puts result.dig('result', 'meta', 'TransactionResult') # => "tesSUCCESS"
|
|
61
|
+
|
|
62
|
+
client.disconnect
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The client is silent by default. To see diagnostic output, pass a logger:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
require 'logger'
|
|
69
|
+
client = XRPL::Client.new(:testnet, logger: Logger.new($stdout))
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
More runnable examples are in the [`examples/`](examples) directory.
|
|
73
|
+
|
|
74
|
+
## Running the tests
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
bundle install
|
|
78
|
+
bundle exec rspec
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Integration tests talk to the real Testnet and are skipped by default. Enable them explicitly:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
XRPL_NETWORK=1 bundle exec rspec spec/integration
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Contributing
|
|
88
|
+
|
|
89
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
90
|
+
<https://github.com/AlexanderBuzz/xrpl-ruby>.
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
Released under the [MIT License](LICENSE).
|
|
@@ -11,21 +11,31 @@ module AddressCodec
|
|
|
11
11
|
|
|
12
12
|
MAX_32_BIT_UNSIGNED_INT = 4294967295
|
|
13
13
|
|
|
14
|
+
# Converts a classic address to an X-address.
|
|
15
|
+
# @param classic_address [String] The classic XRPL address to convert.
|
|
16
|
+
# @param tag [Integer, false, nil] The destination tag.
|
|
17
|
+
# @param test [Boolean] Whether the address is for a test network.
|
|
18
|
+
# @return [String] The encoded X-address.
|
|
14
19
|
def classic_address_to_x_address(classic_address, tag, test)
|
|
15
20
|
account_id = decode_account_id(classic_address)
|
|
16
21
|
encode_x_address(account_id, tag, test)
|
|
17
22
|
end
|
|
18
23
|
|
|
24
|
+
# Encodes an account ID and tag into an X-address.
|
|
25
|
+
# @param account_id [Array<Integer>] 20 bytes for the account ID.
|
|
26
|
+
# @param tag [Integer, false, nil] The destination tag.
|
|
27
|
+
# @param test [Boolean] Whether the address is for a test network.
|
|
28
|
+
# @return [String] The encoded X-address.
|
|
19
29
|
def encode_x_address(account_id, tag, test)
|
|
20
30
|
if account_id.length != 20
|
|
21
31
|
# RIPEMD160 -> 160 Bits = 20 Bytes
|
|
22
32
|
raise 'Account ID must be 20 bytes'
|
|
23
33
|
end
|
|
24
|
-
if tag != false && tag > MAX_32_BIT_UNSIGNED_INT
|
|
34
|
+
if tag && tag != false && tag > MAX_32_BIT_UNSIGNED_INT
|
|
25
35
|
raise 'Invalid tag'
|
|
26
36
|
end
|
|
27
37
|
the_tag = tag || 0
|
|
28
|
-
flag = tag == false || tag.nil? ? 0 : 1
|
|
38
|
+
flag = (tag == false || tag.nil?) ? 0 : 1
|
|
29
39
|
|
|
30
40
|
bytes = concat_args(
|
|
31
41
|
test ? PREFIX_BYTES[:test] : PREFIX_BYTES[:main],
|
|
@@ -46,6 +56,9 @@ module AddressCodec
|
|
|
46
56
|
encode_checked(bytes)
|
|
47
57
|
end
|
|
48
58
|
|
|
59
|
+
# Converts an X-address to a classic address.
|
|
60
|
+
# @param x_address [String] The X-address string to convert.
|
|
61
|
+
# @return [Hash] A hash containing :classic_address, :tag, and :test.
|
|
49
62
|
def x_address_to_classic_address(x_address)
|
|
50
63
|
decoded = decode_x_address(x_address)
|
|
51
64
|
account_id = decoded[:account_id]
|
|
@@ -59,6 +72,9 @@ module AddressCodec
|
|
|
59
72
|
}
|
|
60
73
|
end
|
|
61
74
|
|
|
75
|
+
# Decodes an X-address into its underlying account ID, tag, and network type.
|
|
76
|
+
# @param x_address [String] The X-address string to decode.
|
|
77
|
+
# @return [Hash] A hash containing :account_id, :tag, and :test.
|
|
62
78
|
def decode_x_address(x_address)
|
|
63
79
|
decoded = decode_checked(x_address)
|
|
64
80
|
test = is_uint8_array_for_test_address(decoded)
|
|
@@ -71,6 +87,9 @@ module AddressCodec
|
|
|
71
87
|
}
|
|
72
88
|
end
|
|
73
89
|
|
|
90
|
+
# Checks if a string is a valid X-address.
|
|
91
|
+
# @param x_address [String] The X-address string to check.
|
|
92
|
+
# @return [Boolean] True if the X-address is valid, false otherwise.
|
|
74
93
|
def valid_x_address?(x_address)
|
|
75
94
|
begin
|
|
76
95
|
decode_x_address(x_address)
|
|
@@ -97,11 +116,9 @@ module AddressCodec
|
|
|
97
116
|
def tag_from_uint8_array(bytes)
|
|
98
117
|
flag = bytes[22]
|
|
99
118
|
if flag >= 2
|
|
100
|
-
# Keine Unterstützung für 64-Bit-Tags zu diesem Zeitpunkt
|
|
101
119
|
raise 'Unsupported X-address'
|
|
102
120
|
end
|
|
103
121
|
if flag == 1
|
|
104
|
-
# Little-endian zu Big-endian
|
|
105
122
|
return bytes[23] + bytes[24] * 0x100 + bytes[25] * 0x10000 + bytes[26] * 0x1000000
|
|
106
123
|
end
|
|
107
124
|
if flag != 0
|
data/lib/address-codec/codec.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
require 'digest'
|
|
4
|
-
require_relative "../core/core"
|
|
5
4
|
|
|
6
5
|
module AddressCodec
|
|
7
6
|
class Codec
|
|
@@ -10,11 +9,19 @@ module AddressCodec
|
|
|
10
9
|
@codec = Core::Base58XRP.new
|
|
11
10
|
end
|
|
12
11
|
|
|
12
|
+
# Encodes a byte array into a base58 string with a version prefix and checksum.
|
|
13
|
+
# @param bytes [Array<Integer>] The byte array to encode.
|
|
14
|
+
# @param opts [Hash] Options for encoding (e.g., :versions, :expected_length).
|
|
15
|
+
# @return [String] The encoded base58 string.
|
|
13
16
|
def encode(bytes, opts)
|
|
14
17
|
versions = opts[:versions]
|
|
15
18
|
encode_versioned(bytes, versions, opts[:expected_length])
|
|
16
19
|
end
|
|
17
20
|
|
|
21
|
+
# Decodes a base58 string and verifies its version and checksum.
|
|
22
|
+
# @param base58string [String] The base58 string to decode.
|
|
23
|
+
# @param opts [Hash] Options for decoding (e.g., :versions, :version_types, :expected_length).
|
|
24
|
+
# @return [Hash] The decoded data including version, bytes, and type.
|
|
18
25
|
def decode(base58string, opts)
|
|
19
26
|
versions = opts[:versions]
|
|
20
27
|
types = opts[:version_types]
|
|
@@ -44,11 +51,17 @@ module AddressCodec
|
|
|
44
51
|
raise 'version_invalid: version bytes do not match any of the provided version(s)'
|
|
45
52
|
end
|
|
46
53
|
|
|
54
|
+
# Encodes a byte array into a base58 string with a checksum.
|
|
55
|
+
# @param bytes [Array<Integer>] The byte array to encode.
|
|
56
|
+
# @return [String] The encoded base58 string.
|
|
47
57
|
def encode_checked(bytes)
|
|
48
58
|
check = sha256(sha256(bytes))[0, 4]
|
|
49
59
|
encode_raw(bytes + check)
|
|
50
60
|
end
|
|
51
61
|
|
|
62
|
+
# Decodes a base58 string and verifies its checksum.
|
|
63
|
+
# @param base58string [String] The base58 string to decode.
|
|
64
|
+
# @return [Array<Integer>] The decoded byte array (without checksum).
|
|
52
65
|
def decode_checked(base58string)
|
|
53
66
|
bytes = decode_raw(base58string)
|
|
54
67
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../core/core"
|
|
4
|
-
|
|
5
3
|
module AddressCodec
|
|
6
4
|
|
|
7
5
|
class XrpCodec < Codec
|
|
@@ -13,6 +11,10 @@ module AddressCodec
|
|
|
13
11
|
NODE_PUBLIC = 0x1c # 28; Validation public key (33 bytes)
|
|
14
12
|
ED25519_SEED = [0x01, 0xe1, 0x4b].freeze # [1, 225, 75]
|
|
15
13
|
|
|
14
|
+
# Encodes entropy into a seed string.
|
|
15
|
+
# @param entropy [Array<Integer>] 16 bytes of entropy.
|
|
16
|
+
# @param type [String, nil] The seed type ('ed25519' or 'secp256k1').
|
|
17
|
+
# @return [String] The encoded seed string.
|
|
16
18
|
def encode_seed(entropy, type = nil)
|
|
17
19
|
unless check_byte_length(entropy, 16)
|
|
18
20
|
raise 'entropy must have length 16'
|
|
@@ -27,6 +29,10 @@ module AddressCodec
|
|
|
27
29
|
encode(entropy, opts)
|
|
28
30
|
end
|
|
29
31
|
|
|
32
|
+
# Decodes a seed string into its underlying bytes and type.
|
|
33
|
+
# @param seed [String] The seed string to decode.
|
|
34
|
+
# @param opts [Hash] Options for decoding (e.g., :versions, :version_types, :expected_length).
|
|
35
|
+
# @return [Hash] The decoded data including version, bytes, and type.
|
|
30
36
|
def decode_seed(seed, opts = {
|
|
31
37
|
version_types: ['ed25519', 'secp256k1'],
|
|
32
38
|
versions: [ED25519_SEED, FAMILY_SEED],
|
|
@@ -35,36 +41,57 @@ module AddressCodec
|
|
|
35
41
|
decode(seed, opts)
|
|
36
42
|
end
|
|
37
43
|
|
|
44
|
+
# Encodes a byte array into an account ID string.
|
|
45
|
+
# @param bytes [Array<Integer>] 20 bytes for the account ID.
|
|
46
|
+
# @return [String] The encoded account ID string.
|
|
38
47
|
def encode_account_id(bytes)
|
|
39
48
|
opts = { versions: [ACCOUNT_ID], expected_length: 20 }
|
|
40
49
|
encode(bytes, opts)
|
|
41
50
|
end
|
|
42
51
|
|
|
52
|
+
# Decodes an account ID string into its underlying bytes.
|
|
53
|
+
# @param account_id [String] The account ID string to decode.
|
|
54
|
+
# @return [Array<Integer>] The decoded bytes.
|
|
43
55
|
def decode_account_id(account_id)
|
|
44
56
|
opts = { versions: [ACCOUNT_ID], expected_length: 20 }
|
|
45
57
|
decode(account_id, opts)[:bytes]
|
|
46
58
|
end
|
|
47
59
|
|
|
60
|
+
# Decodes a node public key string into its underlying bytes.
|
|
61
|
+
# @param base58string [String] The node public key string to decode.
|
|
62
|
+
# @return [Array<Integer>] The decoded bytes.
|
|
48
63
|
def decode_node_public(base58string)
|
|
49
64
|
opts = { versions: [NODE_PUBLIC], expected_length: 33 }
|
|
50
65
|
decode(base58string, opts)[:bytes]
|
|
51
66
|
end
|
|
52
67
|
|
|
68
|
+
# Encodes a byte array into a node public key string.
|
|
69
|
+
# @param bytes [Array<Integer>] 33 bytes for the node public key.
|
|
70
|
+
# @return [String] The encoded node public key string.
|
|
53
71
|
def encode_node_public(bytes)
|
|
54
72
|
opts = { versions: [NODE_PUBLIC], expected_length: 33 }
|
|
55
73
|
encode(bytes, opts)
|
|
56
74
|
end
|
|
57
75
|
|
|
76
|
+
# Encodes a byte array into an account public key string.
|
|
77
|
+
# @param bytes [Array<Integer>] 33 bytes for the account public key.
|
|
78
|
+
# @return [String] The encoded account public key string.
|
|
58
79
|
def encode_account_public(bytes)
|
|
59
80
|
opts = { versions: [ACCOUNT_PUBLIC_KEY], expected_length: 33 }
|
|
60
81
|
encode(bytes, opts)
|
|
61
82
|
end
|
|
62
83
|
|
|
84
|
+
# Decodes an account public key string into its underlying bytes.
|
|
85
|
+
# @param base58string [String] The account public key string to decode.
|
|
86
|
+
# @return [Array<Integer>] The decoded bytes.
|
|
63
87
|
def decode_account_public(base58string)
|
|
64
88
|
opts = { versions: [ACCOUNT_PUBLIC_KEY], expected_length: 33 }
|
|
65
89
|
decode(base58string, opts)[:bytes]
|
|
66
90
|
end
|
|
67
91
|
|
|
92
|
+
# Checks if a string is a valid classic XRPL address.
|
|
93
|
+
# @param address [String] The address string to check.
|
|
94
|
+
# @return [Boolean] True if the address is valid, false otherwise.
|
|
68
95
|
def valid_classic_address?(address)
|
|
69
96
|
begin
|
|
70
97
|
decode_account_id(address)
|
|
@@ -1,38 +1,64 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module BinaryCodec
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
# Hash prefixes for serialization.
|
|
5
|
+
HASH_PREFIX = {
|
|
6
|
+
transaction_sig: 0x53545800, # 'STX\0'
|
|
7
|
+
transaction_multi_sig: 0x534D5400, # 'SMT\0'
|
|
8
|
+
validation: 0x56414C00, # 'VAL\0'
|
|
9
|
+
proposal: 0x50525000 # 'PRP\0'
|
|
10
|
+
}.freeze
|
|
7
11
|
|
|
12
|
+
# from here: https://github.com/XRPLF/xrpl.js/blob/main/packages/ripple-binary-codec/src/binary.ts
|
|
13
|
+
class << self
|
|
14
|
+
# Creates a BinaryParser for the given bytes.
|
|
15
|
+
# @param bytes [String, Array<Integer>] The bytes to parse (hex string or byte array).
|
|
16
|
+
# @param definitions [Definitions, nil] Optional definitions.
|
|
17
|
+
# @return [BinaryParser] The created parser.
|
|
8
18
|
def make_parser(bytes, definitions = nil)
|
|
9
19
|
BinaryParser.new(bytes.is_a?(String) ? bytes : bytes_to_hex(bytes))
|
|
10
20
|
end
|
|
11
21
|
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
parser.read_type(core_types[:STObject]).to_json()
|
|
16
|
-
end
|
|
17
|
-
|
|
22
|
+
# Converts a hex string to its JSON representation.
|
|
23
|
+
# @param hex [String] The hex string to convert.
|
|
24
|
+
# @return [Hash] The decoded JSON object.
|
|
18
25
|
def binary_to_json(hex)
|
|
19
26
|
parser = make_parser(hex)
|
|
20
|
-
|
|
27
|
+
st_object = SerializedType.get_type_by_name('STObject')
|
|
28
|
+
result = st_object.from_parser(parser).to_json
|
|
29
|
+
result = JSON.generate(result) unless result.is_a?(String)
|
|
30
|
+
JSON.parse(result)
|
|
21
31
|
end
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
# Converts a JSON object to its binary representation.
|
|
34
|
+
# @param json [Hash] The JSON object to convert.
|
|
35
|
+
# @return [String] The serialized hex string.
|
|
36
|
+
def json_to_binary(json)
|
|
37
|
+
st_object = SerializedType.get_type_by_name('STObject')
|
|
38
|
+
st_object.from(json).to_hex
|
|
25
39
|
end
|
|
26
40
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
# Generates signing data for a transaction.
|
|
42
|
+
# @param transaction [Hash] The transaction to serialize.
|
|
43
|
+
# @param prefix [Integer] The prefix to add to the serialized data.
|
|
44
|
+
# @param opts [Hash] Optional settings (e.g., :definitions, :signing_fields_only).
|
|
45
|
+
# @return [Array<Integer>] The serialized signing data.
|
|
46
|
+
def signing_data(transaction, prefix = HASH_PREFIX[:transaction_sig], opts = {})
|
|
47
|
+
# 1. Start with the prefix bytes
|
|
48
|
+
prefix_bytes = int_to_bytes(prefix, 4)
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
# 2. Serialize the object, only including signing fields
|
|
51
|
+
st_object_class = SerializedType.get_type_by_name('STObject')
|
|
37
52
|
|
|
53
|
+
filter = if opts[:signing_fields_only]
|
|
54
|
+
lambda { |field_name| Definitions.instance.get_field_instance(field_name).is_signing_field }
|
|
55
|
+
else
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
serialized_bytes = st_object_class.from(transaction, filter).to_bytes
|
|
60
|
+
|
|
61
|
+
prefix_bytes + serialized_bytes
|
|
62
|
+
end
|
|
63
|
+
end
|
|
38
64
|
end
|