updated ecash-contract parameters and generated schema

This commit is contained in:
Jędrzej Stuczyński
2024-07-23 18:20:29 +01:00
parent 5e97b1f79a
commit f4fafbfea5
35 changed files with 1455 additions and 216 deletions
@@ -12,8 +12,8 @@ use nym_crypto::asymmetric::identity;
use nym_ecash_time::{ecash_default_expiration_date, Date};
use nym_validator_client::coconut::all_ecash_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
use nym_validator_client::nyxd::contract_traits::EcashSigningClient;
use nym_validator_client::nyxd::contract_traits::{DkgQueryClient, EcashQueryClient};
use nym_validator_client::nyxd::cosmwasm_client::ToSingletonContractData;
use nym_validator_client::EcashApiClient;
use rand::rngs::OsRng;
@@ -24,14 +24,20 @@ pub async fn make_deposit<C>(
expiration: Option<Date>,
) -> Result<IssuanceTicketBook, BandwidthControllerError>
where
C: EcashSigningClient + Sync,
C: EcashSigningClient + EcashQueryClient + Sync,
{
let mut rng = OsRng;
let signing_key = identity::PrivateKey::new(&mut rng);
let expiration = expiration.unwrap_or_else(ecash_default_expiration_date);
let deposit_amount = client.get_required_deposit_amount().await?;
info!("we'll need to deposit {deposit_amount} to obtain the ticketbook");
let result = client
.make_ticketbook_deposit(signing_key.public_key().to_base58_string(), None)
.make_ticketbook_deposit(
signing_key.public_key().to_base58_string(),
deposit_amount.into(),
None,
)
.await?;
let deposit_id = result.parse_singleton_u32_contract_data()?;
@@ -7,7 +7,6 @@ use crate::nyxd::error::NyxdError;
use crate::nyxd::{Coin, Fee, SigningCosmWasmClient};
use crate::signing::signer::OfflineSigner;
use async_trait::async_trait;
use nym_ecash_contract_common::events::TICKET_BOOK_VALUE;
use nym_ecash_contract_common::msg::ExecuteMsg as EcashExecuteMsg;
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -24,13 +23,13 @@ pub trait EcashSigningClient {
async fn make_ticketbook_deposit(
&self,
public_key: String,
deposit_amount: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = EcashExecuteMsg::DepositTicketBookFunds {
identity_key: public_key,
};
let amount = Coin::new(TICKET_BOOK_VALUE, "unym");
self.execute_ecash_contract(fee, req, "Ecash::Deposit".to_string(), vec![amount])
self.execute_ecash_contract(fee, req, "Ecash::Deposit".to_string(), vec![deposit_amount])
.await
}
@@ -48,6 +47,28 @@ pub trait EcashSigningClient {
.await
}
async fn update_admin(
&self,
admin: String,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = EcashExecuteMsg::UpdateAdmin { admin };
self.execute_ecash_contract(fee, req, "Ecash::UpdateAdmin".to_string(), vec![])
.await
}
async fn update_deposit_value(
&self,
new_deposit: Coin,
fee: Option<Fee>,
) -> Result<ExecuteResult, NyxdError> {
let req = EcashExecuteMsg::UpdateDepositValue {
new_deposit: new_deposit.into(),
};
self.execute_ecash_contract(fee, req, "Ecash::UpdateDepositValue".to_string(), vec![])
.await
}
async fn propose_for_blacklist(
&self,
public_key: String,
@@ -95,7 +116,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
use crate::nyxd::contract_traits::tests::{mock_coin, IgnoreValue};
use nym_ecash_contract_common::msg::ExecuteMsg;
// it's enough that this compiles and clippy is happy about it
@@ -106,7 +127,7 @@ mod tests {
) {
match msg {
EcashExecuteMsg::DepositTicketBookFunds { identity_key } => client
.make_ticketbook_deposit(identity_key.to_string(), None)
.make_ticketbook_deposit(identity_key.to_string(), mock_coin(), None)
.ignore(),
EcashExecuteMsg::AddToBlacklist { public_key: _ } => unimplemented!(), //no add to blacklist method on client
EcashExecuteMsg::ProposeToBlacklist { public_key } => {
@@ -119,6 +140,10 @@ mod tests {
.request_ticket_redemption(commitment_bs58, number_of_tickets, None)
.ignore(),
ExecuteMsg::RedeemTickets { .. } => unimplemented!(), // no redeem tickets method for the client
ExecuteMsg::UpdateAdmin { admin } => client.update_admin(admin, None).ignore(),
ExecuteMsg::UpdateDepositValue { new_deposit } => client
.update_deposit_value(new_deposit.into(), None)
.ignore(),
};
}
}
@@ -4,6 +4,7 @@
use std::str::FromStr;
use clap::Parser;
use cosmwasm_std::Coin;
use log::{debug, info};
use nym_ecash_contract_common::msg::InstantiateMsg;
@@ -20,8 +21,8 @@ pub struct Args {
#[clap(long)]
pub holding_account: AccountId,
#[clap(long)]
pub mix_denom: Option<String>,
#[clap(long, default_value = "75000000unym")]
pub deposit_amount: Coin,
}
pub async fn generate(args: Args) {
@@ -43,15 +44,11 @@ pub async fn generate(args: Args) {
.expect("Failed converting multisig address to AccountId")
});
let mix_denom = args.mix_denom.unwrap_or_else(|| {
std::env::var(nym_network_defaults::var_names::MIX_DENOM).expect("Mix denom has to be set")
});
let instantiate_msg = InstantiateMsg {
holding_account: args.holding_account.to_string(),
group_addr: group_addr.to_string(),
multisig_addr: multisig_addr.to_string(),
mix_denom,
deposit_amount: args.deposit_amount,
};
debug!("instantiate_msg: {:?}", instantiate_msg);
@@ -4,9 +4,6 @@
// event types
pub const DEPOSITED_FUNDS_EVENT_TYPE: &str = "deposited-funds";
// a 'wasm-' prefix is added to all cosmwasm events
pub const COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE: &str = "wasm-deposited-funds";
// attributes that are used in multiple places
pub const DEPOSIT_VALUE: &str = "deposit-value";
pub const DEPOSIT_INFO: &str = "deposit-info";
@@ -0,0 +1,12 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin;
#[cw_serde]
pub struct PoolCounters {
pub total_deposited: Coin,
pub total_redeemed_gateways: Coin,
pub total_redeemed_holding: Coin,
}
@@ -15,7 +15,7 @@ pub enum EcashContractError {
InvalidDeposit(#[from] PaymentError),
#[error("received wrong amount for deposit. got: {received}. required: {amount}")]
WrongAmount { received: u128, amount: u128 },
WrongAmount { received: Coin, amount: Coin },
#[error("There aren't enough funds in the contract")]
NotEnoughFunds,
@@ -57,12 +57,12 @@ pub enum EcashContractError {
#[error("the provided ed25519 identity was malformed")]
MalformedEd25519Identity,
#[error("the required deposit amount has changed since the contract was created! This was not expected! It used to be {at_init} but it's {current} now! Please let the developers know ASAP!")]
DepositAmountChanged { at_init: Coin, current: Coin },
#[error("the e-cash ticket value has changed since the contract was created! This was not expected! It used to be {at_init} but it's {current} now! Please let the developers know ASAP!")]
TicketValueChanged { at_init: Coin, current: Coin },
#[error("the ticket book size has changed since the contract was created! This was not expected! It used to be {at_init} but it's {current} now! Please let the developers know ASAP!")]
TicketBookSizeChanged { at_init: u64, current: u64 },
#[error("the provided tickets redemption commitment is malformed")]
MalformedRedemptionCommitment,
#[error("the account blacklisting hasn't been fully implemented yet")]
UnimplementedBlacklisting,
}
@@ -4,15 +4,6 @@
// event types
pub const DEPOSITED_FUNDS_EVENT_TYPE: &str = "deposited-funds";
// a 'wasm-' prefix is added to all cosmwasm events
pub const COSMWASM_DEPOSITED_FUNDS_EVENT_TYPE: &str = "wasm-deposited-funds";
pub const DEPOSIT_ID: &str = "deposit-id";
pub const TICKET_BOOK_VALUE: u128 = 50_000_000;
// pub const TICKET_VALUE: u128 = 50_000;
pub const WASM_EVENT_NAME: &str = "wasm";
pub const PROPOSAL_ID_ATTRIBUTE_NAME: &str = "proposal_id";
pub const BLACKLIST_PROPOSAL_REPLY_ID: u64 = 7759;
pub const REDEMPTION_PROPOSAL_REPLY_ID: u64 = 2137;
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
pub mod blacklist;
pub mod counters;
pub mod deposit;
pub mod error;
pub mod event_attributes;
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Coin;
#[cfg(feature = "schema")]
use crate::blacklist::{BlacklistedAccountResponse, PagedBlacklistedAccountResponse};
@@ -9,15 +10,13 @@ use crate::blacklist::{BlacklistedAccountResponse, PagedBlacklistedAccountRespon
use crate::deposit::{DepositResponse, PagedDepositsResponse};
#[cfg(feature = "schema")]
use cosmwasm_schema::QueryResponses;
#[cfg(feature = "schema")]
use cosmwasm_std::Coin;
#[cw_serde]
pub struct InstantiateMsg {
pub holding_account: String,
pub multisig_addr: String,
pub group_addr: String,
pub mix_denom: String,
pub deposit_amount: Coin,
}
#[cw_serde]
@@ -38,10 +37,16 @@ pub enum ExecuteMsg {
n: u16,
gw: String,
},
// SpendCredential {
// serial_number: String,
// gateway_cosmos_address: String,
// },
UpdateAdmin {
admin: String,
},
UpdateDepositValue {
new_deposit: Coin,
},
// TODO: properly implement
ProposeToBlacklist {
public_key: String,
},
@@ -74,3 +79,6 @@ pub enum QueryMsg {
start_after: Option<u32>,
},
}
#[cw_serde]
pub struct MigrateMsg {}
+2 -2
View File
@@ -10,7 +10,7 @@ use nym_credential_storage::storage::Storage;
use nym_ecash_time::ecash_default_expiration_date;
use nym_validator_client::coconut::all_ecash_api_clients;
use nym_validator_client::nyxd::contract_traits::{
dkg_query_client::EpochState, DkgQueryClient, EcashSigningClient,
dkg_query_client::EpochState, DkgQueryClient, EcashQueryClient, EcashSigningClient,
};
use std::path::PathBuf;
use std::time::Duration;
@@ -18,7 +18,7 @@ use time::OffsetDateTime;
pub async fn issue_credential<C, S>(client: &C, storage: &S, client_id: &[u8]) -> Result<()>
where
C: DkgQueryClient + EcashSigningClient + Send + Sync,
C: DkgQueryClient + EcashSigningClient + EcashQueryClient + Send + Sync,
S: Storage,
<S as Storage>::StorageError: Send + Sync + 'static,
{
+6
View File
@@ -1233,6 +1233,7 @@ dependencies = [
"nym-crypto",
"nym-ecash-contract-common",
"nym-multisig-contract-common",
"nym-network-defaults",
"rand_chacha",
"schemars",
"semver",
@@ -1250,6 +1251,7 @@ dependencies = [
"cosmwasm-std",
"cw-controllers",
"cw-utils",
"cw2",
"nym-multisig-contract-common",
"thiserror",
]
@@ -1320,6 +1322,10 @@ dependencies = [
"thiserror",
]
[[package]]
name = "nym-network-defaults"
version = "0.1.0"
[[package]]
name = "nym-pemstore"
version = "0.3.0"
+4 -1
View File
@@ -1,4 +1,4 @@
schema: coconut-bandwidth-schema coconut-dkg-schema mixnet-schema vesting-schema multisig-schema group-schema
schema: coconut-bandwidth-schema coconut-dkg-schema mixnet-schema vesting-schema multisig-schema group-schema ecash-schema
coconut-bandwidth-schema:
$(MAKE) -C coconut-bandwidth generate-schema
@@ -12,6 +12,9 @@ mixnet-schema:
vesting-schema:
$(MAKE) -C vesting generate-schema
ecash-schema:
$(MAKE) -C ecash generate-schema
multisig-schema:
$(MAKE) -C multisig/cw3-flex-multisig generate-schema
+4
View File
@@ -0,0 +1,4 @@
[alias]
wasm = "build --release --target wasm32-unknown-unknown"
unit-test = "test --lib"
schema = "run --bin schema --features=schema-gen"
+14 -3
View File
@@ -1,10 +1,18 @@
[package]
name = "nym-ecash"
version = "0.1.0"
edition = "2021"
edition = { workspace = true }
authors = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
[[bin]]
name = "schema"
required-features = ["schema-gen"]
[lib]
crate-type = ["cdylib"]
name = "ecash_contract"
crate-type = ["cdylib", "rlib"]
[dependencies]
bs58.workspace = true
@@ -26,9 +34,12 @@ semver = { workspace = true, default-features = false }
nym-ecash-contract-common = { path = "../../common/cosmwasm-smart-contracts/ecash-contract" }
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" }
nym-multisig-contract-common = { path = "../../common/cosmwasm-smart-contracts/multisig-contract" }
nym-network-defaults = { path = "../../common/network-defaults", default-features = false }
[dev-dependencies]
sylvia = { workspace = true, features = ["mt"] }
nym-crypto = { path = "../../common/crypto", features = ["rand", "asymmetric"] }
rand_chacha = "0.3"
[features]
schema-gen = ["nym-ecash-contract-common/schema"]
+5
View File
@@ -0,0 +1,5 @@
wasm:
RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
generate-schema:
cargo schema
+585
View File
@@ -0,0 +1,585 @@
{
"contract_name": "nym-ecash",
"contract_version": "0.1.0",
"idl_version": "1.0.0",
"instantiate": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InstantiateMsg",
"type": "object",
"required": [
"group_addr",
"holding_account",
"mix_denom",
"multisig_addr"
],
"properties": {
"group_addr": {
"type": "string"
},
"holding_account": {
"type": "string"
},
"mix_denom": {
"type": "string"
},
"multisig_addr": {
"type": "string"
}
},
"additionalProperties": false
},
"execute": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExecuteMsg",
"oneOf": [
{
"description": "Used by clients to request ticket books from the signers",
"type": "object",
"required": [
"deposit_ticket_book_funds"
],
"properties": {
"deposit_ticket_book_funds": {
"type": "object",
"required": [
"identity_key"
],
"properties": {
"identity_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "Used by gateways to batch redeem tokens from the spent tickets",
"type": "object",
"required": [
"request_redemption"
],
"properties": {
"request_redemption": {
"type": "object",
"required": [
"commitment_bs58",
"number_of_tickets"
],
"properties": {
"commitment_bs58": {
"type": "string"
},
"number_of_tickets": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "The actual message that gets executed, after multisig votes, that transfers the ticket tokens into gateway's (and the holding) account",
"type": "object",
"required": [
"redeem_tickets"
],
"properties": {
"redeem_tickets": {
"type": "object",
"required": [
"gw",
"n"
],
"properties": {
"gw": {
"type": "string"
},
"n": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"update_admin"
],
"properties": {
"update_admin": {
"type": "object",
"required": [
"admin"
],
"properties": {
"admin": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"update_deposit_value"
],
"properties": {
"update_deposit_value": {
"type": "object",
"required": [
"new_deposit"
],
"properties": {
"new_deposit": {
"$ref": "#/definitions/Coin"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"propose_to_blacklist"
],
"properties": {
"propose_to_blacklist": {
"type": "object",
"required": [
"public_key"
],
"properties": {
"public_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"add_to_blacklist"
],
"properties": {
"add_to_blacklist": {
"type": "object",
"required": [
"public_key"
],
"properties": {
"public_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"Coin": {
"type": "object",
"required": [
"amount",
"denom"
],
"properties": {
"amount": {
"$ref": "#/definitions/Uint128"
},
"denom": {
"type": "string"
}
}
},
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
}
}
},
"query": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "QueryMsg",
"oneOf": [
{
"type": "object",
"required": [
"get_blacklisted_account"
],
"properties": {
"get_blacklisted_account": {
"type": "object",
"required": [
"public_key"
],
"properties": {
"public_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_blacklist_paged"
],
"properties": {
"get_blacklist_paged": {
"type": "object",
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_required_deposit_amount"
],
"properties": {
"get_required_deposit_amount": {
"type": "object",
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_deposit"
],
"properties": {
"get_deposit": {
"type": "object",
"required": [
"deposit_id"
],
"properties": {
"deposit_id": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_deposits_paged"
],
"properties": {
"get_deposits_paged": {
"type": "object",
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
]
},
"migrate": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"additionalProperties": false
},
"sudo": null,
"responses": {
"get_blacklist_paged": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PagedBlacklistedAccountResponse",
"type": "object",
"required": [
"accounts",
"per_page"
],
"properties": {
"accounts": {
"type": "array",
"items": {
"$ref": "#/definitions/BlacklistedAccount"
}
},
"per_page": {
"type": "integer",
"format": "uint",
"minimum": 0.0
},
"start_next_after": {
"description": "Field indicating paging information for the following queries if the caller wishes to get further entries.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false,
"definitions": {
"BlacklistedAccount": {
"type": "object",
"required": [
"info",
"public_key"
],
"properties": {
"info": {
"$ref": "#/definitions/Blacklisting"
},
"public_key": {
"type": "string"
}
},
"additionalProperties": false
},
"Blacklisting": {
"type": "object",
"required": [
"proposal_id"
],
"properties": {
"finalized_at_height": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0.0
},
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
},
"get_blacklisted_account": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "BlacklistedAccountResponse",
"type": "object",
"properties": {
"account": {
"anyOf": [
{
"$ref": "#/definitions/Blacklisting"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"definitions": {
"Blacklisting": {
"type": "object",
"required": [
"proposal_id"
],
"properties": {
"finalized_at_height": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0.0
},
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
},
"get_deposit": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DepositResponse",
"type": "object",
"required": [
"id"
],
"properties": {
"deposit": {
"anyOf": [
{
"$ref": "#/definitions/Deposit"
},
{
"type": "null"
}
]
},
"id": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false,
"definitions": {
"Deposit": {
"type": "object",
"required": [
"bs58_encoded_ed25519_pubkey"
],
"properties": {
"bs58_encoded_ed25519_pubkey": {
"type": "string"
}
},
"additionalProperties": false
}
}
},
"get_deposits_paged": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PagedDepositsResponse",
"type": "object",
"required": [
"deposits"
],
"properties": {
"deposits": {
"type": "array",
"items": {
"$ref": "#/definitions/DepositData"
}
},
"start_next_after": {
"description": "Field indicating paging information for the following queries if the caller wishes to get further entries.",
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false,
"definitions": {
"Deposit": {
"type": "object",
"required": [
"bs58_encoded_ed25519_pubkey"
],
"properties": {
"bs58_encoded_ed25519_pubkey": {
"type": "string"
}
},
"additionalProperties": false
},
"DepositData": {
"type": "object",
"required": [
"deposit",
"id"
],
"properties": {
"deposit": {
"$ref": "#/definitions/Deposit"
},
"id": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
},
"get_required_deposit_amount": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Coin",
"type": "object",
"required": [
"amount",
"denom"
],
"properties": {
"amount": {
"$ref": "#/definitions/Uint128"
},
"denom": {
"type": "string"
}
},
"definitions": {
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
}
}
}
}
}
+189
View File
@@ -0,0 +1,189 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExecuteMsg",
"oneOf": [
{
"description": "Used by clients to request ticket books from the signers",
"type": "object",
"required": [
"deposit_ticket_book_funds"
],
"properties": {
"deposit_ticket_book_funds": {
"type": "object",
"required": [
"identity_key"
],
"properties": {
"identity_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "Used by gateways to batch redeem tokens from the spent tickets",
"type": "object",
"required": [
"request_redemption"
],
"properties": {
"request_redemption": {
"type": "object",
"required": [
"commitment_bs58",
"number_of_tickets"
],
"properties": {
"commitment_bs58": {
"type": "string"
},
"number_of_tickets": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "The actual message that gets executed, after multisig votes, that transfers the ticket tokens into gateway's (and the holding) account",
"type": "object",
"required": [
"redeem_tickets"
],
"properties": {
"redeem_tickets": {
"type": "object",
"required": [
"gw",
"n"
],
"properties": {
"gw": {
"type": "string"
},
"n": {
"type": "integer",
"format": "uint16",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"update_admin"
],
"properties": {
"update_admin": {
"type": "object",
"required": [
"admin"
],
"properties": {
"admin": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"update_deposit_value"
],
"properties": {
"update_deposit_value": {
"type": "object",
"required": [
"new_deposit"
],
"properties": {
"new_deposit": {
"$ref": "#/definitions/Coin"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"propose_to_blacklist"
],
"properties": {
"propose_to_blacklist": {
"type": "object",
"required": [
"public_key"
],
"properties": {
"public_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"add_to_blacklist"
],
"properties": {
"add_to_blacklist": {
"type": "object",
"required": [
"public_key"
],
"properties": {
"public_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
],
"definitions": {
"Coin": {
"type": "object",
"required": [
"amount",
"denom"
],
"properties": {
"amount": {
"$ref": "#/definitions/Uint128"
},
"denom": {
"type": "string"
}
}
},
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
}
}
}
@@ -0,0 +1,26 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InstantiateMsg",
"type": "object",
"required": [
"group_addr",
"holding_account",
"mix_denom",
"multisig_addr"
],
"properties": {
"group_addr": {
"type": "string"
},
"holding_account": {
"type": "string"
},
"mix_denom": {
"type": "string"
},
"multisig_addr": {
"type": "string"
}
},
"additionalProperties": false
}
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"type": "object",
"additionalProperties": false
}
+123
View File
@@ -0,0 +1,123 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "QueryMsg",
"oneOf": [
{
"type": "object",
"required": [
"get_blacklisted_account"
],
"properties": {
"get_blacklisted_account": {
"type": "object",
"required": [
"public_key"
],
"properties": {
"public_key": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_blacklist_paged"
],
"properties": {
"get_blacklist_paged": {
"type": "object",
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_required_deposit_amount"
],
"properties": {
"get_required_deposit_amount": {
"type": "object",
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_deposit"
],
"properties": {
"get_deposit": {
"type": "object",
"required": [
"deposit_id"
],
"properties": {
"deposit_id": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"get_deposits_paged"
],
"properties": {
"get_deposits_paged": {
"type": "object",
"properties": {
"limit": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"start_after": {
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
]
}
@@ -0,0 +1,70 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PagedBlacklistedAccountResponse",
"type": "object",
"required": [
"accounts",
"per_page"
],
"properties": {
"accounts": {
"type": "array",
"items": {
"$ref": "#/definitions/BlacklistedAccount"
}
},
"per_page": {
"type": "integer",
"format": "uint",
"minimum": 0.0
},
"start_next_after": {
"description": "Field indicating paging information for the following queries if the caller wishes to get further entries.",
"type": [
"string",
"null"
]
}
},
"additionalProperties": false,
"definitions": {
"BlacklistedAccount": {
"type": "object",
"required": [
"info",
"public_key"
],
"properties": {
"info": {
"$ref": "#/definitions/Blacklisting"
},
"public_key": {
"type": "string"
}
},
"additionalProperties": false
},
"Blacklisting": {
"type": "object",
"required": [
"proposal_id"
],
"properties": {
"finalized_at_height": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0.0
},
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
}
@@ -0,0 +1,42 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "BlacklistedAccountResponse",
"type": "object",
"properties": {
"account": {
"anyOf": [
{
"$ref": "#/definitions/Blacklisting"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false,
"definitions": {
"Blacklisting": {
"type": "object",
"required": [
"proposal_id"
],
"properties": {
"finalized_at_height": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0.0
},
"proposal_id": {
"type": "integer",
"format": "uint64",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
}
@@ -0,0 +1,40 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DepositResponse",
"type": "object",
"required": [
"id"
],
"properties": {
"deposit": {
"anyOf": [
{
"$ref": "#/definitions/Deposit"
},
{
"type": "null"
}
]
},
"id": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false,
"definitions": {
"Deposit": {
"type": "object",
"required": [
"bs58_encoded_ed25519_pubkey"
],
"properties": {
"bs58_encoded_ed25519_pubkey": {
"type": "string"
}
},
"additionalProperties": false
}
}
}
@@ -0,0 +1,58 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PagedDepositsResponse",
"type": "object",
"required": [
"deposits"
],
"properties": {
"deposits": {
"type": "array",
"items": {
"$ref": "#/definitions/DepositData"
}
},
"start_next_after": {
"description": "Field indicating paging information for the following queries if the caller wishes to get further entries.",
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false,
"definitions": {
"Deposit": {
"type": "object",
"required": [
"bs58_encoded_ed25519_pubkey"
],
"properties": {
"bs58_encoded_ed25519_pubkey": {
"type": "string"
}
},
"additionalProperties": false
},
"DepositData": {
"type": "object",
"required": [
"deposit",
"id"
],
"properties": {
"deposit": {
"$ref": "#/definitions/Deposit"
},
"id": {
"type": "integer",
"format": "uint32",
"minimum": 0.0
}
},
"additionalProperties": false
}
}
}
@@ -0,0 +1,23 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Coin",
"type": "object",
"required": [
"amount",
"denom"
],
"properties": {
"amount": {
"$ref": "#/definitions/Uint128"
},
"denom": {
"type": "string"
}
},
"definitions": {
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
}
}
}
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use cosmwasm_schema::write_api;
use nym_ecash_contract_common::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
fn main() {
write_api! {
instantiate: InstantiateMsg,
query: QueryMsg,
execute: ExecuteMsg,
migrate: MigrateMsg,
}
}
+5
View File
@@ -0,0 +1,5 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub const BLACKLIST_PROPOSAL_REPLY_ID: u64 = 7759;
pub const REDEMPTION_PROPOSAL_REPLY_ID: u64 = 2137;
+19 -3
View File
@@ -4,19 +4,33 @@
use crate::contract::NymEcashContract;
use crate::helpers::{create_batch_redemption_proposal, create_blacklist_proposal, ProposalId};
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{to_binary, Addr, Coin, Deps, SubMsg};
use cosmwasm_std::{to_binary, Addr, Deps, Storage, SubMsg};
use cw3::ProposalResponse;
use nym_ecash_contract_common::EcashContractError;
use nym_multisig_contract_common::msg::QueryMsg as MultisigQueryMsg;
use nym_network_defaults::TICKETBOOK_SIZE;
use sylvia::types::ExecCtx;
#[cw_serde]
pub(crate) struct Invariants {
pub(crate) ticket_book_value: Coin,
pub(crate) ticket_value: Coin,
pub(crate) ticket_book_size: u64,
}
impl NymEcashContract<'_> {
pub(crate) fn get_ticketbook_size(
&self,
storage: &dyn Storage,
) -> Result<u64, EcashContractError> {
let invariants = self.expected_invariants.load(storage)?;
if invariants.ticket_book_size != TICKETBOOK_SIZE {
return Err(EcashContractError::TicketBookSizeChanged {
at_init: invariants.ticket_book_size,
current: TICKETBOOK_SIZE,
});
}
Ok(TICKETBOOK_SIZE)
}
fn must_get_multisig_addr(&self, deps: Deps) -> Result<Addr, EcashContractError> {
// SAFETY: multisig admin MUST always be set on initialisation,
// if the call fails, we're in some weird UB land
@@ -45,6 +59,8 @@ impl NymEcashContract<'_> {
.map_err(Into::into)
}
// temporarily dead
#[allow(dead_code)]
pub(crate) fn create_blacklist_proposal(
&self,
ctx: ExecCtx,
+134 -87
View File
@@ -1,13 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::constants::{BLACKLIST_PROPOSAL_REPLY_ID, REDEMPTION_PROPOSAL_REPLY_ID};
use crate::contract::helpers::Invariants;
use crate::deposit::DepositStorage;
use crate::helpers::{
BlacklistKey, Config, MultisigReply, BLACKLIST_PAGE_DEFAULT_LIMIT, BLACKLIST_PAGE_MAX_LIMIT,
CONTRACT_NAME, CONTRACT_VERSION, DEPOSITS_PAGE_DEFAULT_LIMIT, DEPOSITS_PAGE_MAX_LIMIT,
};
use cosmwasm_std::{BankMsg, Coin, Decimal, Event, Order, Reply, Response, StdResult, Uint128};
use cosmwasm_std::{
coin, BankMsg, Coin, Decimal, Event, Order, Reply, Response, StdResult, Uint128,
};
use cw4::Cw4Contract;
use cw_controllers::Admin;
use cw_storage_plus::{Bound, Item, Map};
@@ -15,12 +18,13 @@ use nym_contracts_common::set_build_information;
use nym_ecash_contract_common::blacklist::{
BlacklistedAccount, BlacklistedAccountResponse, Blacklisting, PagedBlacklistedAccountResponse,
};
use nym_ecash_contract_common::counters::PoolCounters;
use nym_ecash_contract_common::deposit::{DepositData, DepositResponse, PagedDepositsResponse};
use nym_ecash_contract_common::events::{
BLACKLIST_PROPOSAL_REPLY_ID, DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ID,
PROPOSAL_ID_ATTRIBUTE_NAME, REDEMPTION_PROPOSAL_REPLY_ID, TICKET_BOOK_VALUE, TICKET_VALUE,
DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ID, PROPOSAL_ID_ATTRIBUTE_NAME,
};
use nym_ecash_contract_common::EcashContractError;
use nym_network_defaults::TICKETBOOK_SIZE;
use sylvia::types::{ExecCtx, InstantiateCtx, MigrateCtx, QueryCtx, ReplyCtx};
use sylvia::{contract, entry_points};
@@ -30,8 +34,10 @@ mod helpers;
mod test;
pub struct NymEcashContract<'a> {
pub(crate) contract_admin: Admin<'a>,
pub(crate) multisig: Admin<'a>,
pub(crate) config: Item<'a, Config>,
pub(crate) pool_counters: Item<'a, PoolCounters>,
pub(crate) expected_invariants: Item<'a, Invariants>,
pub(crate) blacklist: Map<'a, BlacklistKey, Blacklisting>,
@@ -46,8 +52,10 @@ impl NymEcashContract<'_> {
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self {
contract_admin: Admin::new("contract_admin"),
multisig: Admin::new("multisig"),
config: Item::new("config"),
pool_counters: Item::new("pool_counters"),
expected_invariants: Item::new("expected_invariants"),
blacklist: Map::new("blacklist"),
deposits: DepositStorage::new(),
@@ -61,7 +69,7 @@ impl NymEcashContract<'_> {
holding_account: String,
multisig_addr: String,
group_addr: String,
mix_denom: String,
deposit_amount: Coin,
) -> Result<Response, EcashContractError> {
let multisig_addr = ctx.deps.api.addr_validate(&multisig_addr)?;
let holding_account = ctx.deps.api.addr_validate(&holding_account)?;
@@ -71,25 +79,37 @@ impl NymEcashContract<'_> {
}
})?);
// by default the sender becomes the admin
self.contract_admin
.set(ctx.deps.branch(), Some(ctx.info.sender))?;
self.multisig
.set(ctx.deps.branch(), Some(multisig_addr.clone()))?;
self.expected_invariants.save(
ctx.deps.storage,
&Invariants {
ticket_book_value: Coin::new(TICKET_BOOK_VALUE, &mix_denom),
ticket_value: Coin::new(TICKET_VALUE, &mix_denom),
ticket_book_size: TICKETBOOK_SIZE,
},
)?;
let cfg = Config {
group_addr,
mix_denom,
holding_account,
self.pool_counters.save(
ctx.deps.storage,
&PoolCounters {
total_deposited: coin(0, &deposit_amount.denom),
total_redeemed_gateways: coin(0, &deposit_amount.denom),
total_redeemed_holding: coin(0, &deposit_amount.denom),
},
)?;
redemption_gateway_share: Decimal::percent(5),
};
self.config.save(ctx.deps.storage, &cfg)?;
self.config.save(
ctx.deps.storage,
&Config {
group_addr,
holding_account,
redemption_gateway_share: Decimal::percent(5),
deposit_amount,
},
)?;
cw2::set_contract_version(ctx.deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
set_build_information!(ctx.deps.storage)?;
@@ -142,21 +162,10 @@ impl NymEcashContract<'_> {
}
#[msg(query)]
pub fn get_required_deposit_amount(&self, ctx: QueryCtx) -> Result<Coin, EcashContractError> {
let mix_denom = self.config.load(ctx.deps.storage)?.mix_denom;
let expected_deposit = self
.expected_invariants
.load(ctx.deps.storage)?
.ticket_book_value;
let current = Coin::new(TICKET_BOOK_VALUE, mix_denom);
if expected_deposit != current {
return Err(EcashContractError::DepositAmountChanged {
at_init: expected_deposit,
current,
});
}
pub fn get_required_deposit_amount(&self, ctx: QueryCtx) -> StdResult<Coin> {
let deposit_amount = self.config.load(ctx.deps.storage)?.deposit_amount;
Ok(current)
Ok(deposit_amount)
}
#[msg(query)]
@@ -209,28 +218,26 @@ impl NymEcashContract<'_> {
ctx: ExecCtx,
identity_key: String,
) -> Result<Response, EcashContractError> {
let mix_denom = self.config.load(ctx.deps.storage)?.mix_denom;
let voucher_value = cw_utils::must_pay(&ctx.info, &mix_denom)?;
let amount = voucher_value.u128();
let required_deposit = self.config.load(ctx.deps.storage)?.deposit_amount;
let expected_deposit = self
.expected_invariants
.load(ctx.deps.storage)?
.ticket_book_value;
if expected_deposit.amount.u128() != TICKET_BOOK_VALUE {
return Err(EcashContractError::DepositAmountChanged {
at_init: expected_deposit,
current: Coin::new(TICKET_BOOK_VALUE, mix_denom),
});
}
let submitted = cw_utils::must_pay(&ctx.info, &required_deposit.denom)?;
if amount != TICKET_BOOK_VALUE {
if submitted != required_deposit.amount {
let mut funds = ctx.info.funds;
return Err(EcashContractError::WrongAmount {
received: amount,
amount: TICKET_BOOK_VALUE,
// SAFETY: the call to `must_pay` ensured a single coin has been sent
#[allow(clippy::unwrap_used)]
received: funds.pop().unwrap(),
amount: required_deposit,
});
}
self.pool_counters
.update(ctx.deps.storage, |mut counters| -> StdResult<_> {
counters.total_deposited.amount += submitted;
Ok(counters)
})?;
let deposit_id = self.deposits.save_deposit(ctx.deps.storage, identity_key)?;
Ok(Response::new()
@@ -272,66 +279,103 @@ impl NymEcashContract<'_> {
.assert_admin(ctx.deps.as_ref(), &ctx.info.sender)?;
let config = self.config.load(ctx.deps.storage)?;
let denom = &config.mix_denom;
let expected_ticket = self
.expected_invariants
.load(ctx.deps.storage)?
.ticket_value;
let current = Coin::new(TICKET_VALUE, denom);
if expected_ticket != current {
return Err(EcashContractError::TicketValueChanged {
at_init: expected_ticket,
current,
});
}
// TODO: we need unit tests for this
let return_amount = Uint128::new(TICKET_VALUE * n as u128);
let deposit_amount = config.deposit_amount.amount;
let ticketbook_size = Uint128::new(self.get_ticketbook_size(ctx.deps.storage)? as u128);
let tickets = Uint128::new(n as u128);
// how many tickets from a ticketbook you redeemed
let book_ratio = Decimal::from_ratio(tickets, ticketbook_size);
let return_amount = book_ratio * deposit_amount;
let gw_share = config.redemption_gateway_share * return_amount;
let holding_share = return_amount - gw_share;
self.pool_counters
.update(ctx.deps.storage, |mut counters| -> StdResult<_> {
counters.total_redeemed_gateways.amount += gw_share;
counters.total_redeemed_holding.amount += holding_share;
Ok(counters)
})?;
Ok(Response::new()
.add_message(BankMsg::Send {
to_address: gw,
amount: vec![Coin {
denom: denom.to_owned(),
denom: config.deposit_amount.denom.clone(),
amount: gw_share,
}],
})
.add_message(BankMsg::Send {
to_address: config.holding_account.to_string(),
amount: vec![Coin {
denom: denom.to_owned(),
denom: config.deposit_amount.denom,
amount: holding_share,
}],
}))
}
#[msg(exec)]
pub fn update_admin(
&self,
ctx: ExecCtx,
admin: String,
) -> Result<Response, EcashContractError> {
let new_admin = ctx.deps.api.addr_validate(&admin)?;
// note: the below performs validation to ensure the sender IS the current admin
Ok(self
.contract_admin
.execute_update_admin(ctx.deps, ctx.info, Some(new_admin))?)
}
#[msg(exec)]
pub fn update_deposit_value(
&self,
ctx: ExecCtx,
new_deposit: Coin,
) -> Result<Response, EcashContractError> {
// only current admin can do that
self.contract_admin
.assert_admin(ctx.deps.as_ref(), &ctx.info.sender)?;
let deposit_str = new_deposit.to_string();
self.config
.update(ctx.deps.storage, |mut cfg| -> StdResult<_> {
cfg.deposit_amount = new_deposit;
Ok(cfg)
})?;
Ok(Response::new().add_attribute("updated_deposit", deposit_str))
}
#[msg(exec)]
pub fn propose_to_blacklist(
&self,
ctx: ExecCtx,
public_key: String,
) -> Result<Response, EcashContractError> {
let cfg = self.config.load(ctx.deps.storage)?;
cfg.group_addr
.is_voting_member(&ctx.deps.querier, &ctx.info.sender, ctx.env.block.height)?
.ok_or(EcashContractError::Unauthorized)?;
if let Some(blacklisted) = self
.blacklist
.may_load(ctx.deps.storage, public_key.clone())?
{
// return existing proposal id
Ok(Response::new().add_attribute(
PROPOSAL_ID_ATTRIBUTE_NAME,
blacklisted.proposal_id.to_string(),
))
} else {
let msg = self.create_blacklist_proposal(ctx, public_key)?;
Ok(Response::new().add_submessage(msg))
}
let _ = ctx;
let _ = public_key;
Err(EcashContractError::UnimplementedBlacklisting)
// let cfg = self.config.load(ctx.deps.storage)?;
// cfg.group_addr
// .is_voting_member(&ctx.deps.querier, &ctx.info.sender, ctx.env.block.height)?
// .ok_or(EcashContractError::Unauthorized)?;
//
// if let Some(blacklisted) = self
// .blacklist
// .may_load(ctx.deps.storage, public_key.clone())?
// {
// // return existing proposal id
// Ok(Response::new().add_attribute(
// PROPOSAL_ID_ATTRIBUTE_NAME,
// blacklisted.proposal_id.to_string(),
// ))
// } else {
// let msg = self.create_blacklist_proposal(ctx, public_key)?;
// Ok(Response::new().add_submessage(msg))
// }
}
#[msg(exec)]
@@ -340,16 +384,19 @@ impl NymEcashContract<'_> {
ctx: ExecCtx,
public_key: String,
) -> Result<Response, EcashContractError> {
//Only by multisig contract, actually add public key to blacklist
self.multisig
.assert_admin(ctx.deps.as_ref(), &ctx.info.sender)?;
let mut blacklisting = self.blacklist.load(ctx.deps.storage, public_key.clone())?;
blacklisting.finalized_at_height = Some(ctx.env.block.height);
self.blacklist
.save(ctx.deps.storage, public_key.clone(), &blacklisting)?;
Ok(Response::new())
let _ = ctx;
let _ = public_key;
Err(EcashContractError::UnimplementedBlacklisting)
// //Only by multisig contract, actually add public key to blacklist
// self.multisig
// .assert_admin(ctx.deps.as_ref(), &ctx.info.sender)?;
//
// let mut blacklisting = self.blacklist.load(ctx.deps.storage, public_key.clone())?;
// blacklisting.finalized_at_height = Some(ctx.env.block.height);
// self.blacklist
// .save(ctx.deps.storage, public_key.clone(), &blacklisting)?;
//
// Ok(Response::new())
}
/*=====================
+6 -8
View File
@@ -1,18 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::constants::{BLACKLIST_PROPOSAL_REPLY_ID, REDEMPTION_PROPOSAL_REPLY_ID};
use cosmwasm_std::{
to_binary, Addr, CosmosMsg, Decimal, Reply, StdError, StdResult, SubMsg, SubMsgResult, WasmMsg,
to_binary, Addr, Coin, CosmosMsg, Decimal, Reply, StdError, StdResult, SubMsg, SubMsgResult,
WasmMsg,
};
use cw4::Cw4Contract;
use nym_contracts_common::events::try_find_attribute;
use nym_ecash_contract_common::events::{
PROPOSAL_ID_ATTRIBUTE_NAME, REDEMPTION_PROPOSAL_REPLY_ID, WASM_EVENT_NAME,
};
use nym_ecash_contract_common::events::{PROPOSAL_ID_ATTRIBUTE_NAME, WASM_EVENT_NAME};
use nym_ecash_contract_common::redeem_credential::BATCH_REDEMPTION_PROPOSAL_TITLE;
use nym_ecash_contract_common::{
events::BLACKLIST_PROPOSAL_REPLY_ID, msg::ExecuteMsg, EcashContractError,
};
use nym_ecash_contract_common::{msg::ExecuteMsg, EcashContractError};
use nym_multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg;
use serde::{Deserialize, Serialize};
@@ -23,10 +21,10 @@ pub(crate) const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Config {
pub group_addr: Cw4Contract,
pub mix_denom: String,
pub holding_account: Addr,
pub redemption_gateway_share: Decimal,
pub deposit_amount: Coin,
}
//type aliases for easier reasoning
+1
View File
@@ -6,6 +6,7 @@
#![warn(clippy::todo)]
#![warn(clippy::dbg_macro)]
mod constants;
pub mod contract;
mod deposit;
mod helpers;
-36
View File
@@ -1,36 +0,0 @@
[package]
name = "nym-name-service"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "schema"
required-features = ["schema-gen"]
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
bs58 = { workspace = true }
cosmwasm-schema = { workspace = true, optional = true }
cosmwasm-std = { workspace = true }
cw-controllers = { workspace = true }
cw-storage-plus = { workspace = true }
cw-utils = { workspace = true }
cw2 = { workspace = true }
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.5.0" }
nym-name-service-common = { path = "../../common/cosmwasm-smart-contracts/name-service" }
serde = { version = "1.0.155", default-features = false, features = ["derive"] }
thiserror = { workspace = true }
[dev-dependencies]
anyhow = "1.0.40"
cw-multi-test = { workspace = true }
nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] }
nym-sphinx-addressing = { path = "../../common/nymsphinx/addressing" }
rand = "0.8.5"
rand_chacha = "0.3"
rstest = "0.17.0"
[features]
schema-gen = ["nym-name-service-common/schema", "cosmwasm-schema"]
@@ -1,34 +0,0 @@
[package]
name = "nym-service-provider-directory"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "schema"
required-features = ["schema-gen"]
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
bs58 = { workspace = true }
cosmwasm-schema = { workspace = true, optional = true }
cosmwasm-std = { workspace = true }
cw-controllers = { workspace = true }
cw-storage-plus = { workspace = true }
cw-utils = { workspace = true }
cw2 = { workspace = true }
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.5.0" }
nym-service-provider-directory-common = { path = "../../common/cosmwasm-smart-contracts/service-provider-directory" }
serde = { version = "1.0.155", default-features = false, features = ["derive"] }
thiserror = { workspace = true }
[dev-dependencies]
anyhow = "1.0.40"
cw-multi-test = { workspace = true }
nym-crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] }
rand_chacha = "0.3"
rstest = "0.17.0"
[features]
schema-gen = ["nym-service-provider-directory-common/schema", "cosmwasm-schema"]
@@ -220,7 +220,7 @@ impl NetworkManager {
.kill_on_drop(true);
if let Some(gateway) = &ctx.gateway {
cmd.args(["--gateway", &gateway]);
cmd.args(["--gateway", gateway]);
}
let mut child = cmd.spawn()?;
@@ -199,7 +199,7 @@ impl NetworkManager {
.to_string(),
multisig_addr: ctx.network.contracts.cw3_multisig.address()?.to_string(),
group_addr: ctx.network.contracts.cw4_group.address()?.to_string(),
mix_denom: ctx.admin.mix_coin(0).denom,
deposit_amount: ctx.admin.mix_coin(75_000_000).into(),
})
}