본문으로 건너뛰기

모범 사례

오버플로우 검사 사용

일반적으로 정수 오버플로우에 대해서는 패닉하는 것이 도움이 됩니다. 이를 활성화하려면 Cargo.toml 파일에 다음을 추가하세요.

[profile.release]
overflow-checks = true

초기에 require! 사용

조치를 취하기 전에, require!를 사용하여 입력, 컨텍스트, 상태 및 액세스를 검증하세요. The earlier you panic, the more gas you will save for the caller.

#[near_bindgen]
impl Contract {
pub fn set_fee(&mut self, new_fee: Fee) {
require!(env::predecessor_account_id() == self.owner_id, "Owner's method");
new_fee.assert_valid();
self.internal_set_fee(new_fee);
}
}

참고: 패닉 메시지에서 디버그 정보를 원하거나 4.0.0-pre.2 전 SDK 버전을 사용 중인 경우, Rust의 assert! 매크로를 require! 대신 사용할 수 있습니다.

#[near_bindgen]
impl Contract {
pub fn set_fee(&mut self, new_fee: Fee) {
assert_eq!(env::predecessor_account_id(), self.owner_id, "Owner's method");
new_fee.assert_valid();
self.internal_set_fee(new_fee);
}
}

log! 사용

디버깅 및 사용자 알림을 위해 로깅을 사용합니다.

형식화된 메시지가 필요한 경우, 다음 매크로를 사용할 수 있습니다.

log!("Transferred {} tokens from {} to {}", amount, sender_id, receiver_id);

이는 다음 메시지와 동일합니다.

env::log_str(format!("Transferred {} tokens from {} to {}", amount, sender_id, receiver_id).as_ref());

Promise 반환

교차 컨트랙트 호출(Cross-Contract Call)을 수행하는 경우, 메서드가 새로 생성된 Promise를 반환하도록 하고 싶을 것입니다. 이를 통해 호출자(예: near-cli 또는 near-api-js 호출)는 Promise의 결과를 즉시 반환하는 대신 기다릴 수 있습니다. 또한 어떤 이유로 Promise가 실패하는 경우, Promise를 반환하면 호출자에게 실패에 대해 알리고, NEAR 익스플로러 및 기타 도구를 사용하여 전체 트랜잭션 체인을 실패로 표시할 수 있습니다. 이렇게 하면 체인의 첫 번째 또는 처음 몇 개의 트랜잭션이 성공하지만, 후속 트랜잭션이 실패할 때 긍정 오류(false-positives)를 방지할 수 있습니다.

예를 들어

#[near_bindgen]
impl Contract {
pub fn withdraw_100(&mut self, receiver_id: AccountId) -> Promise {
Promise::new(receiver_id).transfer(100)
}
}

near-sdk로부터의 크레이트 재사용

near-sdk는 다음 크레이트를 다시 내보냅니다.

  • borsh
  • base64
  • bs58
  • serde
  • serde_json

가장 일반적인 크레이트에는 내부 상태 직렬화 및 외부 JSON 직렬화를 위한 serde에 필요한 borsh가 포함됩니다.

serde::Serialize 구조체를 표시할 때, serde가 올바른 기본 크레이트를 가리키도록 #[serde(crate = "near_sdk::serde")]를 사용해야 합니다.

/// Import `borsh` from `near_sdk` crate 
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
/// Import `serde` from `near_sdk` crate
use near_sdk::serde::{Serialize, Deserialize};

/// Main contract structure serialized with Borsh
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct Contract {
pub pair: Pair,
}

/// Implements both `serde` and `borsh` serialization.
/// `serde` is typically useful when returning a struct in JSON format for a frontend.
#[derive(Serialize, Deserialize, BorshDeserialize, BorshSerialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Pair {
pub a: u32,
pub b: u32,
}

#[near_bindgen]
impl Contract {
#[init]
pub fn new(pair: Pair) -> Self {
Self {
pair,
}
}

pub fn get_pair(self) -> Pair {
self.pair
}
}

std::panic! vs env::panic

  • std::panic!은 현재 스레드를 패닉 상태로 만듭니다. 이는 내부적으로 format!을 사용하므로, 인자를 취할 수 있습니다. SDK는 패닉 후크를 설정하여, panic!으로부터 생성된 PanicInfo를 문자열로 변환하고, 내부적으로 env::panic을 사용하여 이를 런타임에 보고합니다. 이는 패닉이 발생한 소스 코드의 줄 번호와 같은 추가 디버깅 정보를 제공할 수 있습니다.

  • env::panic은 호스트 메서드를 직접 호출하여 컨트랙트를 패닉 상태로 만듭니다. 이는 전달된 메시지를 제외하고 다른 추가 디버깅 정보를 제공하지 않습니다.

작업 공간(Workspace) 사용

작업 공간을 사용하면, 워크플로우를 자동화하고 샌드박스 또는 테스트넷 환경에서 여러 컨트랙트 및 교차 컨트랙트 호출에 대한 테스트를 실행할 수 있습니다. workspaces-rs 또는 workspaces-js에 대해 더 알아보세요.

Was this page helpful?