solidity-scale-codec 0.1.3 → 0.2.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.
- package/CHANGELOG.md +15 -0
- package/DEFINITIONS.md +132 -0
- package/README.md +95 -1
- package/package.json +8 -3
- package/src/LittleEndian/LittleEndianU128.sol +4 -2
- package/src/LittleEndian/LittleEndianU16.sol +2 -2
- package/src/LittleEndian/LittleEndianU256.sol +4 -2
- package/src/LittleEndian/LittleEndianU32.sol +4 -2
- package/src/LittleEndian/LittleEndianU64.sol +4 -2
- package/src/LittleEndian/LittleEndianU8.sol +2 -2
- package/src/Scale/Address/Address.sol +55 -0
- package/src/Scale/Address.sol +4 -0
- package/src/Scale/Array/BoolArr.sol +16 -2
- package/src/Scale/Array/I128Arr.sol +16 -2
- package/src/Scale/Array/I16Arr.sol +16 -2
- package/src/Scale/Array/I256Arr.sol +16 -2
- package/src/Scale/Array/I32Arr.sol +16 -2
- package/src/Scale/Array/I64Arr.sol +16 -2
- package/src/Scale/Array/I8Arr.sol +16 -2
- package/src/Scale/Array/U128Arr.sol +16 -2
- package/src/Scale/Array/U16Arr.sol +16 -2
- package/src/Scale/Array/U256Arr.sol +16 -2
- package/src/Scale/Array/U32Arr.sol +16 -2
- package/src/Scale/Array/U64Arr.sol +16 -2
- package/src/Scale/Array/U8Arr.sol +16 -2
- package/src/Scale/Bool/Bool.sol +12 -0
- package/src/Scale/Bytes/Bytes.sol +63 -0
- package/src/Scale/Bytes/Bytes16.sol +53 -0
- package/src/Scale/Bytes/Bytes2.sol +53 -0
- package/src/Scale/Bytes/Bytes32.sol +53 -0
- package/src/Scale/Bytes/Bytes4.sol +53 -0
- package/src/Scale/Bytes/Bytes8.sol +53 -0
- package/src/Scale/Bytes.sol +8 -0
- package/src/Scale/Compact/Compact.sol +37 -3
- package/src/Scale/Signed/I128.sol +11 -0
- package/src/Scale/Signed/I16.sol +11 -0
- package/src/Scale/Signed/I256.sol +11 -0
- package/src/Scale/Signed/I32.sol +11 -0
- package/src/Scale/Signed/I64.sol +11 -0
- package/src/Scale/Signed/I8.sol +11 -0
- package/src/Scale/Unsigned/U128.sol +16 -2
- package/src/Scale/Unsigned/U16.sol +16 -2
- package/src/Scale/Unsigned/U256.sol +16 -2
- package/src/Scale/Unsigned/U32.sol +16 -2
- package/src/Scale/Unsigned/U64.sol +16 -2
- package/src/Scale/Unsigned/U8.sol +16 -2
- package/src/Xcm/Types/Version.sol +5 -0
- package/src/Xcm/VersionedXcm/VersionedXcm.sol +27 -0
- package/src/Xcm/VersionedXcm/VersionedXcmCodec.sol +70 -0
- package/src/Xcm/v3/Constants.sol +5 -0
- package/src/Xcm/v3/MaybeErrorCode/MaybeErrorCode.sol +73 -0
- package/src/Xcm/v3/MaybeErrorCode/MaybeErrorCodeCodec.sol +94 -0
- package/src/Xcm/v5/Asset/Asset.sol +13 -0
- package/src/Xcm/v5/Asset/AssetCodec.sol +72 -0
- package/src/Xcm/v5/AssetFilter/AssetFilter.sol +61 -0
- package/src/Xcm/v5/AssetFilter/AssetFilterCodec.sol +105 -0
- package/src/Xcm/v5/AssetId/AssetId.sol +10 -0
- package/src/Xcm/v5/AssetId/AssetIdCodec.sol +57 -0
- package/src/Xcm/v5/AssetInstance/AssetInstance.sol +139 -0
- package/src/Xcm/v5/AssetInstance/AssetInstanceCodec.sol +174 -0
- package/src/Xcm/v5/AssetTransferFilter/AssetTransferFilter.sol +82 -0
- package/src/Xcm/v5/AssetTransferFilter/AssetTransferFilterCodec.sol +95 -0
- package/src/Xcm/v5/Assets/Assets.sol +14 -0
- package/src/Xcm/v5/Assets/AssetsCodec.sol +94 -0
- package/src/Xcm/v5/BodyId/BodyId.sol +121 -0
- package/src/Xcm/v5/BodyId/BodyIdCodec.sol +128 -0
- package/src/Xcm/v5/BodyPart/BodyPart.sol +105 -0
- package/src/Xcm/v5/BodyPart/BodyPartCodec.sol +134 -0
- package/src/Xcm/v5/Constants.sol +15 -0
- package/src/Xcm/v5/Fungibility/Fungibility.sol +60 -0
- package/src/Xcm/v5/Fungibility/FungibilityCodec.sol +128 -0
- package/src/Xcm/v5/Hint/Hint.sol +40 -0
- package/src/Xcm/v5/Hint/HintCodec.sol +82 -0
- package/src/Xcm/v5/Instruction/Instruction.sol +1217 -0
- package/src/Xcm/v5/Instruction/InstructionCodec.sol +321 -0
- package/src/Xcm/v5/Junction/Junction.sol +258 -0
- package/src/Xcm/v5/Junction/JunctionCodec.sol +329 -0
- package/src/Xcm/v5/Junctions/Junctions.sol +12 -0
- package/src/Xcm/v5/Junctions/JunctionsCodec.sol +120 -0
- package/src/Xcm/v5/Location/Location.sol +12 -0
- package/src/Xcm/v5/Location/LocationCodec.sol +68 -0
- package/src/Xcm/v5/NetworkId/NetworkId.sol +115 -0
- package/src/Xcm/v5/NetworkId/NetworkIdCodec.sol +114 -0
- package/src/Xcm/v5/OriginKind/OriginKind.sol +14 -0
- package/src/Xcm/v5/OriginKind/OriginKindCodec.sol +66 -0
- package/src/Xcm/v5/PalletInfo/PalletInfo.sol +18 -0
- package/src/Xcm/v5/PalletInfo/PalletInfoCodec.sol +119 -0
- package/src/Xcm/v5/QueryResponseInfo/QueryResponseInfo.sol +16 -0
- package/src/Xcm/v5/QueryResponseInfo/QueryResponseInfoCodec.sol +91 -0
- package/src/Xcm/v5/Response/Response.sol +145 -0
- package/src/Xcm/v5/Response/ResponseCodec.sol +174 -0
- package/src/Xcm/v5/Types/QueryId.sol +5 -0
- package/src/Xcm/v5/Weight/Weight.sol +10 -0
- package/src/Xcm/v5/Weight/WeightCodec.sol +87 -0
- package/src/Xcm/v5/WeightLimit/WeightLimit.sol +48 -0
- package/src/Xcm/v5/WeightLimit/WeightLimitCodec.sol +88 -0
- package/src/Xcm/v5/WildAsset/WildAsset.sol +112 -0
- package/src/Xcm/v5/WildAsset/WildAssetCodec.sol +166 -0
- package/src/Xcm/v5/WildFungibility/WildFungibility.sol +10 -0
- package/src/Xcm/v5/WildFungibility/WildFungibilityCodec.sol +74 -0
- package/src/Xcm/v5/Xcm/Xcm.sol +27 -0
- package/src/Xcm/v5/Xcm/XcmCodec.sol +83 -0
- package/src/Xcm/v5/XcmError/XcmError.sol +122 -0
- package/src/Xcm/v5/XcmError/XcmErrorCodec.sol +85 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {BodyId} from "../BodyId/BodyId.sol";
|
|
5
|
+
import {BodyIdCodec} from "../BodyId/BodyIdCodec.sol";
|
|
6
|
+
import {BodyPart} from "../BodyPart/BodyPart.sol";
|
|
7
|
+
import {BodyPartCodec} from "../BodyPart/BodyPartCodec.sol";
|
|
8
|
+
import {NetworkId} from "../NetworkId/NetworkId.sol";
|
|
9
|
+
import {NetworkIdCodec} from "../NetworkId/NetworkIdCodec.sol";
|
|
10
|
+
import {Bytes32} from "../../../Scale/Bytes.sol";
|
|
11
|
+
import {Address} from "../../../Scale/Address.sol";
|
|
12
|
+
import {Compact} from "../../../Scale/Compact.sol";
|
|
13
|
+
import {
|
|
14
|
+
Junction,
|
|
15
|
+
JunctionType,
|
|
16
|
+
AccountId32Params,
|
|
17
|
+
PluralityParams,
|
|
18
|
+
AccountIndex64Params,
|
|
19
|
+
AccountKey20Params,
|
|
20
|
+
GeneralKeyParams
|
|
21
|
+
} from "./Junction.sol";
|
|
22
|
+
|
|
23
|
+
/// @title SCALE Codec for XCM v5 `Junction`
|
|
24
|
+
/// @notice SCALE-compliant encoder/decoder for the `Junction` type.
|
|
25
|
+
/// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
|
|
26
|
+
/// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
|
|
27
|
+
library JunctionCodec {
|
|
28
|
+
error InvalidJunctionLength();
|
|
29
|
+
error InvalidJunctionType(uint8 jType);
|
|
30
|
+
error InvalidJunctionPayload();
|
|
31
|
+
|
|
32
|
+
/// @notice Encodes a `Junction` struct into a byte array suitable for SCALE encoding.
|
|
33
|
+
/// @param junction The `Junction` struct to encode.
|
|
34
|
+
/// @return A byte array representing the SCALE-encoded junction, including its type and payload.
|
|
35
|
+
function encode(
|
|
36
|
+
Junction memory junction
|
|
37
|
+
) internal pure returns (bytes memory) {
|
|
38
|
+
return abi.encodePacked(uint8(junction.jType), junction.payload);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// @notice Returns the number of bytes that a `Junction` struct would occupy when SCALE-encoded, starting from the specified offset.
|
|
42
|
+
/// @param data The byte array containing the SCALE-encoded junction data.
|
|
43
|
+
/// @param offset The byte offset to start calculating from.
|
|
44
|
+
/// @return The number of bytes that the `Junction` struct would occupy when SCALE-encoded, including the type and payload.
|
|
45
|
+
function encodedSizeAt(
|
|
46
|
+
bytes memory data,
|
|
47
|
+
uint256 offset
|
|
48
|
+
) internal pure returns (uint256) {
|
|
49
|
+
if (offset >= data.length) revert InvalidJunctionLength();
|
|
50
|
+
uint8 jType;
|
|
51
|
+
assembly {
|
|
52
|
+
jType := shr(248, mload(add(add(data, 32), offset)))
|
|
53
|
+
}
|
|
54
|
+
uint256 payloadLength;
|
|
55
|
+
++offset; // Move past the type byte
|
|
56
|
+
if (jType == uint8(JunctionType.Parachain)) {
|
|
57
|
+
payloadLength = Compact.encodedSizeAt(data, offset);
|
|
58
|
+
} else if (jType == uint8(JunctionType.AccountId32)) {
|
|
59
|
+
payloadLength = _innerNetworkIdSize(data, offset) + 32; // for the account ID;
|
|
60
|
+
} else if (jType == uint8(JunctionType.AccountIndex64)) {
|
|
61
|
+
payloadLength = _innerNetworkIdSize(data, offset);
|
|
62
|
+
payloadLength += Compact.encodedSizeAt(
|
|
63
|
+
data,
|
|
64
|
+
offset + payloadLength
|
|
65
|
+
); // for the account index
|
|
66
|
+
} else if (jType == uint8(JunctionType.AccountKey20)) {
|
|
67
|
+
payloadLength = _innerNetworkIdSize(data, offset) + 20; // for the account key;
|
|
68
|
+
} else if (jType == uint8(JunctionType.PalletInstance)) {
|
|
69
|
+
payloadLength = 1;
|
|
70
|
+
} else if (jType == uint8(JunctionType.GeneralIndex)) {
|
|
71
|
+
payloadLength = Compact.encodedSizeAt(data, offset);
|
|
72
|
+
} else if (jType == uint8(JunctionType.GeneralKey)) {
|
|
73
|
+
if (offset >= data.length) revert InvalidJunctionLength();
|
|
74
|
+
uint8 length = uint8(data[offset]);
|
|
75
|
+
payloadLength = 1 + length; // 1 byte for the length + the key bytes
|
|
76
|
+
} else if (
|
|
77
|
+
jType == uint8(JunctionType.OnlyChild) ||
|
|
78
|
+
jType == uint8(JunctionType.GlobalConsensus)
|
|
79
|
+
) {
|
|
80
|
+
payloadLength = 0;
|
|
81
|
+
} else if (jType == uint8(JunctionType.Plurality)) {
|
|
82
|
+
uint256 innerLength = BodyIdCodec.encodedSizeAt(data, offset);
|
|
83
|
+
payloadLength =
|
|
84
|
+
innerLength +
|
|
85
|
+
BodyPartCodec.encodedSizeAt(data, offset + innerLength);
|
|
86
|
+
} else {
|
|
87
|
+
revert InvalidJunctionType(jType);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return 1 + payloadLength; // 1 byte for the type + payload length
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// @notice Decodes a byte array into a `Junction` struct, starting from the specified offset.
|
|
94
|
+
/// @param data The byte array containing the SCALE-encoded junction data.
|
|
95
|
+
/// @return junction A `Junction` struct representing the decoded junction, including its type and payload.
|
|
96
|
+
/// @return bytesRead The total number of bytes read during decoding, including the type and payload.
|
|
97
|
+
function decode(
|
|
98
|
+
bytes memory data
|
|
99
|
+
) internal pure returns (Junction memory junction, uint256 bytesRead) {
|
|
100
|
+
return decodeAt(data, 0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// @notice Decodes a byte array into a `Junction` struct, starting from the specified offset.
|
|
104
|
+
/// @param data The byte array containing the SCALE-encoded junction data.
|
|
105
|
+
/// @param offset The byte offset to start decoding from.
|
|
106
|
+
/// @return junction A `Junction` struct representing the decoded junction, including its type and payload.
|
|
107
|
+
/// @return bytesRead The total number of bytes read during decoding, including the type and payload.
|
|
108
|
+
function decodeAt(
|
|
109
|
+
bytes memory data,
|
|
110
|
+
uint256 offset
|
|
111
|
+
) internal pure returns (Junction memory junction, uint256 bytesRead) {
|
|
112
|
+
if (offset >= data.length) revert InvalidJunctionLength();
|
|
113
|
+
uint8 jType;
|
|
114
|
+
assembly {
|
|
115
|
+
jType := shr(248, mload(add(add(data, 32), offset)))
|
|
116
|
+
}
|
|
117
|
+
uint256 payloadLength = encodedSizeAt(data, offset) - 1; // Subtract 1 byte for the type
|
|
118
|
+
bytes memory payload = new bytes(payloadLength);
|
|
119
|
+
for (uint256 i = 0; i < payloadLength; i++) {
|
|
120
|
+
payload[i] = data[offset + 1 + i];
|
|
121
|
+
}
|
|
122
|
+
junction = Junction({jType: JunctionType(jType), payload: payload});
|
|
123
|
+
bytesRead = 1 + payload.length;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// @notice Decodes a `Parachain` junction from a given `Junction` struct, extracting the parachain ID.
|
|
127
|
+
/// @param junction The `Junction` struct to decode, which should represent a `Parachain` junction.
|
|
128
|
+
/// @return parachainId The ID of the parachain extracted from the junction's payload.
|
|
129
|
+
function asParachain(
|
|
130
|
+
Junction memory junction
|
|
131
|
+
) internal pure returns (uint32 parachainId) {
|
|
132
|
+
if (junction.jType != JunctionType.Parachain)
|
|
133
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
134
|
+
if (junction.payload.length != 4) revert InvalidJunctionPayload();
|
|
135
|
+
(uint256 decodedParachain, ) = Compact.decode(junction.payload);
|
|
136
|
+
if (decodedParachain > type(uint32).max) {
|
|
137
|
+
revert InvalidJunctionPayload();
|
|
138
|
+
}
|
|
139
|
+
unchecked {
|
|
140
|
+
parachainId = uint32(decodedParachain);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// @notice Decodes an `AccountId32` junction from a given `Junction` struct, extracting the network information and account ID.
|
|
145
|
+
/// @param junction The `Junction` struct to decode, which should represent an `AccountId32` junction.
|
|
146
|
+
/// @return params An `AccountId32Params` struct containing the decoded network information and account ID.
|
|
147
|
+
function asAccountId32(
|
|
148
|
+
Junction memory junction
|
|
149
|
+
) internal pure returns (AccountId32Params memory params) {
|
|
150
|
+
if (junction.jType != JunctionType.AccountId32)
|
|
151
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
152
|
+
if (junction.payload.length != 33 && junction.payload.length != 34)
|
|
153
|
+
revert InvalidJunctionPayload();
|
|
154
|
+
bool hasNetwork = junction.payload[0] != 0;
|
|
155
|
+
uint256 offset = 1;
|
|
156
|
+
NetworkId memory network;
|
|
157
|
+
uint256 bytesRead;
|
|
158
|
+
if (hasNetwork) {
|
|
159
|
+
(network, bytesRead) = NetworkIdCodec.decodeAt(
|
|
160
|
+
junction.payload,
|
|
161
|
+
offset
|
|
162
|
+
);
|
|
163
|
+
offset += bytesRead;
|
|
164
|
+
}
|
|
165
|
+
bytes32 id = Bytes32.decodeAt(junction.payload, offset);
|
|
166
|
+
return
|
|
167
|
+
AccountId32Params({
|
|
168
|
+
hasNetwork: hasNetwork,
|
|
169
|
+
network: network,
|
|
170
|
+
id: id
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/// @notice Decodes an `AccountIndex64` junction from a given `Junction` struct, extracting the network information and account index.
|
|
175
|
+
/// @param junction The `Junction` struct to decode, which should represent an `AccountIndex64` junction.
|
|
176
|
+
/// @return params An `AccountIndex64Params` struct containing the decoded network information and account index.
|
|
177
|
+
function asAccountIndex64(
|
|
178
|
+
Junction memory junction
|
|
179
|
+
) internal pure returns (AccountIndex64Params memory params) {
|
|
180
|
+
if (junction.jType != JunctionType.AccountIndex64)
|
|
181
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
182
|
+
if (junction.payload.length != 9 && junction.payload.length != 10)
|
|
183
|
+
revert InvalidJunctionPayload();
|
|
184
|
+
bool hasNetwork = junction.payload[0] != 0;
|
|
185
|
+
uint256 offset = 1;
|
|
186
|
+
NetworkId memory network;
|
|
187
|
+
uint256 bytesRead;
|
|
188
|
+
if (hasNetwork) {
|
|
189
|
+
(network, bytesRead) = NetworkIdCodec.decodeAt(
|
|
190
|
+
junction.payload,
|
|
191
|
+
offset
|
|
192
|
+
);
|
|
193
|
+
offset += bytesRead;
|
|
194
|
+
}
|
|
195
|
+
(uint256 decodedIndex, ) = Compact.decodeAt(junction.payload, offset);
|
|
196
|
+
if (decodedIndex > type(uint64).max) {
|
|
197
|
+
revert InvalidJunctionPayload();
|
|
198
|
+
}
|
|
199
|
+
uint64 index;
|
|
200
|
+
unchecked {
|
|
201
|
+
index = uint64(decodedIndex);
|
|
202
|
+
}
|
|
203
|
+
return
|
|
204
|
+
AccountIndex64Params({
|
|
205
|
+
hasNetwork: hasNetwork,
|
|
206
|
+
network: network,
|
|
207
|
+
index: index
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/// @notice Decodes an `AccountKey20` junction from a given `Junction` struct, extracting the network information and account key.
|
|
212
|
+
/// @param junction The `Junction` struct to decode, which should represent an `AccountKey20` junction.
|
|
213
|
+
/// @return params An `AccountKey20Params` struct containing the decoded network information and account key.
|
|
214
|
+
function asAccountKey20(
|
|
215
|
+
Junction memory junction
|
|
216
|
+
) internal pure returns (AccountKey20Params memory params) {
|
|
217
|
+
if (junction.jType != JunctionType.AccountKey20)
|
|
218
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
219
|
+
if (junction.payload.length != 21 && junction.payload.length != 22)
|
|
220
|
+
revert InvalidJunctionPayload();
|
|
221
|
+
bool hasNetwork = junction.payload[0] != 0;
|
|
222
|
+
uint256 offset = 1;
|
|
223
|
+
NetworkId memory network;
|
|
224
|
+
uint256 bytesRead;
|
|
225
|
+
if (hasNetwork) {
|
|
226
|
+
(network, bytesRead) = NetworkIdCodec.decodeAt(
|
|
227
|
+
junction.payload,
|
|
228
|
+
offset
|
|
229
|
+
);
|
|
230
|
+
offset += bytesRead;
|
|
231
|
+
}
|
|
232
|
+
address key = Address.decodeAt(junction.payload, offset);
|
|
233
|
+
return
|
|
234
|
+
AccountKey20Params({
|
|
235
|
+
hasNetwork: hasNetwork,
|
|
236
|
+
network: network,
|
|
237
|
+
key: key
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/// @notice Decodes a `PalletInstance` junction from a given `Junction` struct, extracting the pallet instance index.
|
|
242
|
+
/// @param junction The `Junction` struct to decode, which should represent a `PalletInstance` junction.
|
|
243
|
+
/// @return instance The index of the pallet instance extracted from the junction's payload.
|
|
244
|
+
function asPalletInstance(
|
|
245
|
+
Junction memory junction
|
|
246
|
+
) internal pure returns (uint8 instance) {
|
|
247
|
+
if (junction.jType != JunctionType.PalletInstance)
|
|
248
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
249
|
+
if (junction.payload.length != 1) revert InvalidJunctionPayload();
|
|
250
|
+
return uint8(junction.payload[0]);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// @notice Decodes a `GeneralIndex` junction from a given `Junction` struct, extracting the general index.
|
|
254
|
+
/// @param junction The `Junction` struct to decode, which should represent a `GeneralIndex` junction.
|
|
255
|
+
/// @return index The general index extracted from the junction's payload.
|
|
256
|
+
function asGeneralIndex(
|
|
257
|
+
Junction memory junction
|
|
258
|
+
) internal pure returns (uint128 index) {
|
|
259
|
+
if (junction.jType != JunctionType.GeneralIndex)
|
|
260
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
261
|
+
if (junction.payload.length == 0) revert InvalidJunctionPayload();
|
|
262
|
+
(uint256 decodedIndex, ) = Compact.decode(junction.payload);
|
|
263
|
+
if (decodedIndex > type(uint128).max) {
|
|
264
|
+
revert InvalidJunctionPayload();
|
|
265
|
+
}
|
|
266
|
+
unchecked {
|
|
267
|
+
index = uint128(decodedIndex);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/// @notice Decodes a `GeneralKey` junction from a given `Junction` struct, extracting the key.
|
|
272
|
+
/// @param junction The `Junction` struct to decode, which should represent a `GeneralKey` junction.
|
|
273
|
+
/// @return params A `GeneralKeyParams` struct containing the length and key extracted from the junction's payload.
|
|
274
|
+
function asGeneralKey(
|
|
275
|
+
Junction memory junction
|
|
276
|
+
) internal pure returns (GeneralKeyParams memory params) {
|
|
277
|
+
if (junction.jType != JunctionType.GeneralKey)
|
|
278
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
279
|
+
if (junction.payload.length == 0) revert InvalidJunctionPayload();
|
|
280
|
+
uint8 length = uint8(junction.payload[0]);
|
|
281
|
+
if (length == 0 || length > 32 || junction.payload.length != length + 1)
|
|
282
|
+
revert InvalidJunctionPayload();
|
|
283
|
+
bytes32 key = Bytes32.decodeAt(junction.payload, 1);
|
|
284
|
+
return GeneralKeyParams({length: length, key: key});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/// @notice Decodes a `Plurality` junction from a given `Junction` struct, extracting the body ID and body part.
|
|
288
|
+
/// @param junction The `Junction` struct to decode, which should represent a `Plurality` junction.
|
|
289
|
+
/// @return params A `PluralityParams` struct containing the body ID and body part extracted from the junction's payload.
|
|
290
|
+
function asPlurality(
|
|
291
|
+
Junction memory junction
|
|
292
|
+
) internal pure returns (PluralityParams memory params) {
|
|
293
|
+
if (junction.jType != JunctionType.Plurality)
|
|
294
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
295
|
+
if (junction.payload.length == 0) revert InvalidJunctionPayload();
|
|
296
|
+
uint256 offset = 0;
|
|
297
|
+
BodyId memory id;
|
|
298
|
+
uint256 bytesRead;
|
|
299
|
+
(id, bytesRead) = BodyIdCodec.decodeAt(junction.payload, offset);
|
|
300
|
+
offset += bytesRead;
|
|
301
|
+
BodyPart memory part;
|
|
302
|
+
(part, bytesRead) = BodyPartCodec.decodeAt(junction.payload, offset);
|
|
303
|
+
return PluralityParams({id: id, part: part});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/// @notice Decodes an `GlobalConsensus` junction from a given `Junction` struct and extracts the `NetworkId`.
|
|
307
|
+
/// @param junction The `Junction` struct to decode, which should represent a `GlobalConsensus` junction.
|
|
308
|
+
/// @return networkId The `NetworkId` extracted from the junction's payload, representing the global network's consensus.
|
|
309
|
+
function asGlobalConsensus(
|
|
310
|
+
Junction memory junction
|
|
311
|
+
) internal pure returns (NetworkId memory networkId) {
|
|
312
|
+
if (junction.jType != JunctionType.GlobalConsensus)
|
|
313
|
+
revert InvalidJunctionType(uint8(junction.jType));
|
|
314
|
+
(networkId, ) = NetworkIdCodec.decode(junction.payload);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function _innerNetworkIdSize(
|
|
318
|
+
bytes memory data,
|
|
319
|
+
uint256 offset
|
|
320
|
+
) private pure returns (uint256) {
|
|
321
|
+
if (offset >= data.length) revert InvalidJunctionLength();
|
|
322
|
+
bool hasNetwork = data[offset] != 0;
|
|
323
|
+
uint256 size = 1; // for the hasNetwork byte
|
|
324
|
+
if (hasNetwork) {
|
|
325
|
+
size += NetworkIdCodec.encodedSizeAt(data, offset + size);
|
|
326
|
+
}
|
|
327
|
+
return size;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Junction} from "../Junction/Junction.sol";
|
|
5
|
+
|
|
6
|
+
/// @dev The `Junctions` struct represents a sequence of up to 8 `Junction` items, prefixed by a count.
|
|
7
|
+
struct Junctions {
|
|
8
|
+
/// @custom:property Represents the enum discriminant, 0 = Here, 1 = X1, ..., 8 = X8
|
|
9
|
+
uint8 count;
|
|
10
|
+
/// @custom:property // The actual junction data
|
|
11
|
+
Junction[] items;
|
|
12
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Junction} from "../Junction/Junction.sol";
|
|
5
|
+
import {JunctionCodec} from "../Junction/JunctionCodec.sol";
|
|
6
|
+
import {Junctions} from "./Junctions.sol";
|
|
7
|
+
|
|
8
|
+
/// @title SCALE Codec for XCM v5 `Junctions`
|
|
9
|
+
/// @notice SCALE-compliant encoder/decoder for the `Junctions` type.
|
|
10
|
+
/// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
|
|
11
|
+
/// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
|
|
12
|
+
library JunctionsCodec {
|
|
13
|
+
error InvalidJunctionsLength(uint8 count);
|
|
14
|
+
error InvalidJunctionsCount(uint8 count);
|
|
15
|
+
|
|
16
|
+
/// @notice Creates a `Here` junctions struct.
|
|
17
|
+
function here() internal pure returns (Junctions memory) {
|
|
18
|
+
return Junctions({count: 0, items: new Junction[](0)});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @notice Creates a `Junctions` struct with the given junctions.
|
|
22
|
+
function junction(
|
|
23
|
+
Junction[] memory junctions
|
|
24
|
+
) internal pure returns (Junctions memory) {
|
|
25
|
+
if (junctions.length == 0) {
|
|
26
|
+
return here();
|
|
27
|
+
}
|
|
28
|
+
if (junctions.length > 8) {
|
|
29
|
+
revert InvalidJunctionsCount(uint8(junctions.length));
|
|
30
|
+
}
|
|
31
|
+
return Junctions({count: uint8(junctions.length), items: junctions});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// @notice Encodes a Junctions struct into bytes.
|
|
35
|
+
/// @param junctions The Junctions struct to encode.
|
|
36
|
+
/// @return SCALE-encoded byte sequence representing the Junctions.
|
|
37
|
+
function encode(
|
|
38
|
+
Junctions memory junctions
|
|
39
|
+
) internal pure returns (bytes memory) {
|
|
40
|
+
if (junctions.count > 8) {
|
|
41
|
+
revert InvalidJunctionsCount(junctions.count);
|
|
42
|
+
}
|
|
43
|
+
if (junctions.items.length != junctions.count) {
|
|
44
|
+
revert InvalidJunctionsLength(junctions.count);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
bytes memory encoded = abi.encodePacked(junctions.count);
|
|
48
|
+
for (uint8 i = 0; i < junctions.count; i++) {
|
|
49
|
+
encoded = abi.encodePacked(
|
|
50
|
+
encoded,
|
|
51
|
+
JunctionCodec.encode(junctions.items[i])
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return encoded;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// @notice Returns the number of bytes that a `Junctions` struct would occupy when SCALE-encoded.
|
|
58
|
+
/// @param data The byte sequence containing the encoded `Junctions`.
|
|
59
|
+
/// @param offset The starting index in `data` from which to calculate the encoded size of the `Junctions`.
|
|
60
|
+
/// @return The number of bytes that the `Junctions` struct would occupy when SCALE-encoded.
|
|
61
|
+
function encodedSizeAt(
|
|
62
|
+
bytes memory data,
|
|
63
|
+
uint256 offset
|
|
64
|
+
) internal pure returns (uint256) {
|
|
65
|
+
if (offset >= data.length) {
|
|
66
|
+
revert InvalidJunctionsLength(0);
|
|
67
|
+
}
|
|
68
|
+
uint8 count = uint8(data[offset]);
|
|
69
|
+
if (count > 8) {
|
|
70
|
+
revert InvalidJunctionsCount(count);
|
|
71
|
+
}
|
|
72
|
+
uint256 size = 1; // for the count byte
|
|
73
|
+
uint256 pos = offset + 1;
|
|
74
|
+
for (uint8 i = 0; i < count; i++) {
|
|
75
|
+
uint256 inner = JunctionCodec.encodedSizeAt(data, pos);
|
|
76
|
+
size += inner;
|
|
77
|
+
pos += inner;
|
|
78
|
+
}
|
|
79
|
+
return size;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// @notice Decodes bytes into a Junctions struct.
|
|
83
|
+
/// @param data The byte array to decode.
|
|
84
|
+
/// @return junctions The decoded Junctions struct.
|
|
85
|
+
function decode(
|
|
86
|
+
bytes memory data
|
|
87
|
+
) internal pure returns (Junctions memory junctions, uint256 bytesRead) {
|
|
88
|
+
return decodeAt(data, 0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// @notice Decodes bytes into a Junctions struct starting from a specific offset.
|
|
92
|
+
/// @param data The byte array to decode.
|
|
93
|
+
/// @param offset The byte offset to start decoding from.
|
|
94
|
+
/// @return junctions The decoded Junctions struct.
|
|
95
|
+
/// @return bytesRead The total number of bytes read during decoding.
|
|
96
|
+
function decodeAt(
|
|
97
|
+
bytes memory data,
|
|
98
|
+
uint256 offset
|
|
99
|
+
) internal pure returns (Junctions memory junctions, uint256 bytesRead) {
|
|
100
|
+
if (offset >= data.length) revert InvalidJunctionsLength(0);
|
|
101
|
+
|
|
102
|
+
uint8 count = uint8(data[offset]);
|
|
103
|
+
if (count > 8) revert InvalidJunctionsCount(count);
|
|
104
|
+
|
|
105
|
+
Junction[] memory items = new Junction[](count);
|
|
106
|
+
uint256 pos = offset + 1;
|
|
107
|
+
|
|
108
|
+
for (uint8 i = 0; i < count; i++) {
|
|
109
|
+
(Junction memory item, uint256 itemBytes) = JunctionCodec.decodeAt(
|
|
110
|
+
data,
|
|
111
|
+
pos
|
|
112
|
+
);
|
|
113
|
+
items[i] = item;
|
|
114
|
+
pos += itemBytes;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
junctions = Junctions({count: count, items: items});
|
|
118
|
+
bytesRead = pos - offset;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Junctions} from "../Junctions/Junctions.sol";
|
|
5
|
+
|
|
6
|
+
/// @notice A relative path between state-bearing consensus systems.
|
|
7
|
+
struct Location {
|
|
8
|
+
/// @custom:property The number of parent junctions at the beginning of this Location.
|
|
9
|
+
uint8 parents;
|
|
10
|
+
/// @custom:property The interior (i.e. non-parent) junctions that this Location contains. See `Junctions` struct for details.
|
|
11
|
+
Junctions interior;
|
|
12
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Junctions} from "../Junctions/Junctions.sol";
|
|
5
|
+
import {JunctionsCodec} from "../Junctions/JunctionsCodec.sol";
|
|
6
|
+
import {Location} from "./Location.sol";
|
|
7
|
+
|
|
8
|
+
/// @title SCALE Codec for XCM v5 `Location`
|
|
9
|
+
/// @notice SCALE-compliant encoder/decoder for the `Location` type.
|
|
10
|
+
/// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
|
|
11
|
+
/// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
|
|
12
|
+
library LocationCodec {
|
|
13
|
+
error InvalidLocationLength();
|
|
14
|
+
|
|
15
|
+
/// @notice Encodes a `Location` struct into bytes.
|
|
16
|
+
/// @param location The `Location` struct to encode.
|
|
17
|
+
/// @return SCALE-encoded byte sequence representing the `Location`.
|
|
18
|
+
function encode(
|
|
19
|
+
Location memory location
|
|
20
|
+
) internal pure returns (bytes memory) {
|
|
21
|
+
bytes memory encodedInterior = JunctionsCodec.encode(location.interior);
|
|
22
|
+
return abi.encodePacked(location.parents, encodedInterior);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// @notice Returns the number of bytes that a `Location` struct would occupy when SCALE-encoded.
|
|
26
|
+
/// @param data The byte sequence containing the encoded `Location`.
|
|
27
|
+
/// @param offset The starting index in `data` from which to calculate the encoded size of the `Location`.
|
|
28
|
+
/// @return The number of bytes that the `Location` struct would occupy when SCALE-encoded.
|
|
29
|
+
function encodedSizeAt(
|
|
30
|
+
bytes memory data,
|
|
31
|
+
uint256 offset
|
|
32
|
+
) internal pure returns (uint256) {
|
|
33
|
+
if (data.length < offset + 1) {
|
|
34
|
+
revert InvalidLocationLength();
|
|
35
|
+
}
|
|
36
|
+
uint256 interiorSize = JunctionsCodec.encodedSizeAt(data, offset + 1);
|
|
37
|
+
return 1 + interiorSize;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// @notice Decodes a `Location` struct from bytes starting at the beginning of the data.
|
|
41
|
+
/// @param data The byte sequence containing the encoded `Location`.
|
|
42
|
+
/// @return location The decoded `Location` struct.
|
|
43
|
+
/// @return bytesRead The total number of bytes read from `data` to decode the `Location`.
|
|
44
|
+
function decode(
|
|
45
|
+
bytes memory data
|
|
46
|
+
) internal pure returns (Location memory location, uint256 bytesRead) {
|
|
47
|
+
return decodeAt(data, 0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// @notice Decodes a `Location` struct from bytes starting at a given offset.
|
|
51
|
+
/// @param data The byte sequence containing the encoded `Location`.
|
|
52
|
+
/// @param offset The starting index in `data` from which to decode the `Location`.
|
|
53
|
+
/// @return location The decoded `Location` struct.
|
|
54
|
+
/// @return bytesRead The total number of bytes read from `data` to decode the `Location`.
|
|
55
|
+
function decodeAt(
|
|
56
|
+
bytes memory data,
|
|
57
|
+
uint256 offset
|
|
58
|
+
) internal pure returns (Location memory location, uint256 bytesRead) {
|
|
59
|
+
if (data.length < offset + 1) {
|
|
60
|
+
revert InvalidLocationLength();
|
|
61
|
+
}
|
|
62
|
+
uint8 parents = uint8(data[offset]);
|
|
63
|
+
(Junctions memory interior, uint256 interiorBytesRead) = JunctionsCodec
|
|
64
|
+
.decodeAt(data, offset + 1);
|
|
65
|
+
location = Location({parents: parents, interior: interior});
|
|
66
|
+
bytesRead = 1 + interiorBytesRead;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Compact} from "../../../Scale/Compact.sol";
|
|
5
|
+
import {LittleEndianU64} from "../../../LittleEndian/LittleEndianU64.sol";
|
|
6
|
+
|
|
7
|
+
/// @dev Discriminant for the different types of NetworkIds in XCM v5.
|
|
8
|
+
enum NetworkIdType {
|
|
9
|
+
/// @custom:variant Network specified by the first 32 bytes of its genesis block.
|
|
10
|
+
ByGenesis,
|
|
11
|
+
/// @custom:variant Network defined by the first 32-bytes of the hash and number of some block it contains.
|
|
12
|
+
ByFork,
|
|
13
|
+
/// @custom:variant The Polkadot Relay Chain.
|
|
14
|
+
Polkadot,
|
|
15
|
+
/// @custom:variant The Kusama Relay Chain.
|
|
16
|
+
Kusama,
|
|
17
|
+
/// @custom:variant Reserved. Do not Use.
|
|
18
|
+
_Reserved4,
|
|
19
|
+
/// @custom:variant Reserved. Do not Use.
|
|
20
|
+
_Reserved5,
|
|
21
|
+
/// @custom:variant Reserved. Do not Use.
|
|
22
|
+
_Reserved6,
|
|
23
|
+
/// @custom:variant An Ethereum-based network, identified by its chain ID.
|
|
24
|
+
Ethereum,
|
|
25
|
+
/// @custom:variant The Bitcoin network.
|
|
26
|
+
BitcoinCore,
|
|
27
|
+
/// @custom:variant The Bitcoin Cash network.
|
|
28
|
+
BitcoinCash,
|
|
29
|
+
/// @custom:variant The Polkadot Bulletin Chain.
|
|
30
|
+
PolkadotBulletin
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// @notice Parameters for a `ByGenesis` network ID, containing the genesis block hash.
|
|
34
|
+
struct ByForkParams {
|
|
35
|
+
/// @custom:property The block number of the block.
|
|
36
|
+
uint64 blockNumber;
|
|
37
|
+
/// @custom:property The hash of the block.
|
|
38
|
+
bytes32 blockHash;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// @notice Parameters for an `Ethereum` network ID, containing the chain ID.
|
|
42
|
+
struct EthereumParams {
|
|
43
|
+
/// @custom:property The chain ID of an Ethereum network.
|
|
44
|
+
uint64 chainId;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// @notice Parameters for a `ByGenesis` network ID.
|
|
48
|
+
struct ByGenesisParams {
|
|
49
|
+
/// @custom:property The 32-byte genesis block hash.
|
|
50
|
+
bytes32 genesisHash;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// @dev Notice A global identifier of a data structure existing within consensus.
|
|
54
|
+
struct NetworkId {
|
|
55
|
+
/// @custom:property The type of network ID, determining how to interpret the payload. See `NetworkIdType` enum for possible values.
|
|
56
|
+
NetworkIdType nType;
|
|
57
|
+
/// @custom:property The encoded payload containing the network identifier data, whose structure depends on the `nType`.
|
|
58
|
+
bytes payload;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
using LittleEndianU64 for uint64;
|
|
62
|
+
|
|
63
|
+
// ============ Factory Functions ============
|
|
64
|
+
|
|
65
|
+
/// @notice Creates a `ByGenesis` network ID.
|
|
66
|
+
/// @param params Parameters for the by-genesis variant.
|
|
67
|
+
/// @return A `NetworkId` struct with type `ByGenesis` and the provided genesis hash as payload.
|
|
68
|
+
function byGenesis(
|
|
69
|
+
ByGenesisParams memory params
|
|
70
|
+
) pure returns (NetworkId memory) {
|
|
71
|
+
return
|
|
72
|
+
NetworkId({
|
|
73
|
+
nType: NetworkIdType.ByGenesis,
|
|
74
|
+
payload: abi.encodePacked(params.genesisHash)
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// @notice Creates a `ByFork` network ID.
|
|
79
|
+
/// @param blockNumber The block number of the fork point.
|
|
80
|
+
/// @param blockHash The 32-byte hash of the block at the fork point.
|
|
81
|
+
/// @return A `NetworkId` struct with type `ByFork` and the provided block number and hash encoded in the payload.
|
|
82
|
+
function byFork(
|
|
83
|
+
uint64 blockNumber,
|
|
84
|
+
bytes32 blockHash
|
|
85
|
+
) pure returns (NetworkId memory) {
|
|
86
|
+
return
|
|
87
|
+
NetworkId({
|
|
88
|
+
nType: NetworkIdType.ByFork,
|
|
89
|
+
payload: abi.encodePacked(blockNumber.toLittleEndian(), blockHash)
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// @notice Creates a `Polkadot` network ID.
|
|
94
|
+
/// @return A `NetworkId` struct with type `Polkadot` and an empty payload.
|
|
95
|
+
function polkadot() pure returns (NetworkId memory) {
|
|
96
|
+
return NetworkId({nType: NetworkIdType.Polkadot, payload: ""});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// @notice Creates a `Kusama` network ID.
|
|
100
|
+
/// @return A `NetworkId` struct with type `Kusama` and an empty payload.
|
|
101
|
+
function kusama() pure returns (NetworkId memory) {
|
|
102
|
+
return NetworkId({nType: NetworkIdType.Kusama, payload: ""});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// @notice Creates an `Ethereum` network ID.
|
|
106
|
+
/// @param params Parameters for the ethereum variant.
|
|
107
|
+
function ethereum(
|
|
108
|
+
EthereumParams memory params
|
|
109
|
+
) pure returns (NetworkId memory) {
|
|
110
|
+
return
|
|
111
|
+
NetworkId({
|
|
112
|
+
nType: NetworkIdType.Ethereum,
|
|
113
|
+
payload: Compact.encode(params.chainId)
|
|
114
|
+
});
|
|
115
|
+
}
|