Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e722dd1
Add support for ProtocolVersion::P10.
td202 Nov 18, 2025
01fe162
concordium-base: update submodule
drsk0 Dec 1, 2025
dcb69a2
regenerate proto
Dec 1, 2025
ec9798e
SPO-2: support for sponsored transactions
Nov 17, 2025
b0468d0
replace unknown doctest annotation
Nov 20, 2025
0fce3a9
cosmetics
Nov 20, 2025
a3e057c
add sponsor details to account transaction details
Nov 25, 2025
f29c942
cosmetics
Dec 1, 2025
86b2bfe
update changelog
Dec 1, 2025
3c45dd1
Merge pull request #353 from Concordium/spo_2_support_for_sponsored_tx
drsk0 Dec 1, 2025
58917d8
added sponsored example
drsk0 Dec 2, 2025
7744d40
concordium-base: update submodule
drsk0 Dec 3, 2025
0dc31a6
added sponsored example
drsk0 Dec 3, 2025
2c53824
update top-level comment
drsk0 Dec 3, 2025
15c0903
Update examples/sponsored-plt-transfer.rs
drsk0 Dec 3, 2025
4344e94
Update examples/sponsored-plt-transfer.rs
drsk0 Dec 3, 2025
c69444e
Merge pull request #355 from Concordium/spo_2_sponsored_example
drsk0 Dec 3, 2025
c46b0ea
add sponsor account to affected accounts
drsk0 Dec 3, 2025
42a468a
Update src/types/mod.rs
drsk0 Dec 4, 2025
8ca392c
small fix after github update
Dec 4, 2025
f9b9491
Merge pull request #356 from Concordium/spo_4_tx_logger_sponsored_sup…
drsk0 Dec 4, 2025
196153c
concordium-base: update submodule
drsk0 Dec 9, 2025
00c6bbd
update implied by submodule update
Dec 9, 2025
d306351
clippy fix
Dec 9, 2025
244f283
Merge pull request #358 from Concordium/spo_68_submodule_update
drsk0 Dec 9, 2025
ff00fc1
bump version
Dec 9, 2025
c3407cd
Merge pull request #359 from Concordium/spo_68_merge_p10
drsk0 Dec 10, 2025
f72f139
Update base ref
soerenbf Jan 6, 2026
5f0f5fc
Merge pull request #361 from Concordium/p10-update-base-ref
soerenbf Jan 6, 2026
4dacd75
Merge branch 'main' into p10-merge-main
soerenbf Jan 8, 2026
f322e5a
Merge pull request #363 from Concordium/p10-merge-main
soerenbf Jan 8, 2026
fa7c161
Prepare for 9.0.0 release
soerenbf Jan 9, 2026
04f1d0d
Update base ref to latest `main`
soerenbf Jan 9, 2026
d6f3df0
Update changelog
soerenbf Jan 9, 2026
a43500f
Merge pull request #364 from Concordium/bump-9.0.0
soerenbf Jan 9, 2026
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
24 changes: 14 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
## 8.1.0

- Implemented `web3id::v1` module that contains functionality to support the verification flow of Concordium verifiable presentations V1.
This includes
- creating verification request anchor (VRA)
- verifying presentations
- creating verification audit anchor (VAA)

The main entrypoints in the module are `v1::create_verification_request_and_submit_request_anchor`
and `v1::verify_presentation_and_submit_audit_anchor`.
## 9.0.0

- Support for `ProtocolVersion::P10`.
- The flag `serde_deprecated` now guards `serde::Serialize` and `serde::Deserialize` implemetations on the following types. The implementations will eventually be removed.
- `protocol_level_tokens::AccountToken`
- `protocol_level_tokens::TokenAccountState`
Expand Down Expand Up @@ -56,6 +48,18 @@
- `types::smart_contracts::InstanceInfo`
- `types::smart_contracts::ContractContext`
- `types::smart_contracts::InvokeContractResult`
- Support for sponsored transactions.

## 8.1.0

- Implemented `web3id::v1` module that contains functionality to support the verification flow of Concordium verifiable presentations V1.
This includes
- creating verification request anchor (VRA)
- verifying presentations
- creating verification audit anchor (VAA)

