Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ describe('PersonalWallet/metadata', () => {
test('can submit tx with metadata and then query it', async () => {
const metadata: Cardano.TxMetadata = new Map([[123n, '1234']]);
const walletUtil = createWalletUtil(wallet);
const { minimumCoin } = await walletUtil.validateValue({ coins: 0n });
const { minimumCoin } = await walletUtil.validateOutput({
address: Cardano.PaymentAddress(
'addr_test1qqydn46r6mhge0kfpqmt36m6q43knzsd9ga32n96m89px3nuzcjqw982pcftgx53fu5527z2cj2tkx2h8ux2vxsg475qypp3m9'
),
value: { coins: 0n }
});

// Make sure the wallet has sufficient funds to run this test
await walletReady(wallet, minimumCoin);
Expand Down
27 changes: 5 additions & 22 deletions packages/tx-construction/src/output-validation/outputValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@ import { computeMinimumCoinQuantity, tokenBundleSizeExceedsLimit } from '../inpu
export const createOutputValidator = ({
protocolParameters: protocolParametersGetter
}: OutputValidatorContext): OutputValidator => {
const validateValue = async (
value: Cardano.Value,
const validateOutput = async (
{ address, value }: Cardano.TxOut,
protocolParameters?: ProtocolParametersRequiredByOutputValidator
): Promise<OutputValidation> => {
) => {
const { coinsPerUtxoByte, maxValueSize } = protocolParameters || (await protocolParametersGetter());
const stubMaxSizeAddress = Cardano.PaymentAddress(
'addr_test1qqydn46r6mhge0kfpqmt36m6q43knzsd9ga32n96m89px3nuzcjqw982pcftgx53fu5527z2cj2tkx2h8ux2vxsg475qypp3m9'
);
const stubTxOut: Cardano.TxOut = { address: stubMaxSizeAddress, value };
const stubTxOut: Cardano.TxOut = { address, value };
const negativeAssetQty = value.assets ? [...value.assets.values()].some((qty) => qty <= 0) : false;
if (negativeAssetQty) {
// return early, otherwise 'minimumCoin/maxValueSize' will fail with error: "ParseIntError { kind: InvalidDigit }"
Expand All @@ -39,18 +36,6 @@ export const createOutputValidator = ({
tokenBundleSizeExceedsLimit: tokenBundleSizeExceedsLimit(maxValueSize)(value.assets)
};
};
const validateValues = async (values: Iterable<Cardano.Value>) => {
const protocolParameters = await protocolParametersGetter();
const validations = new Map<Cardano.Value, OutputValidation>();
for (const value of values) {
validations.set(value, await validateValue(value, protocolParameters));
}
return validations;
};
const validateOutput = async (
output: Cardano.TxOut,
protocolParameters?: ProtocolParametersRequiredByOutputValidator
) => validateValue(output.value, protocolParameters);

return {
validateOutput,
Expand All @@ -61,8 +46,6 @@ export const createOutputValidator = ({
validations.set(output, await validateOutput(output, protocolParameters));
}
return validations;
},
validateValue,
validateValues
}
};
};
16 changes: 0 additions & 16 deletions packages/tx-construction/src/output-validation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,6 @@ export interface OutputValidation {
}

export interface OutputValidator {
/**
* Assumes that value will be used with an output that has:
* - no datum
* - grouped address (Shelley era+)
*
* @returns Validates that token bundle size is within limits and computes minimum coin quantity
*/
validateValue(output: Cardano.Value): Promise<OutputValidation>;
/**
* Assumes that values will be used with outputs that have:
* - no datum
* - grouped address (Shelley era+)
*
* @returns For every value, validates that token bundle size is within limits and computes minimum coin quantity
*/
validateValues(outputs: Iterable<Cardano.Value>): Promise<Map<Cardano.Value, OutputValidation>>;
/**
* @returns Validates that token bundle size is within limits and computes minimum coin quantity
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { Cardano } from '@cardano-sdk/core';
import { OutputValidator, createOutputValidator } from '../../src';

describe('createOutputValidator', () => {
const address = Cardano.PaymentAddress(
'addr_test1qqydn46r6mhge0kfpqmt36m6q43knzsd9ga32n96m89px3nuzcjqw982pcftgx53fu5527z2cj2tkx2h8ux2vxsg475qypp3m9'
);
let validator: OutputValidator;

beforeAll(() => {
Expand All @@ -14,67 +17,101 @@ describe('createOutputValidator', () => {
});
});

it('validateValue validates minimum coin quantity', async () => {
expect((await validator.validateValue({ coins: 2_000_000n })).coinMissing).toBe(0n);
expect((await validator.validateValue({ coins: 500_000n })).coinMissing).toBeGreaterThan(0n);
});
describe('validateOutput', () => {
it('validates minimum coin quantity', async () => {
expect((await validator.validateOutput({ address, value: { coins: 2_000_000n } })).coinMissing).toBe(0n);
expect((await validator.validateOutput({ address, value: { coins: 500_000n } })).coinMissing).toBeGreaterThan(0n);
});

it('validateValue validates bundle size', async () => {
expect(
(
await validator.validateValue({
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n]
]),
coins: 2_000_000n
})
).tokenBundleSizeExceedsLimit
).toBe(false);
expect(
(
await validator.validateValue({
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n],
[Cardano.AssetId('c01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 2n]
]),
coins: 2_000_000n
})
).tokenBundleSizeExceedsLimit
).toBe(true);
});
it('validates bundle size', async () => {
expect(
(
await validator.validateOutput({
address,
value: {
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n]
]),
coins: 2_000_000n
}
})
).tokenBundleSizeExceedsLimit
).toBe(false);
expect(
(
await validator.validateOutput({
address,
value: {
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n],
[Cardano.AssetId('c01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 2n]
]),
coins: 2_000_000n
}
})
).tokenBundleSizeExceedsLimit
).toBe(true);
});

it('validateValue validates negative asset quantity', async () => {
expect(
(
await validator.validateValue({
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n]
]),
coins: 2_000_000n
})
).negativeAssetQty
).toBe(false);
expect(
(
await validator.validateValue({
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n],
[Cardano.AssetId('c01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), -2n]
]),
coins: 2_000_000n
})
).negativeAssetQty
).toBe(true);
expect(
(
await validator.validateValue({
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n],
[Cardano.AssetId('c01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 0n]
]),
coins: 2_000_000n
})
).negativeAssetQty
).toBe(true);
it('validates negative asset quantity', async () => {
expect(
(
await validator.validateOutput({
address,
value: {
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n]
]),
coins: 2_000_000n
}
})
).negativeAssetQty
).toBe(false);
expect(
(
await validator.validateOutput({
address,
value: {
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n],
[Cardano.AssetId('c01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), -2n]
]),
coins: 2_000_000n
}
})
).negativeAssetQty
).toBe(true);
expect(
(
await validator.validateOutput({
address,
value: {
assets: new Map([
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n],
[Cardano.AssetId('c01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 0n]
]),
coins: 2_000_000n
}
})
).negativeAssetQty
).toBe(true);
});

it('uses output address size as minimum coin computation parameter', async () => {
const value: Cardano.Value = { coins: 123n };
const { minimumCoin: byronAddressMinimumCoin } = await validator.validateOutput({
address: Cardano.PaymentAddress(
'DdzFFzCqrht4PWfBGtmrQz4x1GkZHYLVGbK7aaBkjWxujxzz3L5GxCgPiTsks5RjUr3yX9KvwKjNJBt7ZzPCmS3fUQrGeRvo9Y1YBQKQ'
),
value
});
const { minimumCoin: shelleyAddressMinimumCoin } = await validator.validateOutput({
address: Cardano.PaymentAddress(
'addr_test1qqydn46r6mhge0kfpqmt36m6q43knzsd9ga32n96m89px3nuzcjqw982pcftgx53fu5527z2cj2tkx2h8ux2vxsg475qypp3m9'
),
value
});
expect(byronAddressMinimumCoin).toBeGreaterThan(shelleyAddressMinimumCoin);
});
});
});
Loading