xrpl-ruby 0.0.3 → 0.5.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/address-codec/address_codec.rb +22 -4
  3. data/lib/address-codec/codec.rb +15 -2
  4. data/lib/address-codec/xrp_codec.rb +29 -2
  5. data/lib/binary-codec/binary_codec.rb +62 -0
  6. data/lib/binary-codec/enums/constants.rb +8 -0
  7. data/lib/binary-codec/enums/definitions.json +3774 -0
  8. data/lib/binary-codec/enums/definitions.rb +90 -0
  9. data/lib/binary-codec/enums/fields.rb +104 -0
  10. data/lib/binary-codec/serdes/binary_parser.rb +183 -0
  11. data/lib/binary-codec/serdes/binary_serializer.rb +93 -0
  12. data/lib/binary-codec/serdes/bytes_list.rb +47 -0
  13. data/lib/binary-codec/types/account_id.rb +60 -0
  14. data/lib/binary-codec/types/amount.rb +304 -0
  15. data/lib/binary-codec/types/blob.rb +41 -0
  16. data/lib/binary-codec/types/currency.rb +116 -0
  17. data/lib/binary-codec/types/hash.rb +106 -0
  18. data/lib/binary-codec/types/issue.rb +50 -0
  19. data/lib/binary-codec/types/path_set.rb +93 -0
  20. data/lib/binary-codec/types/serialized_type.rb +157 -0
  21. data/lib/binary-codec/types/st_array.rb +71 -0
  22. data/lib/binary-codec/types/st_object.rb +157 -0
  23. data/lib/binary-codec/types/uint.rb +166 -0
  24. data/lib/binary-codec/types/vector256.rb +53 -0
  25. data/lib/binary-codec/types/xchain_bridge.rb +47 -0
  26. data/lib/binary-codec/utilities.rb +98 -0
  27. data/lib/core/base_58_xrp.rb +2 -0
  28. data/lib/core/base_x.rb +10 -0
  29. data/lib/core/core.rb +79 -6
  30. data/lib/core/utilities.rb +38 -0
  31. data/lib/key-pairs/ed25519.rb +64 -0
  32. data/lib/key-pairs/key_pairs.rb +92 -0
  33. data/lib/key-pairs/secp256k1.rb +116 -0
  34. data/lib/wallet/wallet.rb +117 -0
  35. data/lib/xrpl-ruby.rb +32 -1
  36. metadata +44 -3
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinaryCodec
4
+ class SerializedType
5
+
6
+ attr_reader :bytes
7
+
8
+ # Initializes a new SerializedType instance.
9
+ # @param bytes [Array<Integer>, nil] The byte array representing the serialized data.
10
+ def initialize(bytes = nil)
11
+ @bytes = bytes
12
+ end
13
+
14
+ # Creates a new instance of the type from a value.
15
+ # @param value [Object] The value to convert.
16
+ # @return [SerializedType] The created instance.
17
+ def self.from(value)
18
+ raise NotImplementedError, 'from not implemented'
19
+ end
20
+
21
+ # Creates an instance of the type from a parser.
22
+ # @param parser [BinaryParser] The parser to read from.
23
+ # @param size_hint [Integer, nil] Optional size hint.
24
+ # @return [SerializedType] The created instance.
25
+ def self.from_parser(parser, size_hint = nil)
26
+ raise NotImplementedError, 'from_parser not implemented'
27
+ end
28
+
29
+ # Check if this is needed
30
+ def self.from_json(json)
31
+ raise NotImplementedError, 'from_parser not implemented'
32
+ end
33
+
34
+ # Check if this is needed
35
+ def self.from_hex(hex)
36
+ self.from_bytes(hex_to_bytes(hex))
37
+ end
38
+
39
+ # Check if this is needed
40
+ def self.from_bytes(bytes)
41
+ new(bytes)
42
+ end
43
+
44
+ # Puts the serialized data into a byte sink.
45
+ # @param sink [Object] The sink to put bytes into.
46
+ def to_byte_sink(sink)
47
+ sink.put(to_bytes)
48
+ end
49
+
50
+ # Serialize the given value into bytes
51
+ # This method must be implemented in the subclasses
52
+ # @return [Array<Integer>] - Byte array representing the serialized data
53
+ def to_bytes
54
+ @bytes
55
+ end
56
+
57
+ # Convert to a hex string
58
+ # @return [String] - Hexadecimal representation of the serialized data
59
+ def to_hex
60
+ bytes_to_hex(to_bytes)
61
+ end
62
+
63
+ # Deserialize instance data and convert it to JSON string
64
+ #
65
+ # @param _definitions [Hash] - Definitions for serialization
66
+ # @param _field_name [String] - Field name for serialization
67
+ # @return [String] - JSON representation of the serialized data
68
+ def to_json(_definitions = nil, _field_name = nil)
69
+ to_hex
70
+ end
71
+
72
+ # Returns the value of the serialized type
73
+ # @return [Object] - The value of the serialized type
74
+ def value_of
75
+ @bytes
76
+ end
77
+
78
+ # Returns the class for a given type name.
79
+ # @param name [String] The name of the type.
80
+ # @return [Class] The class associated with the type name.
81
+ def self.get_type_by_name(name)
82
+ case name
83
+ when "AccountID" then AccountId
84
+ when "Amount" then Amount
85
+ when "Blob" then Blob
86
+ when "Currency" then Currency
87
+ when "Hash128" then Hash128
88
+ when "Hash160" then Hash160
89
+ when "Hash192" then Hash192
90
+ when "Hash256" then Hash256
91
+ when "STArray" then STArray
92
+ when "STObject" then STObject
93
+ when "UInt8" then Uint8
94
+ when "UInt16" then Uint16
95
+ when "UInt32" then Uint32
96
+ when "UInt64" then Uint64
97
+ when "UInt96" then Uint96
98
+ when "UInt128" then Uint128
99
+ when "UInt160" then Uint160
100
+ when "UInt192" then Uint192
101
+ when "UInt256" then Uint256
102
+ when "UInt384" then Uint384
103
+ when "UInt512" then Uint512
104
+ when "Int32" then Int32
105
+ when "Int64" then Int64
106
+ when "PathSet" then PathSet
107
+ when "Vector256" then Vector256
108
+ when "XChainBridge" then XChainBridge
109
+ when "Issue" then Issue
110
+ when "Transaction" then Blob
111
+ when "LedgerEntry" then Blob
112
+ when "Validation" then Blob
113
+ when "Metadata" then Blob
114
+ else
115
+ raise "unsupported type #{name}"
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ class ComparableSerializedType < SerializedType
122
+
123
+ # Compare if `self` is less than `other`
124
+ def lt(other)
125
+ compare_to(other) < 0
126
+ end
127
+
128
+ # Compare if `self` is equal to `other`
129
+ def eq(other)
130
+ compare_to(other) == 0
131
+ end
132
+
133
+ # Compare if `self` is greater than `other`
134
+ def gt(other)
135
+ compare_to(other) > 0
136
+ end
137
+
138
+ # Compare if `self` is greater than or equal to `other`
139
+ def gte(other)
140
+ compare_to(other) >= 0
141
+ end
142
+
143
+ # Compare if `self` is less than or equal to `other`
144
+ def lte(other)
145
+ compare_to(other) <= 0
146
+ end
147
+
148
+ # Overload this method in subclasses to define comparison logic
149
+ #
150
+ # @param other [Object] - The object to compare `self` to
151
+ # @return [Integer] - Returns -1, 0, or 1 depending on the comparison
152
+ def compare_to(other)
153
+ raise NotImplementedError, "Cannot compare #{self} and #{other}"
154
+ end
155
+ end
156
+
157
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinaryCodec
4
+ class STArray < SerializedType
5
+ def initialize(byte_buf = nil)
6
+ super(byte_buf || [])
7
+ end
8
+
9
+ # Creates a new STArray instance from a value.
10
+ # @param value [STArray, String, Array<Hash>] The value to convert.
11
+ # @param definitions [Definitions, nil] Optional definitions.
12
+ # @return [STArray] The created instance.
13
+ def self.from(value, definitions = nil)
14
+ return value if value.is_a?(STArray)
15
+ definitions ||= Definitions.instance
16
+
17
+ if value.is_a?(String)
18
+ return STArray.new(hex_to_bytes(value))
19
+ end
20
+
21
+ if value.is_a?(Array)
22
+ bytes = []
23
+ value.each do |item|
24
+ obj = STObject.from(item, nil, definitions)
25
+ bytes.concat(obj.to_bytes)
26
+ bytes.concat([0xF1]) # ArrayItemEndMarker
27
+ end
28
+ bytes.concat([0xF1]) # ArrayEndMarker
29
+ return STArray.new(bytes)
30
+ end
31
+
32
+ raise StandardError, "Cannot construct STArray from #{value.class}"
33
+ end
34
+
35
+ # Creates an STArray instance from a parser.
36
+ # @param parser [BinaryParser] The parser to read from.
37
+ # @param _hint [Integer, nil] Unused hint.
38
+ # @return [STArray] The created instance.
39
+ def self.from_parser(parser, _hint = nil)
40
+ bytes = []
41
+ until parser.end?(1) # Look ahead for end marker
42
+ obj = STObject.from_parser(parser)
43
+ bytes.concat(obj.to_bytes)
44
+ bytes.concat(parser.read(1)) # Should be 0xF1 (ArrayItemEndMarker)
45
+ end
46
+ parser.read(1) # Consume 0xF1 (ArrayEndMarker)
47
+ STArray.new(bytes)
48
+ end
49
+
50
+ # Returns the JSON representation of the STArray.
51
+ # @param _definitions [Definitions, nil] Unused.
52
+ # @param _field_name [String, nil] Unused.
53
+ # @return [Array<Hash>] The JSON representation.
54
+ def to_json(_definitions = nil, _field_name = nil)
55
+ parser = BinaryParser.new(to_hex)
56
+ result = []
57
+ until parser.end?
58
+ obj = STObject.from_parser(parser)
59
+ result << JSON.parse(obj.to_json)
60
+ # In xrpl.js, array items are STObjects.
61
+ # After each STObject, there might be an ArrayItemEndMarker if we're not at the end.
62
+ # But wait, STObject.from_parser already reads until ObjectEndMarker.
63
+ # STArray in XRPL is a list of objects, each ending with ObjectEndMarker.
64
+ # The whole array ends with ArrayEndMarker (0xF1).
65
+ # Actually, standard XRPL STArray: [FieldHeader][STObject][FieldHeader][STObject]...[0xF1]
66
+ # Wait, I need to check how xrpl.js handles STArray.
67
+ end
68
+ result
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinaryCodec
4
+ class STObject < SerializedType
5
+
6
+ OBJECT_END_MARKER_BYTE = [225]
7
+ OBJECT_END_MARKER = 'ObjectEndMarker'.freeze
8
+ ST_OBJECT = 'STObject'.freeze
9
+ DESTINATION = 'Destination'.freeze
10
+ ACCOUNT = 'Account'.freeze
11
+ SOURCE_TAG = 'SourceTag'.freeze
12
+ DEST_TAG = 'DestinationTag'.freeze
13
+
14
+ # attr_reader :type, :bytes
15
+ #
16
+ def initialize(byte_buf = nil)
17
+ @bytes = byte_buf || Array.new(0)
18
+ end
19
+
20
+ # Creates a new STObject instance from a value.
21
+ # @param value [STObject, String, Array<Integer>, Hash] The value to convert.
22
+ # @param filter [Proc, nil] Optional filter for fields.
23
+ # @param definitions [Definitions, nil] Optional definitions.
24
+ # @return [STObject] The created instance.
25
+ def self.from(value, filter = nil, definitions = nil)
26
+ return value if value.is_a?(STObject)
27
+ definitions ||= Definitions.instance
28
+
29
+ if value.is_a?(String)
30
+ return STObject.new(hex_to_bytes(value))
31
+ end
32
+
33
+ if value.is_a?(Array)
34
+ return STObject.new(value)
35
+ end
36
+
37
+ list = BytesList.new
38
+ serializer = BinarySerializer.new(list)
39
+ is_unl_modify = false
40
+
41
+ # Handle X-Addresses and check for duplicate tags
42
+ processed_value = value.each_with_object({}) do |(key, val), acc|
43
+ if val && val.is_a?(String) && AddressCodec::AddressCodec.new.valid_x_address?(val)
44
+ handled = handle_x_address(key.to_s, val)
45
+ check_for_duplicate_tags(handled, value)
46
+ acc.merge!(handled)
47
+ else
48
+ acc[key.to_s] = val
49
+ end
50
+ end
51
+
52
+ sorted_fields = processed_value.keys.map do |field_name|
53
+ field = definitions.get_field_instance(field_name)
54
+ raise "Field #{field_name} is not defined" if field.nil?
55
+ field
56
+ end.select(&:is_serialized).sort_by(&:ordinal)
57
+
58
+ if filter
59
+ sorted_fields = sorted_fields.select { |f| filter.call(f.name) }
60
+ end
61
+
62
+ sorted_fields.each do |field|
63
+ associated_value = processed_value[field.name]
64
+ next if associated_value.nil?
65
+
66
+ # Special handling for UNLModify
67
+ if field.name == 'UNLModify' # This might need more specific check depending on value
68
+ is_unl_modify = true
69
+ end
70
+ is_unl_modify_workaround = (field.name == 'Account' && is_unl_modify)
71
+
72
+ serializer.write_field_and_value(field, associated_value, is_unl_modify_workaround)
73
+
74
+ if field.type == 'STObject'
75
+ serializer.put(OBJECT_END_MARKER_BYTE)
76
+ end
77
+ end
78
+
79
+ STObject.new(list.to_bytes)
80
+ end
81
+
82
+ # Construct a STObject from a BinaryParser
83
+ #
84
+ # @param parser [BinaryParser] BinaryParser to read STObject from
85
+ # @param size_hint [Integer] Optional size hint for the object
86
+ # @return [STObject] A STObject object
87
+ def self.from_parser(parser, size_hint = nil)
88
+ list = BytesList.new
89
+ bytes = BinarySerializer.new(list)
90
+
91
+ until parser.end?
92
+ field = parser.read_field
93
+
94
+ break if field.name == OBJECT_END_MARKER
95
+
96
+ associated_value = parser.read_field_value(field)
97
+
98
+ bytes.write_field_and_value(field, associated_value)
99
+ bytes.put(OBJECT_END_MARKER_BYTE) if field.type == ST_OBJECT
100
+ end
101
+
102
+ STObject.new(list.to_bytes)
103
+ end
104
+
105
+ # Method to get the JSON interpretation of self.bytes
106
+ #
107
+ # @return [String] A stringified JSON object
108
+ def to_json(_definitions = nil, _field_name = nil)
109
+ parser = BinaryParser.new(to_hex)
110
+ accumulator = {}
111
+
112
+ until parser.end?
113
+ field = parser.read_field
114
+ break if field.name == OBJECT_END_MARKER # Break if the object end marker is reached
115
+ value = parser.read_field_value(field).to_json
116
+ value = JSON.parse(value) if field.type == ST_OBJECT || field.type == Amount
117
+ accumulator[field.name] = value
118
+ end
119
+
120
+ JSON.generate(accumulator)
121
+ end
122
+
123
+ private
124
+
125
+ # Break down an X-Address into an account and a tag
126
+ #
127
+ # @param field [String] Name of the field
128
+ # @param x_address [String] X-Address corresponding to the field
129
+ # @return [Hash] A hash with the classic address and tag (if present)
130
+ def handle_x_address(field, x_address)
131
+ address_codec = AddressCodec::AddressCodec.new
132
+ decoded = address_codec.x_address_to_classic_address(x_address)
133
+
134
+ tag_name = if field == 'Destination'
135
+ 'DestinationTag'
136
+ elsif field == 'Account'
137
+ 'SourceTag'
138
+ elsif decoded[:tag]
139
+ raise "#{field} cannot have an associated tag"
140
+ end
141
+
142
+ decoded[:tag] ? { field => decoded[:classic_address], tag_name => decoded[:tag] } : { field => decoded[:classic_address] }
143
+ end
144
+
145
+ def self.check_for_duplicate_tags(obj1, obj2)
146
+ if obj1['SourceTag'] && obj2['SourceTag']
147
+ raise 'Cannot have Account X-Address and SourceTag'
148
+ end
149
+
150
+ if obj1['DestinationTag'] && obj2['DestinationTag']
151
+ raise 'Cannot have Destination X-Address and DestinationTag'
152
+ end
153
+ end
154
+
155
+
156
+ end
157
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinaryCodec
4
+
5
+ class Uint < ComparableSerializedType
6
+ # Returns the width of the Uint type in bytes.
7
+ # @return [Integer] The width.
8
+ def self.width
9
+ @width
10
+ end
11
+
12
+ def initialize(byte_buf = nil)
13
+ super(byte_buf || Array.new(self.class.width, 0))
14
+ end
15
+
16
+ # Creates a new Uint instance from a value.
17
+ # @param value [Uint, String, Integer] The value to convert.
18
+ # @return [Uint] The created instance.
19
+ def self.from(value)
20
+ return value if value.is_a?(self)
21
+
22
+ if value.is_a?(String)
23
+ # Handle hex strings or numeric strings
24
+ if valid_hex?(value) && value.length == self.width * 2
25
+ return new(hex_to_bytes(value))
26
+ end
27
+ return new(int_to_bytes(value.to_i, width))
28
+ end
29
+
30
+ if value.is_a?(Integer)
31
+ return new(int_to_bytes(value, width))
32
+ end
33
+
34
+ raise StandardError, "Cannot construct #{self} from the value given"
35
+ end
36
+
37
+ # Creates a Uint instance from a parser.
38
+ # @param parser [BinaryParser] The parser to read from.
39
+ # @param _hint [Integer, nil] Unused hint.
40
+ # @return [Uint] The created instance.
41
+ def self.from_parser(parser, _hint = nil)
42
+ new(parser.read(width))
43
+ end
44
+
45
+ # Returns the numeric value of the Uint.
46
+ # @return [Integer] The numeric value.
47
+ def value_of
48
+ @bytes.reduce(0) { |acc, byte| (acc << 8) + byte }
49
+ end
50
+
51
+ # Compares this Uint to another Uint.
52
+ # @param other [Uint] The other Uint to compare to.
53
+ # @return [Integer] Comparison result (-1, 0, or 1).
54
+ def compare_to(other)
55
+ value_of <=> other.value_of
56
+ end
57
+ end
58
+
59
+ class Uint8 < Uint
60
+ # Uint8 is a 1-byte unsigned integer
61
+ @width = 1
62
+ end
63
+
64
+ class Uint16 < Uint
65
+ # Uint16 is a 2-byte unsigned integer
66
+ @width = 2
67
+ end
68
+
69
+ class Uint32 < Uint
70
+ # Uint32 is a 4-byte unsigned integer
71
+ @width = 4
72
+ end
73
+
74
+ class Uint64 < Uint
75
+ # Uint64 is an 8-byte unsigned integer
76
+ @width = 8
77
+ end
78
+
79
+ class Uint96 < Uint
80
+ # Uint96 is a 12-byte unsigned integer
81
+ @width = 12
82
+ end
83
+
84
+ class Uint128 < Uint
85
+ # Uint128 is a 16-byte unsigned integer
86
+ @width = 16
87
+ end
88
+
89
+ class Uint160 < Uint
90
+ # Uint160 is a 20-byte unsigned integer
91
+ @width = 20
92
+ end
93
+
94
+ class Uint192 < Uint
95
+ # Uint192 is a 24-byte unsigned integer
96
+ @width = 24
97
+ end
98
+
99
+ class Uint256 < Uint
100
+ # Uint256 is a 32-byte unsigned integer
101
+ @width = 32
102
+ end
103
+
104
+ class Uint384 < Uint
105
+ # Uint384 is a 48-byte unsigned integer
106
+ @width = 48
107
+ end
108
+
109
+ class Uint512 < Uint
110
+ # Uint512 is a 64-byte unsigned integer
111
+ @width = 64
112
+ end
113
+
114
+ class Int32 < Uint
115
+ @width = 4
116
+ # Returns the numeric value of the Int32.
117
+ # @return [Integer] The signed 32-bit value.
118
+ def value_of
119
+ val = super
120
+ val > 0x7FFFFFFF ? val - 0x100000000 : val
121
+ end
122
+
123
+ # Creates a new Int32 instance from a value.
124
+ # @param value [Int32, Integer] The value to convert.
125
+ # @return [Int32] The created instance.
126
+ def self.from(value)
127
+ return value if value.is_a?(self)
128
+ if value.is_a?(Integer)
129
+ # Ensure it fits in 32-bit signed
130
+ if value < -2147483648 || value > 2147483647
131
+ raise StandardError, "Value #{value} out of range for Int32"
132
+ end
133
+ # Convert to unsigned 32-bit for storage
134
+ u_val = value < 0 ? value + 0x100000000 : value
135
+ return new(int_to_bytes(u_val, 4))
136
+ end
137
+ super(value)
138
+ end
139
+ end
140
+
141
+ class Int64 < Uint
142
+ @width = 8
143
+ # Returns the numeric value of the Int64.
144
+ # @return [Integer] The signed 64-bit value.
145
+ def value_of
146
+ val = super
147
+ val > 0x7FFFFFFFFFFFFFFF ? val - 0x10000000000000000 : val
148
+ end
149
+
150
+ # Creates a new Int64 instance from a value.
151
+ # @param value [Int64, Integer] The value to convert.
152
+ # @return [Int64] The created instance.
153
+ def self.from(value)
154
+ return value if value.is_a?(self)
155
+ if value.is_a?(Integer)
156
+ if value < -9223372036854775808 || value > 9223372036854775807
157
+ raise StandardError, "Value #{value} out of range for Int64"
158
+ end
159
+ u_val = value < 0 ? value + 0x10000000000000000 : value
160
+ return new(int_to_bytes(u_val, 8))
161
+ end
162
+ super(value)
163
+ end
164
+ end
165
+
166
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinaryCodec
4
+ class Vector256 < SerializedType
5
+ def initialize(bytes = nil)
6
+ super(bytes || [])
7
+ end
8
+
9
+ # Creates a new Vector256 instance from a value.
10
+ # @param value [Vector256, String, Array<String>] The value to convert.
11
+ # @return [Vector256] The created instance.
12
+ def self.from(value)
13
+ return value if value.is_a?(Vector256)
14
+
15
+ if value.is_a?(String)
16
+ return Vector256.new(hex_to_bytes(value))
17
+ end
18
+
19
+ if value.is_a?(Array)
20
+ bytes = []
21
+ value.each do |item|
22
+ hash = Hash256.from(item)
23
+ bytes.concat(hash.to_bytes)
24
+ end
25
+ return Vector256.new(bytes)
26
+ end
27
+
28
+ raise StandardError, "Cannot construct Vector256 from #{value.class}"
29
+ end
30
+
31
+ # Creates a Vector256 instance from a parser.
32
+ # @param parser [BinaryParser] The parser to read from.
33
+ # @param size_hint [Integer] The expected total size in bytes.
34
+ # @return [Vector256] The created instance.
35
+ def self.from_parser(parser, size_hint = nil)
36
+ bytes = []
37
+ num_hashes = size_hint / 32
38
+ num_hashes.times do
39
+ bytes.concat(parser.read(32))
40
+ end
41
+ Vector256.new(bytes)
42
+ end
43
+
44
+ def to_json(_definitions = nil, _field_name = nil)
45
+ parser = BinaryParser.new(to_hex)
46
+ result = []
47
+ until parser.end?
48
+ result << bytes_to_hex(parser.read(32))
49
+ end
50
+ result
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BinaryCodec
4
+ class XChainBridge < SerializedType
5
+ def initialize(bytes = nil)
6
+ super(bytes || [])
7
+ end
8
+
9
+ def self.from(value)
10
+ return value if value.is_a?(XChainBridge)
11
+
12
+ if value.is_a?(String)
13
+ return XChainBridge.new(hex_to_bytes(value))
14
+ end
15
+
16
+ if value.is_a?(Hash)
17
+ bytes = []
18
+ bytes.concat(AccountId.from(value['LockingChainDoor']).to_bytes)
19
+ bytes.concat(Issue.from(value['LockingChainIssue']).to_bytes)
20
+ bytes.concat(AccountId.from(value['IssuingChainDoor']).to_bytes)
21
+ bytes.concat(Issue.from(value['IssuingChainIssue']).to_bytes)
22
+ return XChainBridge.new(bytes)
23
+ end
24
+
25
+ raise StandardError, "Cannot construct XChainBridge from #{value.class}"
26
+ end
27
+
28
+ def self.from_parser(parser, _hint = nil)
29
+ bytes = []
30
+ bytes.concat(parser.read(20)) # LockingChainDoor
31
+ bytes.concat(Issue.from_parser(parser).to_bytes) # LockingChainIssue
32
+ bytes.concat(parser.read(20)) # IssuingChainDoor
33
+ bytes.concat(Issue.from_parser(parser).to_bytes) # IssuingChainIssue
34
+ XChainBridge.new(bytes)
35
+ end
36
+
37
+ def to_json(_definitions = nil, _field_name = nil)
38
+ parser = BinaryParser.new(to_hex)
39
+ result = {}
40
+ result['LockingChainDoor'] = AccountId.from_parser(parser).to_json
41
+ result['LockingChainIssue'] = Issue.from_parser(parser).to_json
42
+ result['IssuingChainDoor'] = AccountId.from_parser(parser).to_json
43
+ result['IssuingChainIssue'] = Issue.from_parser(parser).to_json
44
+ result
45
+ end
46
+ end
47
+ end