The main entrypoints in the module are `v1::create_verification_request_and_submit_request_anchor`
and `v1::verify_presentation_and_submit_audit_anchor`.

## 8.0.0

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "concordium-rust-sdk"
version = "8.1.0"
version = "9.0.0"
authors = ["Concordium <[email protected]>"]
edition = "2021"
rust-version = "1.85"
Expand Down Expand Up @@ -36,7 +36,7 @@ num-traits = "0.2"
http = "1.2.0"
tokio-stream = "0.1"

concordium_base = { version = "9.0.0", path = "./concordium-base/rust-src/concordium_base/", features = ["encryption"] }
concordium_base = { version = "10.0.0", path = "./concordium-base/rust-src/concordium_base/", features = ["encryption"] }
concordium-smart-contract-engine = { version = "6.0", path = "./concordium-base/smart-contracts/wasm-chain-integration/", default-features = false, features = ["async"]}
aes-gcm = { version = "0.10", features = ["std"] }
tracing = "0.1"
Expand Down
2 changes: 1 addition & 1 deletion concordium-base
Submodule concordium-base updated 50 files
+1 −0 concordium-base.cabal
+1 −1 concordium-grpc-api
+3 −0 haskell-bins/genesis/Genesis.hs
+3 −0 haskell-src/Concordium/Constants.hs
+1 −0 haskell-src/Concordium/Cost.hs
+62 −21 haskell-src/Concordium/GRPC2.hs
+19 −0 haskell-src/Concordium/Genesis/Data.hs
+151 −0 haskell-src/Concordium/Genesis/Data/P10.hs
+1 −1 haskell-src/Concordium/Types/Accounts.hs
+1 −1 haskell-src/Concordium/Types/DummyData.hs
+40 −16 haskell-src/Concordium/Types/Execution.hs
+6 −0 haskell-src/Concordium/Types/Migration.hs
+2 −0 haskell-src/Concordium/Types/Parameters.hs
+66 −0 haskell-src/Concordium/Types/ProtocolVersion.hs
+45 −27 haskell-src/Concordium/Types/Queries.hs
+1 −0 haskell-src/Concordium/Types/SeedState.hs
+392 −67 haskell-src/Concordium/Types/Transactions.hs
+1 −0 haskell-src/Concordium/Wasm.hs
+47 −17 haskell-tests/Generators.hs
+13 −1 haskell-tests/Types/PayloadSerializationSpec.hs
+92 −6 haskell-tests/Types/TransactionSerializationSpec.hs
+1 −0 haskell-tests/Types/TransactionSummarySpec.hs
+2 −0 haskell-tests/Types/UpdatesSpec.hs
+1 −1 identity-provider-service/Cargo.lock
+1 −1 idiss/Cargo.lock
+1 −1 mobile_wallet/Cargo.lock
+4 −4 mobile_wallet/src/lib.rs
+1 −1 rust-bins/Cargo.lock
+8 −8 rust-bins/src/bin/client.rs
+2 −2 rust-bins/src/bin/generate_testdata.rs
+6 −6 rust-bins/src/bin/user_cli.rs
+1 −1 rust-src/Cargo.lock
+7 −0 rust-src/concordium_base/CHANGELOG.md
+1 −1 rust-src/concordium_base/Cargo.toml
+1 −1 rust-src/concordium_base/benches/compute_message.rs
+10 −4 rust-src/concordium_base/benches/verify_cdi.rs
+6 −0 rust-src/concordium_base/src/base.rs
+4 −0 rust-src/concordium_base/src/common/serialize.rs
+87 −19 rust-src/concordium_base/src/common/types.rs
+8 −3 rust-src/concordium_base/src/id/account_holder.rs
+4 −4 rust-src/concordium_base/src/id/constants.rs
+1 −1 rust-src/concordium_base/src/id/ffi.rs
+4 −1 rust-src/concordium_base/src/id/identity_attributes_credentials.rs
+86 −13 rust-src/concordium_base/src/id/secret_sharing.rs
+4 −2 rust-src/concordium_base/src/id/test.rs
+456 −6 rust-src/concordium_base/src/transactions.rs
+1 −1 rust-src/concordium_base/src/web3id/did.rs
+1 −1 rust-src/concordium_base/src/web3id/v1.rs
+1 −1 rust-src/wallet_library/src/credential.rs
+2 −2 rust-src/wallet_library/src/identity.rs
122 changes: 122 additions & 0 deletions examples/sponsored-plt-transfer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//! Example that shows how to create a sponsored PLT token transfer.
use anyhow::Context;
use clap::AppSettings;
use concordium_base::{
contracts_common::AccountAddress,
protocol_level_tokens::{operations, ConversionRule, TokenAmount, TokenId},
};
use concordium_rust_sdk::{
common::types::TransactionTime,
types::{transactions::BlockItem, WalletAccount},
v2::{
BlockIdentifier, {self},
},
};
use rust_decimal::Decimal;
use std::{path::PathBuf, str::FromStr};
use structopt::*;

