Skip to content

Commit

Permalink
feat: add transaction serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
capt-nemo429 committed Feb 19, 2023
1 parent 7822370 commit 198a0b7
Show file tree
Hide file tree
Showing 5 changed files with 746 additions and 21 deletions.
4 changes: 0 additions & 4 deletions packages/core/src/builder/transactionBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,6 @@ describe("Building", () => {
tokenId: "aef39c526e0c5d9b94e4b93f03b661c8e232382a32c71e1e74b14fc45e09fbed",
amount: "4"
})
// .addTokens({
// tokenId: "aef39c526e0c5d9b94e4b93f03b661c8e232382a32c71e1e74b14fc45e09fbed",
// amount: "2"
// })
.setAdditionalRegisters({
R4: "08cd038d39af8c37583609ff51c6a577efe60684119da2fbd0d75f9c72372886a58a63",
R5: "05c0a38601",
Expand Down
38 changes: 31 additions & 7 deletions packages/core/src/serializer/sigma/boxSerializer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Box } from "@fleet-sdk/common";
import { bytesToHex } from "@noble/hashes/utils";
import { serializeBox } from "./boxSerializer";

Expand All @@ -22,7 +23,7 @@ describe("Serialize ErgoBox", () => {
],
confirmed: true
},
bytes:
serialized:
"c0843d0008cd038d39af8c37583609ff51c6a577efe60684119da2fbd0d75f9c72372886a58a63cdee330150fdc80e168c153e472bd7e3dd18a4a0b9e90c550206fdbdb789ee8afdd3b1a90100ae11d207f0989945f63909d2f703b2640acf4f654a8fdadd23570a640f9d12ee00"
},
{
Expand Down Expand Up @@ -135,7 +136,7 @@ describe("Serialize ErgoBox", () => {
}
]
},
bytes:
serialized:
"caf0ca330008cd038d39af8c37583609ff51c6a577efe60684119da2fbd0d75f9c72372886a58a639fbf3318de5ee573c6a492c129d51119649bfeaedfc9afa6f54af576e62e1f7f3bbd42078e87f9f1051fd6e032e8476c4aa54c18c1a308dce83940e8f4a28f576440513ed7326ad4898a993d03faf2cb329f2e90d6d23b58d91bbb6c046aa143261cc21f52fbe2824bfcbf043274251ce2cb4eb2024a1a155e19ad1d1f58ff8b9e6eb034a3bb1fd58802757d2380a0b787e905003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d00136aba4b4a97b65be491cf9f5ca57b5408b0da8d0194f30ec8330d1e8946161c103c5d6629329285b14ed3eac1dba0e07dbd1e61ee332c2039a7a9c04e8be0cb74eb6f6b1c7ae03a3b3fa62124ef52209a46121e3f93ca98d7fc24198009e90fde8205ef9d3fc330100bd762484086cf560d3127eb53f0769d76244d9737636b2699d55c56cd470bfa589015a34d53ca483924b9a6aa0c771f11888881b516a8d1a9cdc535d063fe26d065e21d601123e8838b95cdaebe24e594276b2a89cd38e98add98405bb5327520ecf6cacf2cb07bf59773def7e08375a553be4cbd862de85f66e6dd3dccb8f87f53158f9255bf59582a6efc79e84911102f31739e2e4937bb9afb552943753d1e3e9cdd1a5e5661949cb0cef93f907eade9e0d30974274078845f263b4f21787e33cc99e9ec19a17ad85a5bc6da2cca91c5a2ec7c98b8c850b0cd8c9f416e5b1ca9f986a7f10a84191dfb85941619e49e53c0dc30ebf83324bfc1c1c51c3a53abfe87e6db9a03c649e8360f255ffc4bd34303d30fc7db23ae551db9c04fbbaac7337d051c10fc3da0ccb864f4d32d40027551e1c3ea3ce361f39b91e40c10fef802b475c06189fdbf844153cdc1d449a5ba87cce13d11bb47b5a539f27f12bfdecfad1f82a472c3d4ecaa08fb7392ff041ee2e6af75f4a558810a74b28600549d5392810e880ade204bf2afb01fde7e373e22f24032434a7b883913bd87a23b62ee8b43eba53c9f6c201bf337a2ce726259ad31e043c5b3d432e31b403fc6686691171e0e0a319b9ae7a0100b1e236b60b95c2c6f8007a9d89bc460fc9e78f98b09faec9449007b40bccf3888124d71693c49a84fbbecd4908c94813b46514b18b67a99952dc1e6e4791556de413db0eee105e8290b090a773b7c56756507d45a76743d73bce54e8a915e95d9eb97360b681e596010089b758cfed2b9eac6721fb4576d8ba016202fdd939f32425aa7e2aefcbdde32e01"
},
{
Expand All @@ -156,7 +157,7 @@ describe("Serialize ErgoBox", () => {
}
]
},
bytes:
serialized:
"c0843d0008cd02200a1c1b8fa17ec82de54bcaef96f23d7b34196c0410f6f578abdbf163b14b258abd33010cd8c9f416e5b1ca9f986a7f10a84191dfb85941619e49e53c0dc30ebf83324b0100b66aab1e43874ad8c5583f685a7d6d947238c373f615aee1d04ee604ba2c934000"
},
{
Expand All @@ -177,7 +178,7 @@ describe("Serialize ErgoBox", () => {
}
]
},
bytes:
serialized:
"d68bb4440008cd038d39af8c37583609ff51c6a577efe60684119da2fbd0d75f9c72372886a58a6380ea30011fd6e032e8476c4aa54c18c1a308dce83940e8f4a28f576440513ed7326ad489fcf715008d210ec0a43662a397b1a35cf3091b246927eba1a51bae6696c8a640491eecd602"
},
{
Expand All @@ -193,7 +194,7 @@ describe("Serialize ErgoBox", () => {
additionalRegisters: {},
assets: []
},
bytes:
serialized:
"c0843d0008cd0357ab5c00616362607d7d9e7000f35f4451a35dd99228b36a38f1461e4308e48480ea3000008d210ec0a43662a397b1a35cf3091b246927eba1a51bae6696c8a640491eecd600"
},
{
Expand All @@ -219,14 +220,37 @@ describe("Serialize ErgoBox", () => {
R6: "0e20f7ef73c4a4ab91b84bb0a2905108d534114472ec057be3a57a9dfc9b1fbd85c1"
}
},
bytes:
serialized:
"90bbe2ee371014040004000e208c27dd9d8a35aac1e3167d58858c0a8b4059b277da790552e37eba22df9b903504000400040204020101040205a0c21e040204080500040c040204a0c21e0402050a05c8010402d806d601b2a5730000d602b5db6501fed9010263ed93e4c67202050ec5a7938cb2db63087202730100017302d603b17202d604e4c6b272027303000605d605d90105049590720573047204e4c6b272029972057305000605d606b07202860273067307d901063c400163d803d6088c720601d6098c720801d60a8c72060286029a72097308ededed8c72080293c2b2a5720900d0cde4c6720a040792c1b2a5720900730992da720501997209730ae4c6720a0605ea02d1ededededededed93cbc27201e4c6a7060e927203730b93db63087201db6308a793e4c6720104059db07202730cd9010741639a8c720701e4c68c72070206057e72030593e4c6720105049ae4c6a70504730d92c1720199c1a77e9c9a7203730e730f058c72060292da720501998c72060173109972049d9c720473117312b2ad7202d9010763cde4c672070407e4c6b2a5731300040400db843401011d3364de07e5a26f0c4eef0852cddb387039a921b7154ef3cab22c6eda887f010305cab4cd9a0304bc89680e20f7ef73c4a4ab91b84bb0a2905108d534114472ec057be3a57a9dfc9b1fbd85c1f1ab205c16865eeadb8eeade83d3de93fbb6cf203da15a8a485dc449c71b663a00"
}
];

