Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auction: define action balances #4218

Merged
merged 20 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2065eaa
transaction(auction): add stub `IsAuction` impl for schedule
erwanor Apr 16, 2024
0a9d52b
auction: import `blake2b_simd`
erwanor Apr 16, 2024
c767328
auction: make `AuctionNft` fields public
erwanor Apr 16, 2024
5357f8e
auction: implement `DutchAuctionDescription::id`
erwanor Apr 16, 2024
50df24c
auction: define `DUTCH_AUCTION_DOMAIN_SEP`
erwanor Apr 16, 2024
c6aaa48
transaction(auction): compute `balance_commitment` for schedule DA
erwanor Apr 16, 2024
a4fd3ad
asset(registry): add `auctionnft` to registry
erwanor Apr 16, 2024
62f9694
auction: re-export `AuctionId` and `AuctionNft` in root
erwanor Apr 16, 2024
f3b8ba7
auction(nft): augment `AuctionNft` with denom metadata
erwanor Apr 16, 2024
5a49acc
auction: implement `balance` for schedule DA
erwanor Apr 16, 2024
5ec96f7
penumbra: stage cargo.lock with `blake2b_simd`
erwanor Apr 16, 2024
9535dbf
auction(dutch): implement value balance for end DA action
erwanor Apr 16, 2024
e72d5f3
auction(nft): add `AuctionNft::asset_id` helper
erwanor Apr 16, 2024
165e27d
auction(dutch): value balance for withdraw DA
erwanor Apr 16, 2024
fc2f173
auction(actions): export withdraw DA struct
erwanor Apr 16, 2024
8b1d79d
auction(withdraw): impl `balance_commitment` for withdraw DAs
erwanor Apr 16, 2024
78f55df
transaction: implement `IsAction` for `ActionDutchAuctionWithdraw`
erwanor Apr 16, 2024
6f36bd7
auction: add tables to value balance descriptions
erwanor Apr 16, 2024
97fc73a
auction: make dsep fit in 16 bytes
erwanor Apr 16, 2024
14bf781
spec: add dutch auction actions to spec
erwanor Apr 16, 2024
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions crates/core/asset/src/asset/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,5 +417,13 @@ pub static REGISTRY: Lazy<Registry> = Lazy::new(|| {
},
])
}) as for<'r> fn(&'r str) -> _)
.add_asset(
"^auctionnft_(?P<seq_num>[0-9]+)_(?P<auction_id>paucid1[a-zA-HJ-NP-Z0-9]+)$",
&[ /* no display units - nft, unit 1 */ ],
(|data: &str| {
assert!(!data.is_empty());
denom_metadata::Inner::new(format!("auctionnft_{data}"), vec![])
}) as for<'r> fn(&'r str) -> _,
)
.build()
});
1 change: 1 addition & 0 deletions crates/core/component/auction/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ bech32 = {workspace = true}
bitvec = {workspace = true}
cnidarium = {workspace = true, default-features = false, optional = true}
cnidarium-component = {workspace = true, default-features = false, optional = true}
blake2b_simd = {workspace = true}
decaf377 = {workspace = true, features = ["r1cs"], default-features = true}
decaf377-rdsa = {workspace = true}
futures = {workspace = true, optional = true}
Expand Down
3 changes: 3 additions & 0 deletions crates/core/component/auction/src/auction.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub mod dutch;
pub mod id;
pub mod nft;

pub use id::AuctionId;
pub use nft::AuctionNft;
26 changes: 26 additions & 0 deletions crates/core/component/auction/src/auction/dutch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ use penumbra_num::Amount;
use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType};
use serde::{Deserialize, Serialize};

use crate::auction::AuctionId;

pub mod actions;

pub const DUTCH_AUCTION_DOMAIN_SEP: &[u8] = b"penumbra_DA_nft";

/// A deployed Dutch Auction, containing an immutable description
/// and stateful data about its current state.
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
Expand Down Expand Up @@ -65,6 +69,28 @@ pub struct DutchAuctionDescription {
pub nonce: [u8; 32],
}

impl DutchAuctionDescription {
/// Compute the unique identifier for the auction description.
pub fn id(&self) -> AuctionId {
let mut state = blake2b_simd::Params::default()
.personal(DUTCH_AUCTION_DOMAIN_SEP)
redshiftzero marked this conversation as resolved.
Show resolved Hide resolved
.to_state();

state.update(&self.nonce);
state.update(&self.input.asset_id.to_bytes());
state.update(&self.input.amount.to_le_bytes());
state.update(&self.max_output.to_le_bytes());
state.update(&self.start_height.to_le_bytes());
state.update(&self.end_height.to_le_bytes());
state.update(&self.step_count.to_le_bytes());

let hash = state.finalize();
let mut bytes = [0; 32];
bytes[0..32].copy_from_slice(&hash.as_bytes()[0..32]);
AuctionId(bytes)
}
}