#[derive(StructOpt)]
struct App {
#[structopt(
long = "node",
help = "V2 GRPC interface of the node.",
default_value = "http://localhost:20000"
)]
endpoint: v2::Endpoint,
#[structopt(long = "sender", help = "Path to the sender account key file.")]
sender_account: PathBuf,
#[structopt(long = "sponsor", help = "Path to the sponsor account key file.")]
sponsor_account: PathBuf,
#[structopt(long = "receiver", help = "Receiver address.")]
receiver: String,
#[structopt(long = "token", help = "Token id of token.")]
token_id: String,
#[structopt(long = "amount", help = "Amount to send.", default_value = "100.0")]
amount: Decimal,
}

#[tokio::main(flavor = "multi_thread")]
async fn main() -> anyhow::Result<()> {
let app = {
let app = App::clap().global_setting(AppSettings::ColoredHelp);
let matches = app.get_matches();
App::from_clap(&matches)
};
let mut client = v2::Client::new(app.endpoint).await?;

// Token id of the PLT token to transfer
let token_id = TokenId::try_from(app.token_id.clone())?;

// Token info, we need the number of decimals in the token amount representation
let token_info = client
.get_token_info(token_id.clone(), BlockIdentifier::LastFinal)
.await?
.response;

// Amount of tokens to send. The number of decimals in the TokenAmount
// must be the same as the number of decimals in the TokenInfo
let token_amount = TokenAmount::try_from_rust_decimal(
app.amount,
token_info.token_state.decimals,
ConversionRule::AllowRounding,
)?;
println!("Token amount: {}", token_amount,);

// Receiver of the tokens
let receiver_address = AccountAddress::from_str(&app.receiver)?;

// Load account keys and address for sender and sponsor from a file
let sender_keys: WalletAccount = WalletAccount::from_json_file(app.sender_account)
.context("Could not read the sender account keys file.")?;
let sponsor_keys: WalletAccount = WalletAccount::from_json_file(app.sponsor_account)
.context("Could not read the sponsor account keys file.")?;

// Get the initial nonce at the last finalized block.
let nonce = client
.get_next_account_sequence_number(&sender_keys.address)
.await?
.nonce;

// Set expiry to now + 5min
let expiry: TransactionTime =
TransactionTime::from_seconds((chrono::Utc::now().timestamp() + 300) as u64);

// Create transfer tokens transaction
let operation = operations::transfer_tokens(receiver_address, token_amount);

// Compose operation to transaction
let txn = concordium_base::transactions::construct::token_update_operations(
1,
sender_keys.address,
nonce,
expiry,
token_id,
[operation].into_iter().collect(),
)?
// Extend the transaction and add a sponsor.
.extend()
.add_sponsor(sponsor_keys.address, 1)
.expect("Can add sponsor account")
// Sender signs the transaction.
.sign(&sender_keys)
// Sponsor signs the now sponsored transaction.
.sponsor(&sponsor_keys)
.expect("Can sponsor the transaction")
.finalize()
.expect("Transaction is well-formed");

let item = BlockItem::AccountTransactionV1(txn);

// Submit the transaction to the chain
let transaction_hash = client.send_block_item(&item).await?;
println!(
"Transaction {} submitted (nonce = {}).",
transaction_hash, nonce,
);
let (bh, bs) = client.wait_until_finalized(&transaction_hash).await?;
println!("Transaction finalized in block {}.", bh);
println!("The outcome is {:#?}", bs);

Ok(())
}
8 changes: 4 additions & 4 deletions src/lib.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ It makes potentially extended information explicit in the types and allows each
Several types and fields in the SDK are now wrapped in [`Upward`] and the wrapper provides several methods to ease the migration depending on the desired behavior of the application.
For some situations unknown information should cause an error, where in other situations it is safe to ignore, and maybe logging warnings to be handled in a future iteration of the application.