it("Should serialize", () => {
for (const tv of testVectors) {
expect(bytesToHex(serializeBox(tv.json))).toBe(tv.bytes);
expect(bytesToHex(serializeBox(tv.json))).toBe(tv.serialized);
}
});

it("Should fail with BoxCandidate without distinct tokens list", () => {
expect(() => {
serializeBox({
boxId: "8f281813a88e3016d0e0e7b83c5917931f63b610e4dc9af84ad1adecae50778d",
value: 14996250000n,
creationHeight: 852571,
ergoTree:
"1014040004000e208c27dd9d8a35aac1e3167d58858c0a8b4059b277da790552e37eba22df9b903504000400040204020101040205a0c21e040204080500040c040204a0c21e0402050a05c8010402d806d601b2a5730000d602b5db6501fed9010263ed93e4c67202050ec5a7938cb2db63087202730100017302d603b17202d604e4c6b272027303000605d605d90105049590720573047204e4c6b272029972057305000605d606b07202860273067307d901063c400163d803d6088c720601d6098c720801d60a8c72060286029a72097308ededed8c72080293c2b2a5720900d0cde4c6720a040792c1b2a5720900730992da720501997209730ae4c6720a0605ea02d1ededededededed93cbc27201e4c6a7060e927203730b93db63087201db6308a793e4c6720104059db07202730cd9010741639a8c720701e4c68c72070206057e72030593e4c6720105049ae4c6a70504730d92c1720199c1a77e9c9a7203730e730f058c72060292da720501998c72060173109972049d9c720473117312b2ad7202d9010763cde4c672070407e4c6b2a5731300040400",
assets: [
{
tokenId: "011d3364de07e5a26f0c4eef0852cddb387039a921b7154ef3cab22c6eda887f",
amount: 1n
}
],
additionalRegisters: {
R4: "05cab4cd9a03",
R5: "04bc8968",
R6: "0e20f7ef73c4a4ab91b84bb0a2905108d534114472ec057be3a57a9dfc9b1fbd85c1"
}
} as unknown as Box<string>);
}).toThrow();
});
});
58 changes: 48 additions & 10 deletions packages/core/src/serializer/sigma/boxSerializer.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,68 @@
import { Amount, Box, NonMandatoryRegisters, TokenAmount } from "@fleet-sdk/common";
import {
Amount,
Box,
BoxCandidate,
NonMandatoryRegisters,
some,
TokenAmount
} from "@fleet-sdk/common";
import { ensureBigInt, isDefined, isEmpty } from "@fleet-sdk/common";
import { concatBytes, hexToBytes } from "@noble/hashes/utils";
import { ErgoBox } from "../../models/ergoBox";
import { vlqEncode, vqlEncodeBigInt } from "../vlq";

