Skip to content

Commit 0a47fae

Browse files
Merge pull request #97 from Biglup/feat/add-donate-to-treasury-to-builder
Feat/add donate to treasury to builder
2 parents 866a186 + 1c6431f commit 0a47fae

File tree

11 files changed

+430
-40
lines changed

11 files changed

+430
-40
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
Next (V1.1.x)
22
---------------------
33

4+
V1.1.7
5+
---------------------
6+
7+
- Add donate to treasury function to tx builder.
8+
- Increase url max size on pool metadata from 64 to 128 bytes.
9+
410
V1.1.6
511
---------------------
612

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
VERSION_MAJOR=1
22
VERSION_MINOR=1
3-
VERSION_PATCH=6
3+
VERSION_PATCH=7

doc/src/sections/api/transaction_builder/transaction_builder.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ Transaction Builder
4141

4242
------------
4343

44+
.. doxygenfunction:: cardano_tx_builder_set_donation
45+
46+
------------
47+
4448
.. doxygenfunction:: cardano_tx_builder_set_utxos
4549

4650
------------
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
* \file donate_to_treasury_example.c
3+
*
4+
* \author angel.castillo
5+
* \date Aug 18, 2025
6+
*
7+
* Copyright 2025 Biglup Labs
8+
*
9+
* Licensed under the Apache License, Version 2.0 (the "License")
10+
* you may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
*/
21+
22+
/* INCLUDES ******************************************************************/
23+
24+
#include "providers/provider_factory.h"
25+
26+
#include "utils/console.h"
27+
#include "utils/utils.h"
28+
#include <cardano/cardano.h>
29+
30+
#include <stdlib.h>
31+
#include <string.h>
32+
33+
/* CONSTANTS *****************************************************************/
34+
35+
static const char* SERIALIZED_BIP32_KEY_HANDLER = "0a0a0a0a01010000005c97db5e09b3a4919ec75ed1126056241a1e5278731c2e0b01bea0a5f42c22db4131e0a4bbe75633677eb0e60e2ecd3520178f85c7e0d4be77a449087fe9674ee52f946b07c1b56d228c496ec0d36dd44212ba8af0f6eed1a82194dd69f479c603";
36+
static const uint64_t CONFIRM_TX_TIMEOUT_MS = 240000U;
37+
static const int64_t LOVELACE_TO_DONATE = 2000000U;
38+
static const uint64_t PAYMENT_CRED_INDEX = 0U;
39+
static const uint64_t STAKE_CRED_INDEX = 0U;
40+
static const uint64_t SECONDS_IN_TWO_HOURS = 60UL * 60UL * 2UL;
41+
42+
static const cardano_account_derivation_path_t ACCOUNT_DERIVATION_PATH = {
43+
.purpose = 1852U | 0x80000000,
44+
.coin_type = 1815U | 0x80000000,
45+
.account = 0U
46+
};
47+
48+
static const cardano_derivation_path_t SIGNER_DERIVATION_PATH = {
49+
.purpose = 1852U | 0x80000000,
50+
.coin_type = 1815U | 0x80000000,
51+
.account = 0U,
52+
.role = 0U,
53+
.index = 0U
54+
};
55+
56+
/* DECLARATIONS **************************************************************/
57+
58+
/**
59+
* \brief Retrieves the password for the secure key handler.
60+
*
61+
* \param buffer The buffer where to write the password.
62+
* \param buffer_len The size of the buffer.
63+
*
64+
* \return The length of the password (or -1 on error).
65+
*/
66+
static int32_t
67+
get_passphrase(byte_t* buffer, const size_t buffer_len)
68+
{
69+
console_warn("Enter passphrase: ");
70+
char password[128] = { 0 };
71+
const int32_t password_len = console_read_password(password, sizeof(password));
72+
73+
if (buffer_len < password_len)
74+
{
75+
return -1;
76+
}
77+
78+
cardano_utils_safe_memcpy(buffer, buffer_len, &password[0], password_len);
79+
80+
// Clear local password from memory
81+
cardano_memzero(password, sizeof(password));
82+
83+
return password_len;
84+
}
85+
86+
/* MAIN **********************************************************************/
87+
88+
/**
89+
* \brief Entry point of the program.
90+
*
91+
* \return Returns `0` on successful execution, or a non-zero value if there is an error.
92+
*/
93+
int
94+
main(void)
95+
{
96+
console_info("Donate lovelace to treasury Example");
97+
console_info("libcardano-c: V-%s\n", cardano_get_lib_version());
98+
99+
console_info("This example will donate %d lovelace to the treasury.", LOVELACE_TO_DONATE);
100+
101+
console_set_foreground_color(CONSOLE_COLOR_GREEN);
102+
console_write("\nUse passphrase: 'password'\n\n");
103+
console_reset_color();
104+
105+
const char* api_key = getenv("BLOCKFROST_API_KEY");
106+
107+
if (api_key == NULL)
108+
{
109+
console_error("BLOCKFROST_API_KEY environment variable is not set.\n");
110+
111+
return EXIT_FAILURE;
112+
}
113+
114+
// 0.- Initialize dependencies
115+
cardano_secure_key_handler_t* key_handler = create_secure_key_handler(SERIALIZED_BIP32_KEY_HANDLER, cardano_utils_safe_strlen(SERIALIZED_BIP32_KEY_HANDLER, 256), get_passphrase);
116+
cardano_provider_t* provider = create_provider(CARDANO_NETWORK_MAGIC_PREPROD, api_key);
117+
cardano_address_t* payment_address = create_address_from_derivation_paths(key_handler, ACCOUNT_DERIVATION_PATH, PAYMENT_CRED_INDEX, STAKE_CRED_INDEX);
118+
cardano_utxo_list_t* utxo_list = get_unspent_utxos(provider, payment_address);
119+
cardano_protocol_parameters_t* protocol_params = get_protocol_parameters(provider);
120+
121+
// 2 hours from now in UNIX time (seconds)
122+
const uint64_t invalid_after = cardano_utils_get_time() + SECONDS_IN_TWO_HOURS;
123+
124+
// 1.- Build transaction
125+
console_info("Building transaction...");
126+
127+
cardano_tx_builder_t* tx_builder = cardano_tx_builder_new(protocol_params, provider);
128+
129+
cardano_tx_builder_set_utxos(tx_builder, utxo_list);
130+
cardano_tx_builder_set_change_address(tx_builder, payment_address);
131+
cardano_tx_builder_set_invalid_after_ex(tx_builder, invalid_after);
132+
cardano_tx_builder_set_donation(tx_builder, LOVELACE_TO_DONATE);
133+
134+
cardano_transaction_t* transaction = NULL;
135+
cardano_error_t result = cardano_tx_builder_build(tx_builder, &transaction);
136+
137+
if (result != CARDANO_SUCCESS)
138+
{
139+
console_error("Failed to build transaction");
140+
console_error("Error [%d]: %s", result, cardano_error_to_string(result));
141+
console_error("%s", cardano_tx_builder_get_last_error(tx_builder));
142+
143+
return result;
144+
}
145+
146+
// 2.- Sign transaction
147+
sign_transaction(key_handler, SIGNER_DERIVATION_PATH, transaction);
148+
149+
// 3.- Submit transaction & confirm
150+
submit_transaction(provider, CONFIRM_TX_TIMEOUT_MS, transaction);
151+
152+
// Cleanup
153+
cardano_provider_unref(&provider);
154+
cardano_address_unref(&payment_address);
155+
cardano_utxo_list_unref(&utxo_list);
156+
cardano_protocol_parameters_unref(&protocol_params);
157+
cardano_tx_builder_unref(&tx_builder);
158+
cardano_transaction_unref(&transaction);
159+
cardano_secure_key_handler_unref(&key_handler);
160+
161+
return EXIT_SUCCESS;
162+
}