```rust,no_compile
```rust,ignore
if let Upward::Known(details) = block_item_summary.details {
// Data is familiar so we handle details as usual.
} else {
Expand All @@ -47,13 +47,13 @@ if let Upward::Known(details) = block_item_summary.details {

To produce an error in the case of unknown data use [`known_or_err`], converting [`Upward<A>`] into [`Result<A, UnknownDataError>`](v2::upward::UnknownDataError).

```rust,no_compile
```rust,ignore
let details = block_item_summary.details.known_or_err()?;
```

Alternatively [`known_or`] or similarly named variants can be used for directly mapping the unknown data case to an error.

```rust,no_compile
```rust,ignore
let details = block_item_summary.details.known_or(MyError::UnknownData)?;
```

Expand Down Expand Up @@ -81,4 +81,4 @@ The `ChainParameters::micro_ccd_per_energy()` and `ChainParameters::ccd_cost()`
Instead, use [`energy_rate()`](types::chain_parameters::ChainParameters::energy_rate) to obtain an [`EnergyRate`](types::chain_parameters::EnergyRate), which encapsulates the [`micro_ccd_per_energy`](types::chain_parameters::EnergyRate::micro_ccd_per_energy) exchange rate.
`EnergyRate` also provides [`ccd_cost()`](types::chain_parameters::EnergyRate::ccd_cost), which should be used in place of the former `ChainParameters::ccd_cost()`.

Finally, the `ChainParameters::foundation_account()` getter function was removed, and should be replaced by directly accessing [`ChainParameters::foundation_account`](types::chain_parameters::ChainParameters::foundation_account).
Finally, the `ChainParameters::foundation_account()` getter function was removed, and should be replaced by directly accessing [`ChainParameters::foundation_account`](types::chain_parameters::ChainParameters::foundation_account).
4 changes: 2 additions & 2 deletions src/protocol_level_tokens/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ impl TryFrom<generated::plt::TokenModuleRef> for TokenModuleRef {
}
}

impl From<generated::plt::CBor> for RawCbor {
fn from(wrapper: generated::plt::CBor) -> Self {
impl From<generated::plt::Cbor> for RawCbor {
fn from(wrapper: generated::plt::Cbor) -> Self {
wrapper.value.into()
}
}
Expand Down
18 changes: 17 additions & 1 deletion src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1914,7 +1914,7 @@ impl BlockItemSummaryDetails {
let Upward::Known(effects) = &at.effects else {
return Upward::Unknown(());
};
match effects {
let mut affected_accounts = match effects {
AccountTransactionEffects::None { .. } => vec![at.sender],
AccountTransactionEffects::ModuleDeployed { .. } => vec![at.sender],
AccountTransactionEffects::ContractInitialized { .. } => vec![at.sender],
Expand Down Expand Up @@ -1992,7 +1992,12 @@ impl BlockItemSummaryDetails {
add_token_event_addresses(&mut addresses, events);
addresses.into_iter().collect()
}
};
// Add the optional sponsor account to the affected accounts.
if let Some(sponsor) = at.sponsor.as_ref() {
affected_accounts.push(sponsor.sponsor);
}
affected_accounts
}
BlockItemSummaryDetails::AccountCreation(_) => Vec::new(),
BlockItemSummaryDetails::Update(_) => Vec::new(),
Expand All @@ -2006,6 +2011,15 @@ impl BlockItemSummaryDetails {
}
}

#[derive(Debug, Clone)]
/// Details about the sponsor of a transaction.
pub struct SponsorDetails {
/// The cost of the transaction. Paid by the sponsor.
pub sponsor: AccountAddress,
/// The sponsor of the transaction.
pub cost: Amount,
}

#[derive(Debug, Clone)]
/// Details of an account transaction. This always has a sender and is paid for,
/// and it might have some other effects on the state of the chain.
Expand All @@ -2015,6 +2029,8 @@ pub struct AccountTransactionDetails {
pub cost: Amount,
/// Sender of the transaction.
pub sender: AccountAddress,
/// Optional sponsor of the transaction
pub sponsor: Option<SponsorDetails>,
/// Effects of the account transaction, if any.
pub effects: Upward<AccountTransactionEffects>,
}
Expand Down
1 change: 1 addition & 0 deletions src/types/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl ProtocolVersionInt {
ProtocolVersion::P7 => Self(7),
ProtocolVersion::P8 => Self(8),
ProtocolVersion::P9 => Self(9),
ProtocolVersion::P10 => Self(10),
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions src/types/summary_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::{
};

use crate::{
types::Address,
types::{Address, SponsorDetails},
v2::upward::{UnknownDataError, Upward},
};
use concordium_base::{
Expand All @@ -42,6 +42,8 @@ pub(crate) struct BlockItemSummary {
/// Sender, if available. The sender is always available for account
/// transactions.
sender: Option<AccountAddress>,
/// Optional sponsor of the transaction.
sponsor: Option<AccountAddress>,
/// Hash of the transaction.
hash: hashes::TransactionHash,
/// The amount of CCD the transaction was charged to the sender.
Expand Down Expand Up @@ -510,6 +512,7 @@ impl TryFrom<super::BlockItemSummary> for BlockItemSummary {
super::AccountTransactionDetails {
cost,
sender,
sponsor,
effects,
},
) => {
Expand Down Expand Up @@ -905,6 +908,7 @@ impl TryFrom<super::BlockItemSummary> for BlockItemSummary {
};
BlockItemSummary {
sender: Some(sender),
sponsor: sponsor.map(|s| s.sponsor),
hash: bi.hash,
cost,
energy_cost: bi.energy_cost,
Expand All @@ -919,6 +923,7 @@ impl TryFrom<super::BlockItemSummary> for BlockItemSummary {
reg_id,
}) => BlockItemSummary {
sender: None,
sponsor: None,
hash: bi.hash,
cost: Amount::zero(),
energy_cost: bi.energy_cost,
Expand All @@ -941,6 +946,7 @@ impl TryFrom<super::BlockItemSummary> for BlockItemSummary {
let payload = payload.known_or_err()?;
BlockItemSummary {
sender: None,
sponsor: None,
hash: bi.hash,
cost: Amount::zero(),
energy_cost: bi.energy_cost,
Expand All @@ -967,6 +973,7 @@ impl TryFrom<super::BlockItemSummary> for BlockItemSummary {

BlockItemSummary {
sender: None,
sponsor: None,
hash: bi.hash,
cost: Amount::zero(),
energy_cost: bi.energy_cost,
Expand Down Expand Up @@ -1012,12 +1019,14 @@ fn convert_account_transaction(
ty: Option<TransactionType>,
cost: Amount,
sender: AccountAddress,
sponsor: Option<AccountAddress>,
value: BlockItemResult,
) -> Result<super::AccountTransactionDetails, ConversionError> {
let mk_none = |reject_reason| {
Ok(super::AccountTransactionDetails {
cost,
sender,
sponsor: sponsor.map(|s| SponsorDetails { sponsor: s, cost }),
effects: Upward::Known(super::AccountTransactionEffects::None {
transaction_type: ty,
reject_reason: Upward::Known(reject_reason),
Expand All @@ -1029,6 +1038,7 @@ fn convert_account_transaction(
Ok(super::AccountTransactionDetails {
cost,
sender,
sponsor: sponsor.map(|s| SponsorDetails { sponsor: s, cost }),
effects: Upward::Known(effects),
})
};
Expand Down Expand Up @@ -1509,12 +1519,14 @@ impl TryFrom<BlockItemSummary> for super::BlockItemSummary {
let index = value.index;
let energy_cost = value.energy_cost;
let hash = value.hash;
let sponsor = value.sponsor;
let sender = value
.sender
.ok_or(ConversionError::InvalidTransactionResult(
"Expect `BlockItemType::Account` to have a sender".to_string(),
))?;
let details = convert_account_transaction(ty, value.cost, sender, value.result)?;
let details =
convert_account_transaction(ty, value.cost, sender, sponsor, value.result)?;
Ok(super::BlockItemSummary {
index,
energy_cost,
Expand Down
Loading