Skip to content

Commit

Permalink
refactor: etna builder importtx with test
Browse files Browse the repository at this point in the history
  • Loading branch information
erictaylor committed Sep 26, 2024
1 parent 7c0d056 commit b3c6bfd
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 47 deletions.
76 changes: 76 additions & 0 deletions src/vms/pvm/etna-builder/builder.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { testContext as _testContext } from '../../../fixtures/context';
import {
getLockedUTXO,
getNotTransferOutput,
getTransferableInputForTest,
getTransferableOutForTest,
getValidUtxo,
Expand Down Expand Up @@ -936,4 +938,78 @@ describe('./src/vms/pvm/etna-builder/builder.test.ts', () => {
expectTxs(unsignedTx.getTx(), expectedTx);
});
});

describe('ImportTx', () => {
it('should create an ImportTx with both AVAX and non-AVAX assets', () => {
const utxos = [
getLockedUTXO(), // Locked and should be ignored.
getNotTransferOutput(), // Invalid and should be ignored.
// AVAX Assets
getValidUtxo(new BigIntPr(BigInt(35 * 1e9)), testAvaxAssetID),
getValidUtxo(new BigIntPr(BigInt(28 * 1e9)), testAvaxAssetID),
// Non-AVAX Assets (Jupiter)
getValidUtxo(new BigIntPr(BigInt(15 * 1e9)), Id.fromString('jupiter')),
getValidUtxo(new BigIntPr(BigInt(11 * 1e9)), Id.fromString('jupiter')),
// Non-AVAX Asset (Mars)
getValidUtxo(new BigIntPr(BigInt(9 * 1e9)), Id.fromString('mars')),
];

const unsignedTx = newImportTx(
{
fromAddressesBytes,
sourceChainId: testContext.cBlockchainID,
toAddresses: [testAddress1],
utxos,
},
testContext,
);

const { baseTx, ins: importedIns } = unsignedTx.getTx() as ImportTx;
const { inputs, outputs } = baseTx;

const [amountConsumed, expectedAmountConsumed, expectedFee] =
checkFeeIsCorrect({
unsignedTx,
inputs,
outputs,
additionalInputs: importedIns,
});

expect(amountConsumed).toEqual(expectedAmountConsumed);

const expectedTx = new ImportTx(
AvaxBaseTx.fromNative(
testContext.networkID,
testContext.pBlockchainID,
[
// "Other" assets are first. Sorted by TransferableInput.compare
TransferableOutput.fromNative('mars', BigInt(9 * 1e9), [
testAddress1,
]),
TransferableOutput.fromNative('jupiter', BigInt(26 * 1e9), [
testAddress1,
]),
// AVAX come last.
TransferableOutput.fromNative(
testContext.avaxAssetID,
BigInt((35 + 28) * 1e9) - expectedFee,
[testAddress1],
),
],
[],
new Uint8Array(),
),
Id.fromString(testContext.cBlockchainID),
[
TransferableInput.fromUtxoAndSigindicies(utxos[2], [0]),
TransferableInput.fromUtxoAndSigindicies(utxos[3], [0]),
TransferableInput.fromUtxoAndSigindicies(utxos[4], [0]),
TransferableInput.fromUtxoAndSigindicies(utxos[5], [0]),
TransferableInput.fromUtxoAndSigindicies(utxos[6], [0]),
],
);

expectTxs(unsignedTx.getTx(), expectedTx);
});
});
});
93 changes: 46 additions & 47 deletions src/vms/pvm/etna-builder/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
PlatformChainID,
PrimaryNetworkID,
} from '../../../constants/networkIDs';
import type { TransferOutput } from '../../../serializable';
import {
Input,
NodeId,
Expand Down Expand Up @@ -233,66 +234,65 @@ export const newImportTx: TxBuilderFn<NewImportTxProps> = (
const fromAddresses = addressesFromBytes(fromAddressesBytes);
const defaultedOptions = defaultSpendOptions(fromAddressesBytes, options);

const importedInputs: TransferableInput[] = [];
const importedAmounts: Record<string, bigint> = {};

for (const utxo of utxos) {
const out = utxo.output;

if (!isTransferOut(out)) {
continue;
}

const { sigIndicies: inputSigIndices } =
matchOwners(
utxo.getOutputOwners(),
fromAddresses,
defaultedOptions.minIssuanceTime,
) || {};

if (inputSigIndices === undefined) {
// We couldn't spend this UTXO, so we skip to the next one.
continue;
}

importedInputs.push(
new TransferableInput(
utxo.utxoId,
utxo.assetId,
new TransferInput(
out.amt,
new Input(inputSigIndices.map((value) => new Int(value))),
),
),
const { importedInputs, importedAmounts } = utxos
.filter((utxo): utxo is Utxo<TransferOutput> => isTransferOut(utxo.output))
.reduce<{
importedInputs: TransferableInput[];
importedAmounts: Record<string, bigint>;
}>(
(acc, utxo) => {
const { sigIndicies: inputSigIndices } =
matchOwners(
utxo.getOutputOwners(),
fromAddresses,
defaultedOptions.minIssuanceTime,
) || {};

if (inputSigIndices === undefined) {
// We couldn't spend this UTXO, so we skip to the next one.
return acc;
}

const assetId = utxo.getAssetId();

return {
importedInputs: [
...acc.importedInputs,
new TransferableInput(
utxo.utxoId,
utxo.assetId,
new TransferInput(
utxo.output.amt,
new Input(inputSigIndices.map((value) => new Int(value))),
),
),
],
importedAmounts: {
...acc.importedAmounts,
[assetId]:
(acc.importedAmounts[assetId] ?? 0n) + utxo.output.amount(),
},
};
},
{ importedInputs: [], importedAmounts: {} },
);

const assetId = utxo.getAssetId();

importedAmounts[assetId] = (importedAmounts[assetId] ?? 0n) + out.amount();
}

if (importedInputs.length === 0) {
throw new Error('no UTXOs available to import');
}

const importedAvax = importedAmounts[context.avaxAssetID];

importedInputs.sort(TransferableInput.compare);
const addressMaps = AddressMaps.fromTransferableInputs(
importedInputs,
utxos,
defaultedOptions.minIssuanceTime,
fromAddressesBytes,
);

const outputs: TransferableOutput[] = [];

for (const [assetID, amount] of Object.entries(importedAmounts)) {
if (assetID === context.avaxAssetID) {
continue;
}

outputs.push(
const outputs: TransferableOutput[] = Object.entries(importedAmounts)
.filter(([assetID]) => assetID !== context.avaxAssetID)
.map(([assetID, amount]) =>
TransferableOutput.fromNative(
assetID,
amount,
Expand All @@ -301,7 +301,6 @@ export const newImportTx: TxBuilderFn<NewImportTxProps> = (
threshold,
),
);
}

const memoComplexity = getMemoComplexity(defaultedOptions);

Expand Down Expand Up @@ -341,7 +340,7 @@ export const newImportTx: TxBuilderFn<NewImportTxProps> = (
new Bytes(defaultedOptions.memo),
),
Id.fromString(sourceChainId),
importedInputs,
importedInputs.sort(TransferableInput.compare),
),
inputUTXOs,
addressMaps,
Expand Down

0 comments on commit b3c6bfd

Please sign in to comment.