
Ескроу
Ескроу — це потужний фінансовий інструмент, який забезпечує безпечний обмін токенами між двома сторонами.
Уявіть це як цифрову банківську скриньку, де один користувач може заблокувати Токен А, очікуючи, поки інший користувач внесе Токен Б перед завершенням обміну.
Це створює середовище без довіри, де жодній стороні не потрібно турбуватися про те, що інша відмовиться від угоди.
У цьому завданні ми реалізуємо цю концепцію через три прості, але потужні інструкції:
Make: Мейкер (перший користувач) визначає умови угоди та вносить узгоджену кількість Токена А у захищене сховище. Це схоже на розміщення вашого предмета в банківській скриньці та встановлення умов обміну.
Take: Тейкер (другий користувач) приймає пропозицію, переказуючи обіцяну кількість Токена Б мейкеру, і натомість отримує заблокований Токен А. Це момент, коли обидві сторони виконують свою частину угоди.
Refund: Якщо мейкер змінює своє рішення або не знаходиться відповідний тейкер, він може скасувати пропозицію та повернути свій Токен А. Це схоже на повернення вашого предмета з банківської скриньки, якщо угода зривається.
Примітка: Якщо ви не знайомі з Anchor, вам варто почати з читання Anchor для початківців, щоб ознайомитися з основними концепціями, які ми будемо використовувати в цій програмі.
Встановлення
Почнімо зі створення нового робочого простору Anchor:
anchor init blueshift_anchor_escrow
cd blueshift_anchor_escrowДалі ми продовжуємо, активуючи init-if-needed у крейті anchor-lang та додаючи крейт anchor-spl:
cargo add anchor-lang --features init-if-needed
cargo add anchor-splОскільки ми використовуємо anchor-spl, нам також потрібно оновити файл programs/blueshift_anchor_escrow/Cargo.toml, щоб включити anchor-spl/idl-build у функцію idl-build.
Відкрийте Cargo.toml і ви побачите існуючий рядок idl-build, який виглядає так:
idl-build = ["anchor-lang/idl-build"]Змініть його, щоб додати також anchor-spl/idl-build:
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]Тепер ви можете відкрити новостворену папку і готові почати кодування!
Template
Цього разу, оскільки програма досить складна, ми розділимо її на невеликі, сфокусовані модулі замість того, щоб все запихати у lib.rs.
Структура папок буде приблизно такою:
src
├── instructions
│ ├── make.rs
│ ├── mod.rs
│ ├── refund.rs
│ └── take.rs
├── errors.rs
├── lib.rs
└── state.rsПри цьому lib.rs буде виглядати приблизно так:
use anchor_lang::prelude::*;
mod state;
mod errors;
mod instructions;
use instructions::*;
declare_id!("22222222222222222222222222222222222222222222");
#[program]
pub mod blueshift_anchor_escrow {
use super::*;
#[instruction(discriminator = 0)]
pub fn make(ctx: Context<Make>, seed: u64, receive: u64, amount: u64) -> Result<()> {
//...
}
#[instruction(discriminator = 1)]
pub fn take(ctx: Context<Take>) -> Result<()> {
//...
}
#[instruction(discriminator = 2)]
pub fn refund(ctx: Context<Refund>) -> Result<()> {
//...
}
}Як бачите, ми реалізували власний дискримінатор для інструкцій. Тому переконайтеся, що використовуєте версію anchor 0.31.0 або новішу.
State
Ми перейдемо до state.rs, де зберігаються всі дані для нашого Escrow. Для цього ми надамо йому власний дискримінатор і обгорнемо структуру в макрос #[account] ось так:
use anchor_lang::prelude::*;
#[derive(InitSpace)]
#[account(discriminator = 1)]
pub struct Escrow {
pub seed: u64,
pub maker: Pubkey,
pub mint_a: Pubkey,
pub mint_b: Pubkey,
pub receive: u64,
pub bump: u8,
}Що робить кожне поле:
seed: Випадкове число, яке використовується під час виведення сіда, щоб один мейкер міг відкрити кілька ескроу з однією і тією ж парою токенів; зберігається в блокчейні, щоб ми завжди могли повторно вивести PDA.
maker: Гаманець, який створив ескроу; потрібен для повернення коштів і отримання платежу.
mint_a і mint_b: Адреси SPL-мінтів для сторін "віддати" та "отримати" свопу.
receive: Скільки токенів B хоче отримати мейкер. (Баланс сховища сам показує, скільки токенів A було внесено, тому ми це не зберігаємо.)
bump: Кешований байт бампу; виведення його на льоту коштує обчислювальних ресурсів, тому ми зберігаємо його один раз.
Ми могли б додати більше інформації, але додаткові байти означають додаткову оренду. Зберігання лише необхідного мінімуму робить депозити дешевими, при цьому дозволяючи програмі застосовувати всі потрібні правила.
Ми завершуємо додаванням макросу #[derive(InitSpace)], щоб не розраховувати оренду цієї структури вручну.
Errors
Тепер ми можемо перейти до файлу errors.rs, де ми додамо деякі помилки, які будемо використовувати пізніше, ось так:
use anchor_lang::prelude::*;
#[error_code]
pub enum EscrowError {
#[msg("Invalid amount")]
InvalidAmount,
#[msg("Invalid maker")]
InvalidMaker,
#[msg("Invalid mint a")]
InvalidMintA,
#[msg("Invalid mint b")]
InvalidMintB,
}Кожен enum відповідає чіткому, зрозумілому для людини повідомленню, яке Anchor показуватиме щоразу, коли обмеження або require!() не виконуються.