lib/include/cardano/transaction_builder/transaction_builder.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,25 @@ CARDANO_EXPORT void cardano_tx_builder_set_collateral_change_address_ex(cardano_
310310
*/
311311
CARDANO_EXPORT void cardano_tx_builder_set_minimum_fee(cardano_tx_builder_t* builder, uint64_t minimum_fee);
312312

313+
/**
314+
* \brief Sets the donation amount for the transaction builder.
315+
*
316+
* This function sets the donation amount. Donations are a Conway-era
317+
* feature that contributes a specific amount to the treasury.
318+
*
319+
* \param[in] builder A pointer to the \ref cardano_tx_builder_t instance where the donation will be set.
320+
* \param[in] donation The donation amount, specified in lovelace.
321+
*
322+
* Usage Example:
323+
* \code{.c}
324+
* cardano_tx_builder_t* tx_builder = ...; // Initialized transaction builder
325+
* uint64_t donation = 1000000; // 1 ADA donation in lovelace
326+
*
327+
* cardano_tx_builder_set_donation(tx_builder, donation);
328+
* \endcode
329+
*/
330+
CARDANO_EXPORT void cardano_tx_builder_set_donation(cardano_tx_builder_t* builder, uint64_t donation);
331+
313332
/**
314333
* \brief Sets the available UTXOs for coin selection in transaction balancing.
315334
*

lib/src/pool_params/pool_metadata.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static const int64_t EMBEDDED_GROUP_SIZE = 2;
4646
typedef struct cardano_pool_metadata_t
4747
{
4848
cardano_object_t base;
49-
char url[65];
49+
char url[129];
5050
cardano_blake2b_hash_t* hash;
5151
} cardano_pool_metadata_t;
5252

@@ -96,7 +96,7 @@ cardano_pool_metadata_new(
9696
return CARDANO_ERROR_POINTER_IS_NULL;
9797
}
9898

99-
if (url_length > 64U)
99+
if (url_length > 128U)
100100
{
101101
return CARDANO_ERROR_INVALID_ARGUMENT;
102102
}
@@ -117,11 +117,11 @@ cardano_pool_metadata_new(
117117
(*pool_metadata)->base.ref_count = 1;
118118
(*pool_metadata)->base.last_error[0] = '\0';
119119

120-
CARDANO_UNUSED(memset((*pool_metadata)->url, 0, 65));
120+
CARDANO_UNUSED(memset((*pool_metadata)->url, 0, 129));
121121

122-
cardano_safe_memcpy((*pool_metadata)->url, 65, url, url_length);
122+
cardano_safe_memcpy((*pool_metadata)->url, 129, url, url_length);
123123

124-
const size_t url_size = cardano_safe_strlen((*pool_metadata)->url, 64);
124+
const size_t url_size = cardano_safe_strlen((*pool_metadata)->url, 128);
125125
(*pool_metadata)->url[url_size] = '\0';
126126

127127
cardano_blake2b_hash_ref(hash);
@@ -148,7 +148,7 @@ cardano_pool_metadata_from_hash_hex(
148148
return CARDANO_ERROR_POINTER_IS_NULL;
149149
}
150150

151-
if (url_size > 64U)
151+
if (url_size > 128U)
152152
{
153153
return CARDANO_ERROR_INVALID_ARGUMENT;
154154
}
@@ -239,7 +239,15 @@ cardano_pool_metadata_from_cbor(cardano_cbor_reader_t* reader, cardano_pool_meta
239239
return new_result;
240240
}
241241

242-
return cardano_cbor_validate_end_array(validator_name, reader);
242+
const cardano_error_t end_array_result = cardano_cbor_validate_end_array(validator_name, reader);
243+
244+
if (end_array_result != CARDANO_SUCCESS)
245+
{
246+
cardano_pool_metadata_unref(pool_metadata);
247+
*pool_metadata = NULL;
248+
}
249+
250+
return end_array_result;
243251
}
244252

245253
cardano_error_t
@@ -267,7 +275,7 @@ cardano_pool_metadata_to_cbor(const cardano_pool_metadata_t* pool_metadata, card
267275
cardano_error_t write_string_result = cardano_cbor_writer_write_textstring(
268276
writer,
269277
pool_metadata->url,
270-
cardano_safe_strlen(pool_metadata->url, 64));
278+
cardano_safe_strlen(pool_metadata->url, 128));
271279

272280
if (write_string_result != CARDANO_SUCCESS)
273281
{
@@ -286,7 +294,7 @@ cardano_pool_metadata_get_url_size(
286294
return 0;
287295
}
288296

289-
return cardano_safe_strlen(pool_metadata->url, 64);
297+
return cardano_safe_strlen(pool_metadata->url, 128);
290298
}
291299

292300
const char*
@@ -317,14 +325,14 @@ cardano_pool_metadata_set_url(
317325
return CARDANO_ERROR_POINTER_IS_NULL;
318326
}
319327

320-
if (url_size > 64U)
328+
if (url_size > 128U)
321329
{
322330
return CARDANO_ERROR_INVALID_ARGUMENT;
323331
}
324332

325-
cardano_safe_memcpy(pool_metadata->url, 65, url, url_size);
333+
cardano_safe_memcpy(pool_metadata->url, 129, url, url_size);
326334

327-
const size_t url_length = cardano_safe_strlen(pool_metadata->url, 64);
335+
const size_t url_length = cardano_safe_strlen(pool_metadata->url, 128);
328336
pool_metadata->url[url_length] = '\0';
329337

330338
return CARDANO_SUCCESS;

lib/src/transaction_builder/balancing/transaction_balancing.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,13 @@ cardano_balance_transaction(
496496

497497
uint64_t fee = cardano_transaction_body_get_fee(body);
498498
uint64_t change_padding = 0U;
499+
uint64_t donation = 0;
500+
501+
const uint64_t* donationPtr = cardano_transaction_body_get_donation(body);
502+
if (donationPtr != NULL)
503+
{
504+
donation = *donationPtr;
505+
}
499506

500507
while (!is_balanced)
501508
{
@@ -529,7 +536,7 @@ cardano_balance_transaction(
529536

530537
result = cardano_value_new(
531538
((int64_t)implicit_coin.withdrawals + (int64_t)implicit_coin.reclaim_deposits) -
532-
((int64_t)implicit_coin.deposits + (int64_t)fee + (int64_t)change_padding),
539+
((int64_t)implicit_coin.deposits + (int64_t)fee + (int64_t)change_padding + (int64_t)donation),
533540
mint,
534541
&implicit_value);
535542

@@ -960,12 +967,14 @@ cardano_is_transaction_balanced(
960967
return result;
961968
}
962969

963-
const uint64_t fee = cardano_transaction_body_get_fee(body);
964-
const int64_t implicit_coin_value = ((int64_t)implicit_coin.withdrawals + (int64_t)implicit_coin.reclaim_deposits) - (int64_t)implicit_coin.deposits;
970+
const uint64_t* donationPtr = cardano_transaction_body_get_donation(body);
971+
const uint64_t donation = (donationPtr != NULL) ? *donationPtr : 0U;
972+
const uint64_t fee = cardano_transaction_body_get_fee(body);
973+
const int64_t implicit_coin_value = ((int64_t)implicit_coin.withdrawals + (int64_t)implicit_coin.reclaim_deposits) - (int64_t)implicit_coin.deposits;
965974

966975
cardano_value_t* implicit_value = NULL;
967976

968-
result = cardano_value_new(implicit_coin_value - (int64_t)fee, mint, &implicit_value);
977+
result = cardano_value_new(implicit_coin_value - ((int64_t)fee + (int64_t)donation), mint, &implicit_value);
969978

970979
if (result != CARDANO_SUCCESS)
971980
{

lib/src/transaction_builder/transaction_builder.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,45 @@ cardano_tx_builder_set_minimum_fee(
10601060
}
10611061
}
10621062

1063+
void
1064+
cardano_tx_builder_set_donation(
1065+
cardano_tx_builder_t* builder,
1066+
const uint64_t donation)
1067+
{
1068+
if ((builder == NULL) || (builder->last_error != CARDANO_SUCCESS))
1069+
{
1070+
return;
1071+
}
1072+
1073+
cardano_transaction_body_t* body = cardano_transaction_get_body(builder->transaction);
1074+
cardano_transaction_body_unref(&body);
1075+
1076+
if (body == NULL)
1077+
{
1078+
cardano_tx_builder_set_last_error(builder, "Transaction body is NULL.");
1079+
builder->last_error = CARDANO_ERROR_POINTER_IS_NULL;
1080+
1081+
return;
1082+
}
1083+
1084+
cardano_error_t result = CARDANO_SUCCESS;
1085+
1086+
if (donation == 0U)
1087+
{
1088+
result = cardano_transaction_body_set_donation(body, NULL);
1089+
}
1090+
else
1091+
{
1092+
result = cardano_transaction_body_set_donation(body, &donation);
1093+
}
1094+
1095+
if (result != CARDANO_SUCCESS)
1096+
{
1097+
cardano_tx_builder_set_last_error(builder, "Failed to set donation.");
1098+
builder->last_error = result;
1099+
}
1100+
}
1101+
10631102
void
10641103
cardano_tx_builder_set_utxos(
10651104
cardano_tx_builder_t* builder,

0 commit comments

Comments
 (0)