export function serializeBox(box: Box<Amount> | ErgoBox): Uint8Array {
return concatBytes(
export function serializeBox(box: Box<Amount> | ErgoBox): Uint8Array;
export function serializeBox(box: BoxCandidate<Amount>, distinctTokenIds: string[]): Uint8Array;
export function serializeBox(
box: Box<Amount> | ErgoBox | BoxCandidate<Amount>,
distinctTokenIds?: string[]
): Uint8Array {
const bytes = concatBytes(
vqlEncodeBigInt(ensureBigInt(box.value)),
hexToBytes(box.ergoTree),
vlqEncode(box.creationHeight),
serializeTokens(box.assets),
serializeRegisters(box.additionalRegisters),
hexToBytes(box.transactionId),
vlqEncode(box.index)
serializeTokens(box.assets, distinctTokenIds),
serializeRegisters(box.additionalRegisters)
);

if (isDefined(distinctTokenIds)) {
return bytes;
} else {
if (!isBox(box)) {
throw new Error("Invalid box type.");
}

return concatBytes(bytes, hexToBytes(box.transactionId), vlqEncode(box.index));
}
}

function serializeTokens(tokens: TokenAmount<Amount>[]): Uint8Array {
function isBox<T extends Amount>(box: Box<Amount> | ErgoBox | BoxCandidate<Amount>): box is Box<T> {
const castedBox = box as Box<T>;

return isDefined(castedBox.transactionId) && isDefined(castedBox.index);
}

function serializeTokens(tokens: TokenAmount<Amount>[], tokenIds?: string[]): Uint8Array {
if (isEmpty(tokens)) {
return Uint8Array.from([0]);
}

if (some(tokenIds)) {
return concatBytes(
vlqEncode(tokens.length),
...tokens.map((token) =>
concatBytes(
vlqEncode(tokenIds.indexOf(token.tokenId)),
vqlEncodeBigInt(ensureBigInt(token.amount))
)
)
);
}

return concatBytes(
vlqEncode(tokens.length),
...tokens.map((asset) =>
concatBytes(hexToBytes(asset.tokenId), vqlEncodeBigInt(ensureBigInt(asset.amount)))
...tokens.map((token) =>
concatBytes(hexToBytes(token.tokenId), vqlEncodeBigInt(ensureBigInt(token.amount)))
)
);
}
Expand Down
Loading

0 comments on commit 198a0b7

Please sign in to comment.