# Gas и Treasury ## Gas модель Каждый вызов контракта (`CALL_CONTRACT` транзакция) тратит gas. Gas конвертируется в µT и списывается со счёта отправителя. ### Формула ``` fee = gas_used × gas_price ``` | Параметр | Значение | Откуда | |---------|---------|-------| | `gas_used` | ≤ `--gas` лимит | считается VM | | `gas_price` | 1 µT/gas по умолчанию | governance или константа | ### Лимит gas Задаётся в транзакции флагом `--gas`: ```bash client call-contract --method increment \ --gas 5000 \ --contract $CONTRACT_ID --key key.json --node http://localhost:8081 ``` Если VM израсходует весь лимит до конца исполнения — транзакция откатывается, gas не возвращается. ### Что стоит gas | Операция | Стоимость | |---------|---------| | Итерация цикла (`gas_tick`) | 1 unit | | Внешний вызов (`call_contract`) | gas подвызова | | Прочие инструкции | 0 (не инструментированы) | > TinyGo автоматически вставляет `gas_tick` в циклы. Бинарные WASM-контракты вызывают `gas_tick` вручную. ### Межконтрактный gas При вызове `dc.CallContract(...)`, подвызов получает budget = `Remaining()` родителя. После возврата, `gasUsed` подвызова списывается с родительского счётчика. ``` Родитель: limit=5000, used=200 → подвызов budget = 4800 → подвызов использовал 300 Родитель: used = 200 + 300 = 500 ``` ## Treasury Каждый контракт имеет **treasury** — специальный баланс, привязанный к контракту. ### Получить адрес treasury ```go treasury := dc.Treasury() // hex pubkey, 64 символа ``` ### Переводы через treasury Treasury используется как промежуточный эскроу: ```go // Принять деньги от caller → treasury dc.Transfer(dc.Caller(), dc.Treasury(), amount) // Отправить деньги из treasury → получателю dc.Transfer(dc.Treasury(), recipient, amount) ``` **Ограничение:** в `dc.Transfer(from, ...)`, `from` может быть только: 1. `dc.Caller()` — списать со счёта вызывающего 2. `dc.Treasury()` — списать с treasury контракта Контракт **не может** списывать деньги с произвольных адресов. ### Проверить баланс treasury ```go treasuryBal := dc.Balance(dc.Treasury()) ``` ### Паттерны использования treasury **1. Fee collector:** ```go const fee = 1000 // µT dc.Transfer(dc.Caller(), dc.Treasury(), fee) // Деньги остаются в treasury навсегда (или до явного вывода) ``` **2. Эскроу (lock → release):** ```go // lock: buyer → treasury dc.Transfer(buyer, dc.Treasury(), amount) // release: treasury → seller dc.Transfer(dc.Treasury(), seller, amount) // refund: treasury → buyer dc.Transfer(dc.Treasury(), buyer, amount) ``` **3. Prize pool (аукцион):** ```go // Принять ставку dc.Transfer(bidder, dc.Treasury(), bid) // Возврат предыдущей ставки dc.Transfer(dc.Treasury(), prevBidder, prevBid) // Финал: перевод победителю dc.Transfer(dc.Treasury(), seller, topBid) ``` ## Governance и динамический gas_price По умолчанию `gas_price = 1 µT/gas`. Это значение можно изменить через governance-контракт. ### Как нода читает gas_price ```go // blockchain/chain.go func (c *Chain) GetEffectiveGasPrice() uint64 { val, ok := c.GetGovParam("gas_price") if !ok { return GasPrice } // константа по умолчанию price, err := strconv.ParseUint(val, 10, 64) if err != nil { return GasPrice } return price } ``` `GetGovParam` читает `cstate::param:gas_price` напрямую из BadgerDB без VM-вызова. ### Изменить gas_price через governance ```bash # Предложить новое значение (5 µT/gas) client call-contract --method propose \ --arg gas_price --arg 5 \ --contract $GOV_ID --key /keys/node1.json \ --gas 10000 --node http://node1:8080 # Admin утверждает client call-contract --method approve \ --arg gas_price \ --contract $GOV_ID --key /keys/node1.json \ --gas 10000 --node http://node1:8080 ``` После approve все последующие `CALL_CONTRACT` транзакции будут использовать новую цену. ### Проверить текущий gas_price ```bash # Через контракт client call-contract --method get \ --arg gas_price \ --contract $GOV_ID --key key.json \ --gas 3000 --node http://localhost:8081 # Через REST (без транзакции) curl http://localhost:8081/api/contracts/$GOV_ID/state/param:gas_price ``` ## Константы ```go // blockchain/chain.go const ( GasPrice = uint64(1) // µT за 1 gas unit (default) ) // vm/host.go const ( maxContractCallDepth = 8 ) ``` ## Рекомендации по выбору --gas | Операция | Рекомендуемый gas | |---------|-----------------| | Простое чтение/запись state | 3 000 | | Регистрация / короткий метод | 5 000 | | Метод с несколькими state операциями | 10 000 | | Создание эскроу/аукциона | 20 000 – 30 000 | | Метод с межконтрактным вызовом | 30 000 – 50 000 | Gas, который не был потрачён, **не возвращается**. Завышенный лимит безопасен, но лишних денег не списывается больше `gas_used × gas_price`.