错误
错误可用于处理智能合约执行过程中可能发生的验证和其他条件。 如果在执行智能合约调用期间抛出错误,则将停止执行,并恢复在交易期间所做的任何更改。
要抛出错误,请使用 assert
或 panic
函数:
-
'assert' 用于验证条件。 如果检查失败,则会引发错误以及指定的值,通常是一条消息。 它类似于 Solidity 中的
require
语句。 -
'panic' 立即停止执行,并给出错误值。 当要检查的条件复杂且存在内部错误时,应使用它。它类似于 Solidity 中的
revert
语句。 (使用panic_with_felt252
可以直接传递一个felt252作为错误值)
下面是一个简单的示例,演示了这些函数的用法:
#[starknet::interface]
trait IErrorsExample<TContractState> {
fn test_assert(self: @TContractState, i: u256);
fn test_panic(self: @TContractState, i: u256);
}
#[starknet::contract]
mod ErrorsExample {
#[storage]
struct Storage {}
#[abi(embed_v0)]
impl ErrorsExample of super::IErrorsExample<ContractState> {
fn test_assert(self: @ContractState, i: u256) {
// Assert used to validate a condition
// and abort execution if the condition is not met
assert(i > 0, 'i must be greater than 0');
}
fn test_panic(self: @ContractState, i: u256) {
if (i == 0) {
// Panic used to abort execution directly
panic_with_felt252('i must not be 0');
}
}
}
}
自定义错误
您可以通过在特定模块中定义错误代码来简化错误处理。
mod Errors {
const NOT_POSITIVE: felt252 = 'must be greater than 0';
const NOT_NULL: felt252 = 'must not be null';
}
#[starknet::interface]
trait ICustomErrorsExample<TContractState> {
fn test_assert(self: @TContractState, i: u256);
fn test_panic(self: @TContractState, i: u256);
}
#[starknet::contract]
mod CustomErrorsExample {
use super::Errors;
#[storage]
struct Storage {}
#[abi(embed_v0)]
impl CustomErrorsExample of super::ICustomErrorsExample<ContractState> {
fn test_assert(self: @ContractState, i: u256) {
assert(i > 0, Errors::NOT_POSITIVE);
}
fn test_panic(self: @ContractState, i: u256) {
if (i == 0) {
panic_with_felt252(Errors::NOT_NULL);
}
}
}
}
在 Voyager 上访问 contract 或在 Remix 中尝试它。
Vault 示例
下面是另一个示例,演示了在更复杂的合约中使用错误:
mod VaultErrors {
const INSUFFICIENT_BALANCE: felt252 = 'insufficient_balance';
// you can define more errors here
}
#[starknet::interface]
trait IVaultErrorsExample<TContractState> {
fn deposit(ref self: TContractState, amount: u256);
fn withdraw(ref self: TContractState, amount: u256);
}
#[starknet::contract]
mod VaultErrorsExample {
use super::VaultErrors;
#[storage]
struct Storage {
balance: u256,
}
#[abi(embed_v0)]
impl VaultErrorsExample of super::IVaultErrorsExample<ContractState> {
fn deposit(ref self: ContractState, amount: u256) {
let mut balance = self.balance.read();
balance = balance + amount;
self.balance.write(balance);
}
fn withdraw(ref self: ContractState, amount: u256) {
let mut balance = self.balance.read();
assert(balance >= amount, VaultErrors::INSUFFICIENT_BALANCE);
// Or using panic:
if (balance >= amount) {
panic_with_felt252(VaultErrors::INSUFFICIENT_BALANCE);
}
let balance = balance - amount;
self.balance.write(balance);
}
}
}