EOS系列 - 智能合約進階
1.eosio::same_payer
第一個只是一個常量表達式,可在修改多索引表的條目時使用。當使用eosio::same_payer
時,將要使用的新RAM(如果有的話)分配給已經爲表項支付的相同帳戶。
用法:
statstable.modify( st, eosio::same_payer, [&]( auto& s ) {
s.supply += quantity;
});
它在[multi_index.hpp
]中定義,只是空的name
(value:0),""_n
或name(0)
的常量表達式,某些開發人員仍在使用該表達式來表示相同的付款人。
2.get_first_receiver
,get_self()
在 contracts.hpp中定義的 get_self
和get_first_receiver
,返回正在運行的動作的執行上下文的一部分。 (在EOSIO.CDT 1.6中,get_first_receiver
的實現是爲了支持舊的get_code
,現在已棄用。)get_self
方法返回當前正在運行代碼的合同,而get_first_receiver
返回的帳戶位於動作源自。除非涉及通過require_recipient
發出的通知,否則這兩個帳戶是相同的。
例如,偵聽“ eosio.token”的“轉移”操作的通知,“ get_self()”將返回您的合同部署到的帳戶,而“ get_first_receiver()”將返回“ eosio.token”帳戶。這是因爲該操作是由向與您的合同帳戶有關的“ eosio.token”帳戶發送“轉移”操作的帳戶發起的。
用法:
[[eosio::on_notify("eosio.token::transfer")]] void cryptoship::transfer(name from, name to, const asset &quantity,
string memo) {
print(get_self()); // cryptoship
print(get_first_receiver()); // eosio.token
}
3.action_wrapper
對於許多用例,需要從合同代碼向另一個合同發送新操作。這是合同之間能夠積極溝通的唯一途徑。再說一次,有很多方法可以做到這一點,但是最優雅的方法之一是使用eosio::action_wrapper。它爲特定智能合約代碼的特定操作創建“操作模板”,然後可使用該模板來調用此操作。
第一個參數是動作名稱,第二個參數是動作的方法_declaration_。
用法
eosio.token
標頭在eosio.token.hpp header file中定義了其所有動作的動作包裝/include/eosio.token/eosio.token.hpp):
[[eosio::action]]
void create( name issuer,
asset maximum_supply);
[[eosio::action]]
void issue( name to, asset quantity, string memo );
[[eosio::action]]
void retire( asset quantity, string memo );
[[eosio::action]]
void transfer( name from,
name to,
asset quantity,
string memo );
// ...
using create_action = eosio::action_wrapper<"create"_n, &token::create>;
using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>;
using retire_action = eosio::action_wrapper<"retire"_n, &token::retire>;
using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>;
// ...
現在,我們可以通過包含此頭文件將內聯動作發送到任何eosio.token
合同。
要注意的重要一點是,只需要包含帶有聲明的頭文件。這意味着,即使對於實施細節未知的封閉源合同,也可以輕鬆編寫動作包裝。僅需要編寫聲明,即動作簽名,可以從ABI獲得。
使用
eosio-cpp
的-I
標誌包含頭文件的附加include目錄。
包含頭文件後,將發送** inline **傳輸操作,如下所示:
#include <eosio_token/include/eosio_token.hpp>
// can specify the contract to send the action to as first argument
token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n});
// transfer arguments are now passed as postional arguments
payout.send(get_self(), to, quantity, memo);
使用to_action
方法對延時交易也適用:
token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n});
transaction t{};
t.actions.emplace_back(payout.to_action(get_self(), to, quantity, memo));
t.delay_sec = 10;
t.send(0 /* sender id */, get_self(), false);
4. EOSIO時間類別time_point
, time_point_sec
, microseconds
EOSIO庫在time.hpp header中定義了兩個日期類。 time_point_sec
類是標準的UNIX時間戳,將1970年1月1日以來的秒數存儲在uint32_t
中,time_point
具有更精確的精度,將經過的微秒(不是毫秒)存儲在uint64_t
中。 。 在這兩個類別之間進行轉換很容易。
爲了與時間進行算術運算,人們使用了“微秒”類,該類帶有有用的輔助工具,例如“秒”,“分鐘”或“小時”。
用法
eosio::time_point tp = eosio::current_time_point();
eosio::time_point_sec tps = eosio::current_time_point();
eosio::microseconds micros = tp.time_since_epoch();
uint64_t count_micros = micros.count();
uint32_t count_seconds = tps.sec_since_epoch();
// no more 60*60*24*1e6
const auto MICROSECONDS_IN_DAY = hours(24);
count_micros += MICROSECONDS_IN_DAY;
// no more 60*60*24
count_seconds += hours(24).to_seconds();
eosio::time_point_sec lastGame = /* ... */;
check((eosio::time_point_sec)(current_time_point() + minutes(1)) >= lastGame,
"last game not finished");
使用microseconds
類及其幫助器可以避免使用諸如const auto SECONDS_PER_DAY = 60 * 60 * 24
之類的任何常量,從而使代碼更易於推理。