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,128 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Bytes4} from "../../../Scale/Bytes.sol";
|
|
5
|
+
import {Compact} from "../../../Scale/Compact.sol";
|
|
6
|
+
import {BodyId, BodyIdType} from "./BodyId.sol";
|
|
7
|
+
|
|
8
|
+
/// @title SCALE Codec for XCM v5 `BodyId`
|
|
9
|
+
/// @notice SCALE-compliant encoder/decoder for the `BodyId` 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 BodyIdCodec {
|
|
13
|
+
error InvalidBodyIdLength();
|
|
14
|
+
error InvalidBodyIdType(uint8 bodyIdType);
|
|
15
|
+
|
|
16
|
+
/// @notice Encodes a `BodyId` into bytes.
|
|
17
|
+
/// @param bodyId The `BodyId` to encode.
|
|
18
|
+
/// @return SCALE-encoded byte sequence representing the `BodyId`.
|
|
19
|
+
function encode(BodyId memory bodyId) internal pure returns (bytes memory) {
|
|
20
|
+
return abi.encodePacked(uint8(bodyId.bodyIdType), bodyId.payload);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// @notice Returns the number of bytes that a `BodyId` struct would occupy when SCALE-encoded, starting at a given offset in the data.
|
|
24
|
+
/// @param data The byte sequence containing the encoded `BodyId`.
|
|
25
|
+
/// @param offset The starting index in `data` from which to calculate the encoded size of the `BodyId`.
|
|
26
|
+
/// @return The number of bytes that the `BodyId` struct would occupy when SCALE-encoded.
|
|
27
|
+
function encodedSizeAt(
|
|
28
|
+
bytes memory data,
|
|
29
|
+
uint256 offset
|
|
30
|
+
) internal pure returns (uint256) {
|
|
31
|
+
if (data.length < offset + 1) {
|
|
32
|
+
revert InvalidBodyIdLength();
|
|
33
|
+
}
|
|
34
|
+
uint8 bodyIdTypeValue = uint8(data[offset]);
|
|
35
|
+
BodyIdType bodyIdType = BodyIdType(bodyIdTypeValue);
|
|
36
|
+
uint256 payloadLength;
|
|
37
|
+
if (
|
|
38
|
+
bodyIdType == BodyIdType.Unit ||
|
|
39
|
+
bodyIdType == BodyIdType.Executive ||
|
|
40
|
+
bodyIdType == BodyIdType.Technical ||
|
|
41
|
+
bodyIdType == BodyIdType.Legislative ||
|
|
42
|
+
bodyIdType == BodyIdType.Judicial ||
|
|
43
|
+
bodyIdType == BodyIdType.Defense ||
|
|
44
|
+
bodyIdType == BodyIdType.Administration ||
|
|
45
|
+
bodyIdType == BodyIdType.Treasury
|
|
46
|
+
) {
|
|
47
|
+
payloadLength = 0;
|
|
48
|
+
} else if (bodyIdType == BodyIdType.Moniker) {
|
|
49
|
+
payloadLength = 4;
|
|
50
|
+
} else if (bodyIdType == BodyIdType.Index) {
|
|
51
|
+
payloadLength = 4;
|
|
52
|
+
} else {
|
|
53
|
+
revert InvalidBodyIdType(bodyIdTypeValue);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (data.length < offset + 1 + payloadLength) {
|
|
57
|
+
revert InvalidBodyIdLength();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return 1 + payloadLength;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// @notice Decodes a `BodyId` from bytes starting at the beginning of the data.
|
|
64
|
+
/// @param data The byte sequence containing the encoded `BodyId`.
|
|
65
|
+
/// @return bodyId The decoded `BodyId`.
|
|
66
|
+
/// @return bytesRead The total number of bytes read from the input data to decode the `BodyId`.
|
|
67
|
+
function decode(
|
|
68
|
+
bytes memory data
|
|
69
|
+
) internal pure returns (BodyId memory bodyId, uint256 bytesRead) {
|
|
70
|
+
return decodeAt(data, 0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/// @notice Decodes a `BodyId` from bytes starting at a given offset.
|
|
74
|
+
/// @param data The byte sequence containing the encoded `BodyId`.
|
|
75
|
+
/// @param offset The starting index in `data` from which to decode the `BodyId`.
|
|
76
|
+
/// @return bodyId The decoded `BodyId`.
|
|
77
|
+
/// @return bytesRead The total number of bytes read from the input data to decode the `BodyId`.
|
|
78
|
+
function decodeAt(
|
|
79
|
+
bytes memory data,
|
|
80
|
+
uint256 offset
|
|
81
|
+
) internal pure returns (BodyId memory bodyId, uint256 bytesRead) {
|
|
82
|
+
if (data.length < offset + 1) {
|
|
83
|
+
revert InvalidBodyIdLength();
|
|
84
|
+
}
|
|
85
|
+
uint8 bodyIdTypeValue = uint8(data[offset]);
|
|
86
|
+
BodyIdType bodyIdType = BodyIdType(bodyIdTypeValue);
|
|
87
|
+
uint256 payloadLength = encodedSizeAt(data, offset) - 1; // subtract 1 byte for the bodyIdType
|
|
88
|
+
bytes memory payload = new bytes(payloadLength);
|
|
89
|
+
|
|
90
|
+
for (uint256 i = 0; i < payloadLength; i++) {
|
|
91
|
+
payload[i] = data[offset + 1 + i];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
bodyId = BodyId({bodyIdType: bodyIdType, payload: payload});
|
|
95
|
+
bytesRead = 1 + payloadLength;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// @notice Helper function to decode a `BodyId` and extract the moniker name if the type is `Moniker`.
|
|
99
|
+
/// @param bodyId The `BodyId` to extract the moniker name from.
|
|
100
|
+
/// @return name The 4-byte name of the moniker if the `bodyIdType` is `Moniker`.
|
|
101
|
+
function asMoniker(
|
|
102
|
+
BodyId memory bodyId
|
|
103
|
+
) internal pure returns (bytes4 name) {
|
|
104
|
+
if (bodyId.bodyIdType != BodyIdType.Moniker) {
|
|
105
|
+
revert InvalidBodyIdType(uint8(bodyId.bodyIdType));
|
|
106
|
+
}
|
|
107
|
+
return Bytes4.decode(bodyId.payload);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// @notice Helper function to decode a `BodyId` and extract the index if the type is `Index`.
|
|
111
|
+
/// @param bodyId The `BodyId` to extract the index from.
|
|
112
|
+
/// @return idx The index of the body if the `bodyIdType` is `Index`.
|
|
113
|
+
function asIndex(BodyId memory bodyId) internal pure returns (uint32 idx) {
|
|
114
|
+
if (bodyId.bodyIdType != BodyIdType.Index) {
|
|
115
|
+
revert InvalidBodyIdType(uint8(bodyId.bodyIdType));
|
|
116
|
+
}
|
|
117
|
+
if (bodyId.payload.length != 4) {
|
|
118
|
+
revert InvalidBodyIdLength();
|
|
119
|
+
}
|
|
120
|
+
(uint256 decodedIndex, ) = Compact.decode(bodyId.payload);
|
|
121
|
+
if (decodedIndex > type(uint32).max) {
|
|
122
|
+
revert InvalidBodyIdLength();
|
|
123
|
+
}
|
|
124
|
+
unchecked {
|
|
125
|
+
idx = uint32(decodedIndex);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Compact} from "../../../Scale/Compact.sol";
|
|
5
|
+
|
|
6
|
+
/// @dev Discriminant for the different types of BodyParts in XCM v5. Each variant corresponds to a specific structure of the payload.
|
|
7
|
+
enum BodyPartType {
|
|
8
|
+
/// @custom:variant The body's declaration, under whatever means it decides.
|
|
9
|
+
Voice,
|
|
10
|
+
/// @custom:variant A given number of members of the body.
|
|
11
|
+
Members,
|
|
12
|
+
/// @custom:variant A given number of members of the body, out of some larger caucus.
|
|
13
|
+
Fraction,
|
|
14
|
+
/// @custom:variant No less than the given proportion of members of the body.
|
|
15
|
+
AtLeastProportion,
|
|
16
|
+
/// @custom:variant More than the given proportion of members of the body.
|
|
17
|
+
MoreThanProportion
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// @notice A part of a pluralistic body.
|
|
21
|
+
struct BodyPart {
|
|
22
|
+
/// @custom:property The type of BodyPart, which determines how to interpret the payload. See `BodyPartType` enum for possible values.
|
|
23
|
+
BodyPartType bodyPartType;
|
|
24
|
+
/// @custom:property For Members, this will hold the count. For Fraction, AtLeastProportion, and MoreThanProportion, this will hold the encoded Proportion struct. For Voice, this will be empty.
|
|
25
|
+
bytes payload;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// @notice Parameters for the `Members` variant.
|
|
29
|
+
struct MembersParams {
|
|
30
|
+
/// @custom:property The number of members in the body part.
|
|
31
|
+
uint32 count;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ============ Factory Functions ============
|
|
35
|
+
|
|
36
|
+
/// @notice Creates a `BodyPart` struct representing a `Voice` body part.
|
|
37
|
+
/// @return A `BodyPart` with the `Voice` variant.
|
|
38
|
+
function voice() pure returns (BodyPart memory) {
|
|
39
|
+
return BodyPart({bodyPartType: BodyPartType.Voice, payload: ""});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// @notice Creates a `BodyPart` struct representing a `Members` body part with the given count.
|
|
43
|
+
/// @param params Parameters for the members variant.
|
|
44
|
+
/// @return A `BodyPart` with the `Members` variant and the count encoded in the payload.
|
|
45
|
+
function members(MembersParams memory params) pure returns (BodyPart memory) {
|
|
46
|
+
return
|
|
47
|
+
BodyPart({
|
|
48
|
+
bodyPartType: BodyPartType.Members,
|
|
49
|
+
payload: Compact.encode(params.count)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// @notice Creates a `BodyPart` struct representing a `Fraction` body part with the given proportion.
|
|
54
|
+
/// @param nominator The numerator of the proportion, representing the number of members in favor.
|
|
55
|
+
/// @param denominator The denominator of the proportion, representing the total number of members considered.
|
|
56
|
+
/// @return A `BodyPart` with the `Fraction` variant and the encoded proportion in the payload.
|
|
57
|
+
function fraction(
|
|
58
|
+
uint32 nominator,
|
|
59
|
+
uint32 denominator
|
|
60
|
+
) pure returns (BodyPart memory) {
|
|
61
|
+
return
|
|
62
|
+
BodyPart({
|
|
63
|
+
bodyPartType: BodyPartType.Fraction,
|
|
64
|
+
payload: abi.encodePacked(
|
|
65
|
+
Compact.encode(nominator),
|
|
66
|
+
Compact.encode(denominator)
|
|
67
|
+
)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// @notice Creates a `BodyPart` struct representing an `AtLeastProportion` body part with the given proportion.
|
|
72
|
+
/// @param nominator The numerator of the proportion, representing the minimum number of members in favor.
|
|
73
|
+
/// @param denominator The denominator of the proportion, representing the total number of members considered.
|
|
74
|
+
/// @return A `BodyPart` with the `AtLeastProportion` variant and the encoded proportion in the payload.
|
|
75
|
+
function atLeastProportion(
|
|
76
|
+
uint32 nominator,
|
|
77
|
+
uint32 denominator
|
|
78
|
+
) pure returns (BodyPart memory) {
|
|
79
|
+
return
|
|
80
|
+
BodyPart({
|
|
81
|
+
bodyPartType: BodyPartType.AtLeastProportion,
|
|
82
|
+
payload: abi.encodePacked(
|
|
83
|
+
Compact.encode(nominator),
|
|
84
|
+
Compact.encode(denominator)
|
|
85
|
+
)
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// @notice Creates a `BodyPart` struct representing a `MoreThanProportion` body part with the given proportion.
|
|
90
|
+
/// @param nominator The numerator of the proportion, representing the minimum number of members in favor.
|
|
91
|
+
/// @param denominator The denominator of the proportion, representing the total number of members considered.
|
|
92
|
+
/// @return A `BodyPart` with the `MoreThanProportion` variant and the encoded proportion in the payload.
|
|
93
|
+
function moreThanProportion(
|
|
94
|
+
uint32 nominator,
|
|
95
|
+
uint32 denominator
|
|
96
|
+
) pure returns (BodyPart memory) {
|
|
97
|
+
return
|
|
98
|
+
BodyPart({
|
|
99
|
+
bodyPartType: BodyPartType.MoreThanProportion,
|
|
100
|
+
payload: abi.encodePacked(
|
|
101
|
+
Compact.encode(nominator),
|
|
102
|
+
Compact.encode(denominator)
|
|
103
|
+
)
|
|
104
|
+
});
|
|
105
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Compact} from "../../../Scale/Compact.sol";
|
|
5
|
+
import {BodyPart, BodyPartType} from "./BodyPart.sol";
|
|
6
|
+
|
|
7
|
+
/// @title SCALE Codec for XCM v5 `BodyPart`
|
|
8
|
+
/// @notice SCALE-compliant encoder/decoder for the `BodyPart` type.
|
|
9
|
+
/// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
|
|
10
|
+
/// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
|
|
11
|
+
library BodyPartCodec {
|
|
12
|
+
error InvalidBodyPartLength();
|
|
13
|
+
error InvalidBodyPartType(uint8 bodyPartType);
|
|
14
|
+
error InvalidBodyPartPayload();
|
|
15
|
+
|
|
16
|
+
/// @notice Encodes a `BodyPart` struct into bytes.
|
|
17
|
+
/// @param bodyPart The `BodyPart` struct to encode.
|
|
18
|
+
/// @return SCALE-encoded byte sequence representing the `BodyPart`.
|
|
19
|
+
function encode(
|
|
20
|
+
BodyPart memory bodyPart
|
|
21
|
+
) internal pure returns (bytes memory) {
|
|
22
|
+
return abi.encodePacked(uint8(bodyPart.bodyPartType), bodyPart.payload);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// @notice Returns the number of bytes that a `BodyPart` struct would occupy when SCALE-encoded.
|
|
26
|
+
/// @param data The byte sequence containing the encoded `BodyPart`.
|
|
27
|
+
/// @param offset The starting index in `data` from which to calculate the encoded size of the `BodyPart`.
|
|
28
|
+
/// @return The number of bytes that the `BodyPart` struct would occupy when SCALE-encoded.
|
|
29
|
+
function encodedSizeAt(
|
|
30
|
+
bytes memory data,
|
|
31
|
+
uint256 offset
|
|
32
|
+
) internal pure returns (uint256) {
|
|
33
|
+
if (offset >= data.length) revert InvalidBodyPartLength();
|
|
34
|
+
|
|
35
|
+
uint8 bodyPartType = uint8(data[offset]);
|
|
36
|
+
uint256 payloadLength;
|
|
37
|
+
if (bodyPartType == uint8(BodyPartType.Voice)) {
|
|
38
|
+
payloadLength = 0;
|
|
39
|
+
} else if (bodyPartType == uint8(BodyPartType.Members)) {
|
|
40
|
+
payloadLength = Compact.encodedSizeAt(data, offset + 1);
|
|
41
|
+
} else if (
|
|
42
|
+
bodyPartType == uint8(BodyPartType.Fraction) ||
|
|
43
|
+
bodyPartType == uint8(BodyPartType.AtLeastProportion) ||
|
|
44
|
+
bodyPartType == uint8(BodyPartType.MoreThanProportion)
|
|
45
|
+
) {
|
|
46
|
+
uint256 innerLength = Compact.encodedSizeAt(data, offset + 1);
|
|
47
|
+
payloadLength =
|
|
48
|
+
innerLength +
|
|
49
|
+
Compact.encodedSizeAt(data, offset + 1 + innerLength);
|
|
50
|
+
} else {
|
|
51
|
+
revert InvalidBodyPartType(bodyPartType);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (data.length < offset + 1 + payloadLength) {
|
|
55
|
+
revert InvalidBodyPartLength();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return 1 + payloadLength;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// @notice Decodes a `BodyPart` struct from bytes starting at the beginning of the data.
|
|
62
|
+
/// @param data The byte sequence containing the encoded `BodyPart`.
|
|
63
|
+
/// @return bodyPart The decoded `BodyPart` struct.
|
|
64
|
+
/// @return bytesRead The total number of bytes read from the input data to decode the `BodyPart`.
|
|
65
|
+
function decode(
|
|
66
|
+
bytes memory data
|
|
67
|
+
) internal pure returns (BodyPart memory bodyPart, uint256 bytesRead) {
|
|
68
|
+
return decodeAt(data, 0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// @notice Decodes a `BodyPart` struct from bytes starting at a given offset.
|
|
72
|
+
/// @param data The byte sequence containing the encoded `BodyPart`.
|
|
73
|
+
/// @param offset The starting index in `data` from which to decode the `BodyPart`.
|
|
74
|
+
/// @return bodyPart The decoded `BodyPart` struct.
|
|
75
|
+
/// @return bytesRead The total number of bytes read from the input data to decode the `BodyPart`.
|
|
76
|
+
function decodeAt(
|
|
77
|
+
bytes memory data,
|
|
78
|
+
uint256 offset
|
|
79
|
+
) internal pure returns (BodyPart memory bodyPart, uint256 bytesRead) {
|
|
80
|
+
if (offset >= data.length) revert InvalidBodyPartLength();
|
|
81
|
+
|
|
82
|
+
uint8 bodyPartType = uint8(data[offset]);
|
|
83
|
+
uint256 payloadLength = encodedSizeAt(data, offset) - 1; // total size minus 1 byte for the bodyPartType
|
|
84
|
+
|
|
85
|
+
bytes memory payload = new bytes(payloadLength);
|
|
86
|
+
for (uint256 i = 0; i < payloadLength; i++) {
|
|
87
|
+
payload[i] = data[offset + 1 + i];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
bodyPart = BodyPart({
|
|
91
|
+
bodyPartType: BodyPartType(bodyPartType),
|
|
92
|
+
payload: payload
|
|
93
|
+
});
|
|
94
|
+
bytesRead = 1 + payloadLength;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// @notice Decodes a `Members` body part to extract the member count.
|
|
98
|
+
/// @param bodyPart The `BodyPart` struct to decode, which must be of type `Members`.
|
|
99
|
+
/// @return count The number of members encoded in the body part's payload.
|
|
100
|
+
function asMembers(
|
|
101
|
+
BodyPart memory bodyPart
|
|
102
|
+
) internal pure returns (uint32 count) {
|
|
103
|
+
if (bodyPart.bodyPartType != BodyPartType.Members) {
|
|
104
|
+
revert InvalidBodyPartType(uint8(bodyPart.bodyPartType));
|
|
105
|
+
}
|
|
106
|
+
(uint256 decodedCount, ) = Compact.decode(bodyPart.payload);
|
|
107
|
+
count = uint32(decodedCount);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// @notice Decodes a `Fraction`, `AtLeastProportion`, or `MoreThanProportion` body part to extract the nominator and denominator.
|
|
111
|
+
/// @param bodyPart The `BodyPart` struct to decode, which must be of type `Fraction`, `AtLeastProportion`, or `MoreThanProportion`.
|
|
112
|
+
/// @return nominator The numerator of the proportion encoded in the body part's payload.
|
|
113
|
+
/// @return denominator The denominator of the proportion encoded in the body part's payload.
|
|
114
|
+
function asProportion(
|
|
115
|
+
BodyPart memory bodyPart
|
|
116
|
+
) internal pure returns (uint32 nominator, uint32 denominator) {
|
|
117
|
+
if (
|
|
118
|
+
bodyPart.bodyPartType != BodyPartType.Fraction &&
|
|
119
|
+
bodyPart.bodyPartType != BodyPartType.AtLeastProportion &&
|
|
120
|
+
bodyPart.bodyPartType != BodyPartType.MoreThanProportion
|
|
121
|
+
) {
|
|
122
|
+
revert InvalidBodyPartType(uint8(bodyPart.bodyPartType));
|
|
123
|
+
}
|
|
124
|
+
(uint256 decodedNominator, uint256 offset) = Compact.decode(
|
|
125
|
+
bodyPart.payload
|
|
126
|
+
);
|
|
127
|
+
(uint256 decodedDenominator, ) = Compact.decodeAt(
|
|
128
|
+
bodyPart.payload,
|
|
129
|
+
offset
|
|
130
|
+
);
|
|
131
|
+
nominator = uint32(decodedNominator);
|
|
132
|
+
denominator = uint32(decodedDenominator);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {HintType} from "./Hint/Hint.sol";
|
|
5
|
+
|
|
6
|
+
// Maximum number of items we expect in a single Assets value.
|
|
7
|
+
uint64 constant MAX_ITEMS_IN_ASSETS = 20;
|
|
8
|
+
// Maximum number of PalletsInfo entries we expect in a single `PalletsInfo` value.
|
|
9
|
+
uint32 constant MAX_PALLETS_INFO = 64;
|
|
10
|
+
// Maximum number of entries in `InitiateTransfer.assets` (BoundedVec<AssetTransferFilter, MaxAssetTransferFilters> in Rust).
|
|
11
|
+
uint32 constant MAX_ASSET_TRANSFER_FILTERS = 6;
|
|
12
|
+
// Maximum length of a pallet name in bytes.
|
|
13
|
+
uint32 constant MAX_PALLET_NAME_LEN = 48;
|
|
14
|
+
// Maximum number of hints in a `SetHints` instruction, equal to the number of variants in the `Hint` enum.
|
|
15
|
+
uint32 constant HINT_NUM_VARIANTS = uint32(type(HintType).max) + 1;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Compact} from "../../../Scale/Compact.sol";
|
|
5
|
+
import {AssetInstance} from "../AssetInstance/AssetInstance.sol";
|
|
6
|
+
import {AssetInstanceCodec} from "../AssetInstance/AssetInstanceCodec.sol";
|
|
7
|
+
|
|
8
|
+
/// @dev Discriminant for the different types of Fungibility in XCM v5.
|
|
9
|
+
enum FungibilityType {
|
|
10
|
+
/// @custom:variant A fungible asset; we record a number of units, as a `uint128` in the inner item.
|
|
11
|
+
Fungible,
|
|
12
|
+
/// @custom:variant A non-fungible asset. We record the instance identifier in the inner item. Only one asset of each instance identifier may ever be in existence at once.
|
|
13
|
+
NonFungible
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// @notice Classification of whether an asset is fungible or not, along with a mandatory amount or instance.
|
|
17
|
+
struct Fungibility {
|
|
18
|
+
/// @custom:property The type of fungibility, determining how to interpret the payload. See `FungibilityType` enum for possible values.
|
|
19
|
+
FungibilityType fType;
|
|
20
|
+
/// @custom:property The encoded payload containing the fungibility data, whose structure depends on the `fType`.
|
|
21
|
+
bytes payload;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// @notice Parameters for the `Fungible` variant.
|
|
25
|
+
struct FungibleParams {
|
|
26
|
+
/// @custom:property The number of units of the fungible asset.
|
|
27
|
+
uint128 amount;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// @notice Parameters for the `NonFungible` variant.
|
|
31
|
+
struct NonFungibleParams {
|
|
32
|
+
/// @custom:property The specific non-fungible asset instance.
|
|
33
|
+
AssetInstance instance;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ============ Factory Functions ============
|
|
37
|
+
|
|
38
|
+
/// @notice Creates a `Fungibility` struct representing a fungible asset with the given amount.
|
|
39
|
+
/// @param params Parameters for the fungible variant.
|
|
40
|
+
function fungible(
|
|
41
|
+
FungibleParams memory params
|
|
42
|
+
) pure returns (Fungibility memory) {
|
|
43
|
+
return
|
|
44
|
+
Fungibility({
|
|
45
|
+
fType: FungibilityType.Fungible,
|
|
46
|
+
payload: Compact.encode(params.amount)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// @notice Creates a `Fungibility` struct representing a non-fungible asset with the given instance identifier.
|
|
51
|
+
/// @param params Parameters for the non-fungible variant.
|
|
52
|
+
function nonFungible(
|
|
53
|
+
NonFungibleParams memory params
|
|
54
|
+
) pure returns (Fungibility memory) {
|
|
55
|
+
return
|
|
56
|
+
Fungibility({
|
|
57
|
+
fType: FungibilityType.NonFungible,
|
|
58
|
+
payload: AssetInstanceCodec.encode(params.instance)
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Compact} from "../../../Scale/Compact.sol";
|
|
5
|
+
import {AssetInstance} from "../AssetInstance/AssetInstance.sol";
|
|
6
|
+
import {AssetInstanceCodec} from "../AssetInstance/AssetInstanceCodec.sol";
|
|
7
|
+
import {Fungibility, FungibilityType} from "./Fungibility.sol";
|
|
8
|
+
|
|
9
|
+
/// @title SCALE Codec for XCM v5 `Fungibility`
|
|
10
|
+
/// @notice SCALE-compliant encoder/decoder for the `Fungibility` type.
|
|
11
|
+
/// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
|
|
12
|
+
/// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
|
|
13
|
+
library FungibilityCodec {
|
|
14
|
+
error InvalidFungibilityLength();
|
|
15
|
+
error InvalidFungibilityType(uint8 fType);
|
|
16
|
+
error InvalidFungibilityPayload();
|
|
17
|
+
|
|
18
|
+
/// @notice Encodes a `Fungibility` struct into bytes.
|
|
19
|
+
/// @param fungibility The `Fungibility` struct to encode.
|
|
20
|
+
/// @return SCALE-encoded byte sequence representing the `Fungibility`.
|
|
21
|
+
function encode(
|
|
22
|
+
Fungibility memory fungibility
|
|
23
|
+
) internal pure returns (bytes memory) {
|
|
24
|
+
return abi.encodePacked(uint8(fungibility.fType), fungibility.payload);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// @notice Returns the number of bytes that a `Fungibility` struct would occupy when SCALE-encoded, starting at a given offset in the data.
|
|
28
|
+
/// @param data The byte sequence containing the encoded `Fungibility`.
|
|
29
|
+
/// @param offset The starting index in `data` from which to calculate the encoded size of the `Fungibility`.
|
|
30
|
+
/// @return The number of bytes that the `Fungibility` struct would occupy when SCALE-encoded, starting at the given offset.
|
|
31
|
+
function encodedSizeAt(
|
|
32
|
+
bytes memory data,
|
|
33
|
+
uint256 offset
|
|
34
|
+
) internal pure returns (uint256) {
|
|
35
|
+
if (data.length < offset + 1) {
|
|
36
|
+
revert InvalidFungibilityLength();
|
|
37
|
+
}
|
|
38
|
+
uint8 fType = uint8(data[offset]);
|
|
39
|
+
uint256 payloadLength;
|
|
40
|
+
++offset;
|
|
41
|
+
if (fType == uint8(FungibilityType.Fungible)) {
|
|
42
|
+
payloadLength = Compact.encodedSizeAt(data, offset);
|
|
43
|
+
} else if (fType == uint8(FungibilityType.NonFungible)) {
|
|
44
|
+
payloadLength = AssetInstanceCodec.encodedSizeAt(data, offset);
|
|
45
|
+
} else {
|
|
46
|
+
revert InvalidFungibilityType(fType);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (data.length < offset + payloadLength) {
|
|
50
|
+
revert InvalidFungibilityLength();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return 1 + payloadLength;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// @notice Decodes a `Fungibility` instance from bytes starting at the beginning of the data.
|
|
57
|
+
/// @param data The byte sequence containing the encoded `Fungibility`.
|
|
58
|
+
/// @return fungibility The decoded `Fungibility` struct.
|
|
59
|
+
/// @return bytesRead The total number of bytes read from the input data to decode the `Fungibility`.
|
|
60
|
+
function decode(
|
|
61
|
+
bytes memory data
|
|
62
|
+
)
|
|
63
|
+
internal
|
|
64
|
+
pure
|
|
65
|
+
returns (Fungibility memory fungibility, uint256 bytesRead)
|
|
66
|
+
{
|
|
67
|
+
return decodeAt(data, 0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// @notice Decodes a `Fungibility` instance from bytes starting at a given offset.
|
|
71
|
+
/// @param data The byte sequence containing the encoded `Fungibility`.
|
|
72
|
+
/// @param offset The starting index in `data` from which to decode the `Fungibility`.
|
|
73
|
+
/// @return fungibility The decoded `Fungibility` struct.
|
|
74
|
+
/// @return bytesRead The total number of bytes read from the input data to decode the `Fungibility`.
|
|
75
|
+
function decodeAt(
|
|
76
|
+
bytes memory data,
|
|
77
|
+
uint256 offset
|
|
78
|
+
)
|
|
79
|
+
internal
|
|
80
|
+
pure
|
|
81
|
+
returns (Fungibility memory fungibility, uint256 bytesRead)
|
|
82
|
+
{
|
|
83
|
+
if (data.length < offset + 1) {
|
|
84
|
+
revert InvalidFungibilityLength();
|
|
85
|
+
}
|
|
86
|
+
uint8 fType = uint8(data[offset]);
|
|
87
|
+
uint256 payloadLength = encodedSizeAt(data, offset) - 1; // subtract 1 byte for the fType
|
|
88
|
+
bytes memory payload = new bytes(payloadLength);
|
|
89
|
+
for (uint256 i = 0; i < payloadLength; i++) {
|
|
90
|
+
payload[i] = data[offset + 1 + i];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
Fungibility({fType: FungibilityType(fType), payload: payload}),
|
|
95
|
+
1 + payloadLength
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// @notice Decodes a `Fungibility` struct representing a fungible asset and extracts the amount.
|
|
100
|
+
/// @param fungibility The `Fungibility` struct to decode, which must have `fType` equal to `FungibilityType.Fungible`.
|
|
101
|
+
/// @return amount The number of units of the fungible asset, as a `uint128`.
|
|
102
|
+
function asFungible(
|
|
103
|
+
Fungibility memory fungibility
|
|
104
|
+
) internal pure returns (uint128 amount) {
|
|
105
|
+
if (fungibility.fType != FungibilityType.Fungible) {
|
|
106
|
+
revert InvalidFungibilityType(uint8(fungibility.fType));
|
|
107
|
+
}
|
|
108
|
+
(uint256 decodedAmount, ) = Compact.decode(fungibility.payload);
|
|
109
|
+
if (decodedAmount > type(uint128).max) {
|
|
110
|
+
revert InvalidFungibilityPayload();
|
|
111
|
+
}
|
|
112
|
+
unchecked {
|
|
113
|
+
amount = uint128(decodedAmount);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// @notice Decodes a `Fungibility` struct representing a non-fungible asset and extracts the instance identifier.
|
|
118
|
+
/// @param fungibility The `Fungibility` struct to decode, which must have `fType` equal to `FungibilityType.NonFungible`.
|
|
119
|
+
/// @return instance The `AssetInstance` struct identifying the specific instance of the non-fungible asset.
|
|
120
|
+
function asNonFungible(
|
|
121
|
+
Fungibility memory fungibility
|
|
122
|
+
) internal pure returns (AssetInstance memory instance) {
|
|
123
|
+
if (fungibility.fType != FungibilityType.NonFungible) {
|
|
124
|
+
revert InvalidFungibilityType(uint8(fungibility.fType));
|
|
125
|
+
}
|
|
126
|
+
(instance, ) = AssetInstanceCodec.decode(fungibility.payload);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Location} from "../Location/Location.sol";
|
|
5
|
+
import {LocationCodec} from "../Location/LocationCodec.sol";
|
|
6
|
+
|
|
7
|
+
/// @notice Discriminant for the `Hint` enum.
|
|
8
|
+
enum HintType {
|
|
9
|
+
/// @custom:variant Set asset claimer for all the trapped assets during the execution.
|
|
10
|
+
AssetClaimer
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// @notice A hint for XCM execution, changing the behaviour of the XCM program.
|
|
14
|
+
struct Hint {
|
|
15
|
+
/// @custom:property The type of the hint. See `HintType` enum for possible values.
|
|
16
|
+
HintType hType;
|
|
17
|
+
/// @custom:property The SCALE-encoded payload of the hint. Structure depends on `hType`.
|
|
18
|
+
bytes payload;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/// @notice Parameters for the `AssetClaimer` variant.
|
|
22
|
+
struct AssetClaimerParams {
|
|
23
|
+
/// @custom:property The claimer location.
|
|
24
|
+
Location location;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ============ Factory Functions ============
|
|
28
|
+
|
|
29
|
+
/// @notice Creates an `AssetClaimer` hint.
|
|
30
|
+
/// @param params Parameters for the asset-claimer variant.
|
|
31
|
+
/// @return A `Hint` struct representing the `AssetClaimer` hint.
|
|
32
|
+
function assetClaimer(
|
|
33
|
+
AssetClaimerParams memory params
|
|
34
|
+
) pure returns (Hint memory) {
|
|
35
|
+
return
|
|
36
|
+
Hint({
|
|
37
|
+
hType: HintType.AssetClaimer,
|
|
38
|
+
payload: LocationCodec.encode(params.location)
|
|
39
|
+
});
|
|
40
|
+
}
|