2021-11-25 23:25 | 出处: CUDOS
去中心化云计算网络CUDOS是一个第一层区块链,由智能合约管理,能够以分布式的方式将区块链与安全的外部资源对接,为区块链引入高性能计算以及解决区块链可扩展问题。在这一系列文章中,我们将从基础知识入手,逐步讲解如何在CUDOS网络上搭建智能合约。
CUDOS的测试网激励计划正在进行中,感兴趣的开发者可以参与到测试其公测网络Somniorum的过程中,并赢得相应的奖励。
在第一部分中,您完成了CosmWasm环境和CosmWasm合约架构的设置。现在是时候开始创建一个项目了,这也是您将在本部分学到的内容。
根文件夹:CW-plus(所有路径都是以CW-plus作为根定义的)S。
[workspace]
members = [“packages/*”, “contracts/*”]
[profile.release.package.stake-cw20]
codegen-units = 1
incremental = false
[profile.release]
rpath = false
lto = true
overflow-checks =true
opt-level = 3
debug = false
debug-assertions =false
这里,stake-cw20是您将在下一步中创建的项目的名称。如果仔细研究下这个cargo.toml,你会发现该cargo的workspace配置。
codegen-units标记控制着库文件被分成多少个代码生成单元。它需要一个大于0的整数。
cargo new stake-cw20— lib
[package]
name = “stake-cw20”
version = “0.1.0”
edition = “2018”
# See more keys andtheir definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type =[“cdylib”, “rlib”]
[features]
backtraces =[“cosmwasm-std/backtraces”]
# use libraryfeature to disable all instantiate/execute/query exports
library = []
[dependencies]
cw0 = { path =“../../packages/cw0”, version = “0.8.0” }
cw2 = { path =“../../packages/cw2”, version = “0.8.0” }
cw20 = { path =“../../packages/cw20”, version = “0.8.0” }
cw-storage-plus = {path = “../../packages/storage-plus”, version = “0.8.0” }
cosmwasm-std = {version = “0.16.0” }
schemars = “0.8.1”
serde = { version =“1.0.103”, default-features = false, features = [“derive”] }
thiserror = {version = “1.0.23” }
[dev-dependencies]
cosmwasm-schema = {version = “0.16.0” }
在src文件夹内创建以下文件夹:
首先让我们定义智能合约中的错误信息。用以下代码更新error.rs:
usecosmwasm_std::StdError;
usethiserror::Error;
#[derive(Error,Debug, PartialEq)]
pub enumContractError {
#[error(“{0}”)]
Std(#[from]StdError),
#[error(“Unauthorized”)]
Unauthorized {},
#[error(“Cannot set to own account”)]
CannotSetOwnAccount{},
#[error(“Invalid zero amount”)]
InvalidZeroAmount{},
#[error(“Allowance is expired”)]
Expired {},
#[error(“No allowance for this account”)]
NoAllowance {},
}
在定义了信息之后,你将定义合约拥有的状态(state)。可以把state想成典型应用程序中的数据库,你将在那里存储所有的数据。
useschemars::JsonSchema;
useserde::{Deserialize, Serialize};
usecosmwasm_std::{Addr, Timestamp, Uint128};
usecw_storage_plus::{Item, Map};
usecw20::{AllowanceResponse, Logo};
#[derive(Serialize,Deserialize, Clone, PartialEq, JsonSchema, Debug)]
#[serde(rename_all =“snake_case”)]
pub struct TokenInfo{
pub name: String,
pub symbol: String,
pub decimals: u8,
pub total_supply:Uint128,
pub minter: Addr,
}
#[derive(Serialize,Deserialize, Clone, PartialEq, JsonSchema, Debug)]
#[serde(rename_all =“snake_case”)]
pub structStakeHolderInfo {
pub amount: Uint128,
pub rewards:Uint128,
}
pub constTOKEN_INFO: Item<TokenInfo> = Item::new(“token_info”);
pub const LAST_DISTRIBUTE_TIME:Item<Timestamp> = Item::new(“last_distributed_time”);
pub const BALANCES:Map<&Addr, Uint128> = Map::new(“balance”);
pub constALLOWANCES: Map<(&Addr, &Addr), AllowanceResponse> = Map::new(“allowance”);
pub constSTAKE_HOLDERS: Map<&Addr, StakeHolderInfo> = Map::new(“stake_holder”);
pub constTOTAL_STAKE: Item<Uint128> = Item::new(“total_stake”);
derive stmt的基本功能是为一个给定的类型提供标准的特征实现。这有助于减少代码和消除错误。
如果你熟悉Rust,那么你已经了解了结构。如果你不熟悉Rust,请先看看结构。你会在一个状态(state)下发现Items<>和Maps<>类型。让我们来详细了解一下它们:
这些都在state.rs文件里面。
在这里,你将定义区块链的只读和只写功能的结构。
在这里,你可以按照你的意愿来命名msg。下面你可以看到开发者用来创建CosmWasm合约的惯例。
usecosmwasm_std::{StdError, StdResult, Uint128};
use cw0::Expiration;
usecw20::{Cw20Coin};
useschemars::JsonSchema;
useserde::{Deserialize, Serialize};
#[derive(Serialize,Deserialize, JsonSchema, Debug, Clone, PartialEq)]
pub struct InstantiateMsg{
pub name: String,
pub symbol: String,
pub decimals: u8,
pubinitial_balances: Vec<Cw20Coin>,
}
impl InstantiateMsg{
pub fnvalidate(&self) -> StdResult<()> {
// Check name,symbol, decimals
if!is_valid_name(&self.name) {
returnErr(StdError::generic_err(
“Name is notin the expected format (3–50 UTF-8 bytes)”,
));
}
if!is_valid_symbol(&self.symbol) {
returnErr(StdError::generic_err(
“Ticker symbolis not in expected format [a-zA-Z\-]{3,12}”,
));
}
if self.decimals> 18 {
returnErr(StdError::generic_err(“Decimals must not exceed 18”));
}
Ok(())
}
}
fnis_valid_name(name: &str) -> bool {
let bytes =name.as_bytes();
if bytes.len() <3 || bytes.len() > 50 {
return false;
}
true
}
fnis_valid_symbol(symbol: &str) -> bool {
let bytes =symbol.as_bytes();
if bytes.len() <3 || bytes.len() > 12 {
return false;
}
for byte inbytes.iter() {
if (*byte != 45)&& (*byte < 65 || *byte > 90) && (*byte < 97 || *byte> 122) {
return false;
}
}
true
}
#[derive(Serialize,Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all =“snake_case”)]
pub enum QueryMsg {
/// Returns thecurrent balance of the given address, 0 if unset.
/// Return type:BalanceResponse.
Balance {
address: String,
},
Minter {},
/// Returns metadataon the contract — name, decimals, supply, etc.
/// Return type:TokenInfoResponse.
TokenInfo {},
/// Only with“allowance” extension.
/// Returns how muchspender can use from owner account, 0 if unset.
/// Return type:AllowanceResponse.
Allowance {
owner: String,
spender: String,
},
/// Only with“enumerable” extension (and “allowances”)
/// Returns allallowances this owner has approved. Supports pagination.
/// Return type:AllAllowancesResponse.
AllAllowances {
owner: String,
start_after:Option<String>,
limit:Option<u32>,
},
/// Only with“enumerable” extension
/// Returns allaccounts that have balances. Supports pagination.
/// Return type:AllAccountsResponse.
AllAccounts {
start_after:Option<String>,
limit:Option<u32>,
},
AllStakeHolders {
start_after:Option<String>,
limit:Option<u32>,
},
TotalStake {},
StakeAndRewardOf {
account: String,
},
}
#[derive(Serialize,Deserialize, Clone, PartialEq, JsonSchema, Debug)]
#[serde(rename_all =“snake_case”)]
pub enum ExecuteMsg{
/// Transfer is abase message to move tokens to another account without triggering actions
Transfer {
recipient: String,
amount: Uint128,
},
/// Burn is a basemessage to destroy tokens forever
Burn {
amount: Uint128,
},
/// Only with“approval” extension. Allows spender to access an additional amount tokens
/// from the owner’s(env.sender) account. If expires is Some(), overwrites current allowance
/// expiration withthis one.
IncreaseAllowance {
spender: String,
amount: Uint128,
expires:Option<Expiration>,
},
/// Only with“approval” extension. Lowers the spender’s access of tokens
/// from the owner’s(env.sender) account by amount. If expires is Some(), overwrites current
/// allowanceexpiration with this one.
DecreaseAllowance {
spender: String,
amount: Uint128,
expires:Option<Expiration>,
},
/// Only with“approval” extension. Transfers amount tokens from owner -> recipient
/// if `env.sender`has sufficient pre-approval.
TransferFrom {
owner: String,
recipient: String,
amount: Uint128,
},
/// Only with“approval” extension. Destroys tokens forever
BurnFrom {
owner: String,
amount: Uint128,
},
/// Only with the“mintable” extension. If authorized, create amount new tokens
/// and adds to therecipient balance.
Mint {
recipient: String,
amount: Uint128,
},
CreateStake {
amount: Uint128,
},
RemoveStake {
amount: Uint128,
},
DistributRewards {},
WithdrawRewards {},
}
#[derive(Serialize,Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub structTotalStakeResponse {
pub total_stake:Uint128,
}
#[derive(Serialize,Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub structAllStakeHolderResponse {
pub accounts:Vec<String>,
}
五个变量:
例如
pub mod allowances;
pub mod contract;
pub mod enumerable;
mod error;
pub mod msg;
pub mod state;
pub usecrate::error::ContractError;
另外,你会发现两个新的mod allowance和enumerable(可枚举项)。
你可以直接从这里复制这些文件,而不用自己创建这两个文件:
在本系列的第三部分,我们将介绍包含主要业务逻辑的Contract.rs,讨论让你能够在状态(state)内进行一些计算和存储值操作的函数。
通过以下链接,您可以立即加入我们的激励测试网Project Artemis:
加入CUDOS的Discord服务器
加入CUDOS的Telegram社区
买入CUDOS
成为CUDOS的大使
值得注意的是,您将根据您在测试网中完成的任务获得奖励。
此外,如果您已经购买了CUDOS代币,可以把它们质押在我们的平台上,以确保网络安全,作为回报,您可以获得奖励。
CUDOS网络是一个第一层区块链和第二层计算及预言机网络,旨在大规模提供去中心化、无许可的高性能计算,可将计算资源扩展至数十万节点。在与以/太坊、Algorand、波卡和Cosmos桥接后,CUDOS将在所有桥接的区块链上实现可扩展的计算和第二层预言机。
官网:https://www.cudos.org/
Twitter:https://twitter.com/CUDOS_
微博:https://weibo.com/cudos
中文电报:https://t.me/Cudos2021