/* Protobuf impls */
impl DomainType for DutchAuctionDescription {
type Proto = pb::DutchAuctionDescription;
Expand Down
28 changes: 27 additions & 1 deletion crates/core/component/auction/src/auction/dutch/actions/end.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use anyhow::anyhow;
use penumbra_asset::{Balance, Value};
use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType};
use serde::{Deserialize, Serialize};

use crate::auction::id::AuctionId;
use crate::auction::{id::AuctionId, AuctionNft};

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(
Expand All @@ -13,6 +14,31 @@ pub struct ActionDutchAuctionEnd {
pub auction_id: AuctionId,
}

impl ActionDutchAuctionEnd {
/// Compute the value balance for this action
///
/// # Diagram
///
/// ┌────────────────────┬──────────────────────┐
/// │ Burn (-) │ Mint (+) │
/// ├────────────────────┼──────────────────────┤
/// │ opened auction nft │ closed auction nft │
/// └────────────────────┴──────────────────────┘
pub fn balance(&self) -> Balance {
let start_auction = Value {
amount: 1u128.into(),
asset_id: AuctionNft::new(self.auction_id, 0u64).asset_id(),
};

let end_auction = Value {
amount: 1u128.into(),
asset_id: AuctionNft::new(self.auction_id, 1u64).asset_id(),
};

Balance::from(end_auction) - Balance::from(start_auction)
}
}

/* Protobuf impls */
impl DomainType for ActionDutchAuctionEnd {
type Proto = pb::ActionDutchAuctionEnd;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
pub mod schedule;
pub use schedule::ActionDutchAuctionSchedule;

pub mod schedule_view;
pub use schedule_view::ActionDutchAuctionScheduleView;

pub mod end;
pub use end::ActionDutchAuctionEnd;

pub mod withdraw;
pub use withdraw::ActionDutchAuctionWithdraw;

pub mod withdraw_view;
pub use withdraw_view::ActionDutchAuctionWithdrawView;
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::auction::dutch::DutchAuctionDescription;
use crate::auction::{dutch::DutchAuctionDescription, nft::AuctionNft};
use anyhow::anyhow;
use penumbra_asset::{Balance, Value};
use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType};
use serde::{Deserialize, Serialize};

Expand All @@ -12,6 +13,30 @@ pub struct ActionDutchAuctionSchedule {
pub description: DutchAuctionDescription,
}

impl ActionDutchAuctionSchedule {
/// Compute the value balance corresponding to this action:
///
/// # Diagram
///
/// ┌────────────────────┬──────────────────────┐
/// │ Burn (-) │ Mint (+) │
/// ├────────────────────┼──────────────────────┤
/// │ input value │ opened auction nft │
/// └────────────────────┴──────────────────────┘
pub fn balance(&self) -> Balance {
let opened_auction_nft = AuctionNft::new(self.description.id(), 0u64);
let opened_auction_nft_value = Value {
asset_id: opened_auction_nft.metadata.id(),
amount: 1u128.into(),
};

let output_nft_balance = Balance::from(opened_auction_nft_value);
let input_balance = Balance::from(self.description.input);

output_nft_balance - input_balance
}
}

/* Protobuf impls */
impl DomainType for ActionDutchAuctionSchedule {
type Proto = pb::ActionDutchAuctionSchedule;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::auction::id::AuctionId;
use crate::auction::{id::AuctionId, AuctionNft};
use anyhow::anyhow;
use penumbra_asset::balance;
use ark_ff::Zero;
use decaf377_rdsa::Fr;
use penumbra_asset::{balance, Balance, Value};
use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType};
use serde::{Deserialize, Serialize};

Expand All @@ -15,6 +17,44 @@ pub struct ActionDutchAuctionWithdraw {
pub reserves_commitment: balance::Commitment,
}

impl ActionDutchAuctionWithdraw {
/// Compute a balance **commitment** for this action.
///
/// # Diagram
///
/// The value balance commitment is built from the balance:
/// ┌────────────────────┬──────────────────────┐
/// │ Burn (-) │ Mint (+) │
/// ├────────────────────┼──────────────────────┤
/// │ auction nft │ auction │
/// │ with seq >= 1 │ value balance │
/// └────────────────────┼──────────────────────┤
/// │withdrawn auction nft │
/// │ with seq+1 │
/// └──────────────────────┘
///
/// More context: [Actions and Value balance][protocol-spec]
/// [protocol-spec]: https://protocol.penumbra.zone/main/transactions.html#actions-and-value-balance
pub fn balance_commitment(&self) -> balance::Commitment {
let prev_auction_nft = Balance::from(Value {
amount: 1u128.into(),
// The sequence number should always be >= 1, because we can
// only withdraw an auction that has ended (i.e. with sequence number `>=1`).
// We use a saturating operation defensively so that we don't underflow.
asset_id: AuctionNft::new(self.auction_id, self.seq.saturating_sub(1)).asset_id(),
})
Copy link
Member Author

@erwanor erwanor Apr 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@redshiftzero My rationale to do this is that we check the binding signature before we run any action validation checks, so even if this MUST be seq >= 1, we can't actually rely on that yet.

.commit(Fr::zero());

let next_auction_nft = Balance::from(Value {
amount: 1u128.into(),
asset_id: AuctionNft::new(self.auction_id, self.seq).asset_id(),
})
.commit(Fr::zero());

self.reserves_commitment + next_auction_nft - prev_auction_nft
}
}

/* Protobuf impls */
impl DomainType for ActionDutchAuctionWithdraw {
type Proto = pb::ActionDutchAuctionWithdraw;
Expand Down
33 changes: 24 additions & 9 deletions crates/core/component/auction/src/auction/nft.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
use crate::auction::id::AuctionId;
use anyhow::{anyhow, Result};
use penumbra_asset::asset::{self};
use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType};

/// An non-fungible token (NFT) tracking the state and ownership of an auction.
#[derive(Debug, Clone)]
pub struct AuctionNft {
/// The unique identifier for the auction this nft resolves to.
id: AuctionId,
pub id: AuctionId,
/// The state of an auction, its specific semantics depend on the
/// type of auction the NFT resolves to.
seq: u64,
pub seq: u64,
/// The metadata corresponding to the nft denom.
pub metadata: asset::Metadata,
}

impl AuctionNft {
pub fn new(id: AuctionId, seq: u64) -> AuctionNft {
let metadata = asset::REGISTRY
.parse_denom(&format!("auctionnft_{seq}_{id}"))
.expect("auction nft denom is valid");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I want to do a second pass on both auction and lp nfts to make their constructor fallible.

AuctionNft { id, seq, metadata }
}

pub fn asset_id(&self) -> asset::Id {
self.metadata.id()
}
}

/* Protobuf impls ;*/
Expand All @@ -30,12 +46,11 @@ impl TryFrom<pb::AuctionNft> for AuctionNft {
type Error = anyhow::Error;

fn try_from(msg: pb::AuctionNft) -> Result<Self, Self::Error> {
Ok(Self {
id: msg
.id
.ok_or_else(|| anyhow!("AuctionNft message is missing an auction id"))?
.try_into()?,
seq: msg.seq,
})
let id: AuctionId = msg
.id
.ok_or_else(|| anyhow!("AuctionNft message is missing an auction id"))?
.try_into()?;
let seq = msg.seq;
Ok(AuctionNft::new(id, seq))
}
}
33 changes: 33 additions & 0 deletions crates/core/transaction/src/is_action.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use ark_ff::Zero;
use decaf377::Fr;
use penumbra_asset::{balance, Value};
use penumbra_auction::auction::dutch::actions::{
ActionDutchAuctionEnd, ActionDutchAuctionSchedule, ActionDutchAuctionWithdraw,
};
use penumbra_community_pool::{CommunityPoolDeposit, CommunityPoolOutput, CommunityPoolSpend};
use penumbra_dex::{
lp::{
Expand Down Expand Up @@ -406,3 +409,33 @@ impl IsAction for SwapClaim {
}
}
}

impl IsAction for ActionDutchAuctionSchedule {
fn balance_commitment(&self) -> balance::Commitment {
self.balance().commit(Fr::zero())
}

fn view_from_perspective(&self, _txp: &TransactionPerspective) -> ActionView {
todo!()
}
}

impl IsAction for ActionDutchAuctionEnd {
fn balance_commitment(&self) -> balance::Commitment {
self.balance().commit(Fr::zero())
}

fn view_from_perspective(&self, _txp: &TransactionPerspective) -> ActionView {
todo!()
}
}

impl IsAction for ActionDutchAuctionWithdraw {
fn balance_commitment(&self) -> balance::Commitment {
self.balance_commitment()
}

fn view_from_perspective(&self, _txp: &TransactionPerspective) -> ActionView {
todo!()
}
}
Loading
Loading