Skip to content

Commit

Permalink
feat(dart/catalyst_cardano_serialization)!: Implement tiered fee calc…
Browse files Browse the repository at this point in the history
…ulation for reference scripts (#871)

* fix(dart/catalyst_cardano_serialization): update inputs to Set for CDDL alignment and change referenceInputs for reference script fee calculation

* feat(catalyst_cardano_serialization): add length getter to the Script's classes for reference script fee calculation

* feat(catalyst_cardano_serialization): Implement tiered fee calculation for reference scripts

  * Replace LinearFee with TieredFee to support tiered fee calculation for transactions that consider reference scripts.
  * Rename the minNoScriptFee() method to minFee() for clarity.
  * Make the script constructors private and add a fromHex(String cborHex) factory constructor for PlutusScripts.
  * Add tests for the length property of scripts, which also validates the fromHex factory constructor.
  * Add tests for fee calculation with reference scripts.
  * Add a ReferenceScriptSizeLimitExceededException class for handling errors when the reference script size limit is exceeded.

* fix(catalyst_cardano_serialization): add missing fields (multiplier, sizeIncrement, maxRefScriptSize) to props for equality

* fix(catalyst_cardano): resolve compilation errors in dependent packages caused by catalyst_cardano_serialization changes

---------

Co-authored-by: Steven Johnson <[email protected]>
Co-authored-by: Dominik Toton <[email protected]>
  • Loading branch information
3 people authored Sep 24, 2024
1 parent 626476a commit 28cb3c5
Show file tree
Hide file tree
Showing 18 changed files with 868 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,14 @@ Future<void> main() async {
}
Transaction _buildUnsignedTx({
required List<TransactionUnspentOutput> utxos,
required Set<TransactionUnspentOutput> utxos,
required ShelleyAddress changeAddress,
}) {
const txBuilderConfig = TransactionBuilderConfig(
feeAlgo: LinearFee(
constant: Coin(155381),
coefficient: Coin(44),
feeAlgo: TieredFee(
constant: 155381,
coefficient: 44,
refScriptByteCost: 15,
),
maxTxSize: 16384,
maxValueSize: 5000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ class _WalletDetailsState extends State<_WalletDetails> {
List<ShelleyAddress>? _rewardAddresses;
List<ShelleyAddress>? _unusedAddresses;
List<ShelleyAddress>? _usedAddresses;
List<TransactionUnspentOutput>? _utxos;
Set<TransactionUnspentOutput>? _utxos;
PubDRepKey? _pubDRepKey;
List<PubStakeKey>? _registeredPubStakeKeys;
List<PubStakeKey>? _unregisteredPubStakeKeys;
Expand Down Expand Up @@ -450,7 +450,7 @@ String _formatBalance(Balance? balance) {
return buffer.toString();
}

String _formatUtxos(List<TransactionUnspentOutput>? utxos) {
String _formatUtxos(Set<TransactionUnspentOutput>? utxos) {
if (utxos == null) {
return '---';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Future<void> _signAndSubmitRbacTx({
}

Future<X509MetadataEnvelope<RegistrationData>> _buildMetadataEnvelope({
required List<TransactionUnspentOutput> utxos,
required Set<TransactionUnspentOutput> utxos,
required ShelleyAddress rewardAddress,
}) async {
final seed = List.generate(
Expand Down Expand Up @@ -152,7 +152,7 @@ Future<X509MetadataEnvelope<RegistrationData>> _buildMetadataEnvelope({
}

Transaction _buildUnsignedRbacTx({
required List<TransactionUnspentOutput> inputs,
required Set<TransactionUnspentOutput> inputs,
required ShelleyAddress changeAddress,
required ShelleyAddress rewardAddress,
required AuxiliaryData auxiliaryData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Future<void> _signAndSubmitTx({
}

Transaction _buildUnsignedTx({
required List<TransactionUnspentOutput> utxos,
required Set<TransactionUnspentOutput> utxos,
required ShelleyAddress changeAddress,
}) {
/* cSpell:disable */
Expand Down Expand Up @@ -81,9 +81,10 @@ Transaction _buildUnsignedTx({

TransactionBuilderConfig _buildTransactionBuilderConfig() {
return const TransactionBuilderConfig(
feeAlgo: LinearFee(
constant: Coin(155381),
coefficient: Coin(44),
feeAlgo: TieredFee(
constant: 155381,
coefficient: 44,
refScriptByteCost: 15,
),
maxTxSize: 16384,
maxValueSize: 5000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ abstract interface class CardanoWalletApi {
/// specified in amount, and if this cannot be attained,
/// null shall be returned. The results can be further paginated by
/// [paginate] if it is not null.
Future<List<TransactionUnspentOutput>> getUtxos({
Future<Set<TransactionUnspentOutput>> getUtxos({
Balance? amount,
Paginate? paginate,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class JSCardanoWalletApiProxy implements CardanoWalletApi {
}

@override
Future<List<TransactionUnspentOutput>> getUtxos({
Future<Set<TransactionUnspentOutput>> getUtxos({
Balance? amount,
Paginate? paginate,
}) async {
Expand All @@ -183,7 +183,7 @@ class JSCardanoWalletApiProxy implements CardanoWalletApi {
paginate != null ? JSPaginate.fromDart(paginate) : makeUndefined(),
);

if (utxos == null) return [];
if (utxos == null) return {};

return await utxos.toDart.then(
(array) => array.toDart
Expand All @@ -192,7 +192,7 @@ class JSCardanoWalletApiProxy implements CardanoWalletApi {
cbor.decode(hex.decode(item.toDart)),
),
)
.toList(),
.toSet(),
);
} catch (ex) {
throw _mapApiException(ex) ??
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ import 'package:convert/convert.dart';
/* cSpell:disable */
void main() {
const txBuilderConfig = TransactionBuilderConfig(
feeAlgo: LinearFee(
constant: Coin(155381),
coefficient: Coin(44),
feeAlgo: TieredFee(
constant: 155381,
coefficient: 44,
refScriptByteCost: 0,
),
maxTxSize: 16384,
maxValueSize: 5000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import 'package:convert/convert.dart';
/* cSpell:disable */
void main() {
const txBuilderConfig = TransactionBuilderConfig(
feeAlgo: LinearFee(
constant: Coin(155381),
coefficient: Coin(44),
feeAlgo: TieredFee(
constant: 155381,
coefficient: 44,
refScriptByteCost: 15,
),
maxTxSize: 16384,
maxValueSize: 5000,
Expand Down Expand Up @@ -58,7 +59,7 @@ void main() {

final txBuilder = TransactionBuilder(
config: txBuilderConfig,
inputs: [utxo],
inputs: {utxo},
// fee can be left empty so that it's auto calculated or can be hardcoded
// fee: const Coin(1000000),
ttl: const SlotBigNum(410021),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class TransactionBuilder extends Equatable {
///
/// Enough [inputs] must be provided to be greater or equal
/// the amount of [outputs] + [fee].
final List<TransactionUnspentOutput> inputs;
final Set<TransactionUnspentOutput> inputs;

/// The list of transaction outputs which describes which address
/// will receive what amount of [Coin].
Expand Down Expand Up @@ -64,7 +64,7 @@ final class TransactionBuilder extends Equatable {
final Coin? totalCollateral;

/// Reference inputs as nonempty set of transaction inputs.
final Set<TransactionInput>? referenceInputs;
final Set<TransactionUnspentOutput>? referenceInputs;

/// The builder that builds the witness set of the transaction.
///
Expand Down Expand Up @@ -249,7 +249,7 @@ final class TransactionBuilder extends Equatable {
Coin minFee() {
final txBody = _copyWith(fee: const Coin(Numbers.intMaxValue)).buildBody();
final fullTx = buildFakeTransaction(txBody);
return config.feeAlgo.minNoScriptFee(fullTx);
return config.feeAlgo.minFee(fullTx, {...inputs, ...?referenceInputs});
}

@override
Expand Down Expand Up @@ -521,7 +521,7 @@ final class TransactionBuilder extends Equatable {
networkId: networkId,
collateralReturn: collateralReturn,
totalCollateral: totalCollateral,
referenceInputs: referenceInputs,
referenceInputs: referenceInputs?.map((utxo) => utxo.input).toSet(),
);
}

Expand Down Expand Up @@ -555,7 +555,7 @@ final class TransactionBuilder extends Equatable {
/// protocol parameters and other constants.
final class TransactionBuilderConfig extends Equatable {
/// The protocol parameter which describes the transaction fee algorithm.
final LinearFee feeAlgo;
final TieredFee feeAlgo;

/// The protocol parameter which limits the maximum transaction size in bytes.
final int maxTxSize;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,21 @@ final class InsufficientAdaForAssetsException extends Equatable
@override
List<Object?> get props => [];
}

/// Exception thrown when the total size of reference scripts exceeds the limit.
final class ReferenceScriptSizeLimitExceededException extends Equatable
implements Exception {
/// The maximum size of reference scripts allowed per transaction.
final int maxRefScriptSize;

/// The default constructor for [ReferenceScriptSizeLimitExceededException].
const ReferenceScriptSizeLimitExceededException(this.maxRefScriptSize);

@override
String toString() =>
'Total size of reference scripts exceeds the limit of $maxRefScriptSize '
'bytes';

@override
List<Object?> get props => [maxRefScriptSize];
}
Loading

0 comments on commit 28cb3c5

Please sign in to comment.