diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml
index 516531b1..544cba98 100644
--- a/build/StarcoinFramework/BuildInfo.yaml
+++ b/build/StarcoinFramework/BuildInfo.yaml
@@ -5,7 +5,7 @@ compiled_package_info:
StarcoinAssociation: "0x0000000000000000000000000a550c18"
StarcoinFramework: "0x00000000000000000000000000000001"
VMReserved: "0x00000000000000000000000000000000"
- source_digest: 88545469FF3E16035E05352124B98D1C4408DD2CFDC741EEE1C13000F9EBB4E6
+ source_digest: DEAD5E4489A0087D5ECEDCE704BCF29BF0E73B77A305D5324A9F453D3803B69B
build_flags:
dev_mode: false
test_mode: false
diff --git a/build/StarcoinFramework/abis/EasyGas/init_data_source.abi b/build/StarcoinFramework/abis/EasyGas/init_data_source.abi
new file mode 100644
index 00000000..90a0e498
Binary files /dev/null and b/build/StarcoinFramework/abis/EasyGas/init_data_source.abi differ
diff --git a/build/StarcoinFramework/abis/EasyGas/register.abi b/build/StarcoinFramework/abis/EasyGas/register.abi
new file mode 100644
index 00000000..aebcb5f8
Binary files /dev/null and b/build/StarcoinFramework/abis/EasyGas/register.abi differ
diff --git a/build/StarcoinFramework/abis/EasyGas/update.abi b/build/StarcoinFramework/abis/EasyGas/update.abi
new file mode 100644
index 00000000..19dc8d01
Binary files /dev/null and b/build/StarcoinFramework/abis/EasyGas/update.abi differ
diff --git a/build/StarcoinFramework/abis/EasyGas/withdraw_gas_fee_entry.abi b/build/StarcoinFramework/abis/EasyGas/withdraw_gas_fee_entry.abi
new file mode 100644
index 00000000..b6fcd89d
Binary files /dev/null and b/build/StarcoinFramework/abis/EasyGas/withdraw_gas_fee_entry.abi differ
diff --git a/build/StarcoinFramework/bytecode_modules/Account.mv b/build/StarcoinFramework/bytecode_modules/Account.mv
index f904edd0..a3e77c29 100644
Binary files a/build/StarcoinFramework/bytecode_modules/Account.mv and b/build/StarcoinFramework/bytecode_modules/Account.mv differ
diff --git a/build/StarcoinFramework/bytecode_modules/EasyGas.mv b/build/StarcoinFramework/bytecode_modules/EasyGas.mv
new file mode 100644
index 00000000..cf3a3a36
Binary files /dev/null and b/build/StarcoinFramework/bytecode_modules/EasyGas.mv differ
diff --git a/build/StarcoinFramework/bytecode_modules/EasyGasScript.mv b/build/StarcoinFramework/bytecode_modules/EasyGasScript.mv
new file mode 100644
index 00000000..260e57f8
Binary files /dev/null and b/build/StarcoinFramework/bytecode_modules/EasyGasScript.mv differ
diff --git a/build/StarcoinFramework/bytecode_modules/GenesisSignerCapability.mv b/build/StarcoinFramework/bytecode_modules/GenesisSignerCapability.mv
index c7e787b2..0b2013c1 100644
Binary files a/build/StarcoinFramework/bytecode_modules/GenesisSignerCapability.mv and b/build/StarcoinFramework/bytecode_modules/GenesisSignerCapability.mv differ
diff --git a/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv b/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv
index a9bbbad6..1d9e31fe 100644
Binary files a/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv and b/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv differ
diff --git a/build/StarcoinFramework/bytecode_modules/TransactionManager.mv b/build/StarcoinFramework/bytecode_modules/TransactionManager.mv
index 04b09867..44f482f8 100644
Binary files a/build/StarcoinFramework/bytecode_modules/TransactionManager.mv and b/build/StarcoinFramework/bytecode_modules/TransactionManager.mv differ
diff --git a/build/StarcoinFramework/docs/Account.md b/build/StarcoinFramework/docs/Account.md
index 8dd831d9..40d600a1 100644
--- a/build/StarcoinFramework/docs/Account.md
+++ b/build/StarcoinFramework/docs/Account.md
@@ -41,6 +41,9 @@ The module for the account resource that governs every account
- [Function `deposit`](#0x1_Account_deposit)
- [Function `deposit_with_metadata`](#0x1_Account_deposit_with_metadata)
- [Function `deposit_to_balance`](#0x1_Account_deposit_to_balance)
+- [Function `withdraw_from_balance_v2`](#0x1_Account_withdraw_from_balance_v2)
+- [Function `set_sequence_number`](#0x1_Account_set_sequence_number)
+- [Function `set_authentication_key`](#0x1_Account_set_authentication_key)
- [Function `withdraw_from_balance`](#0x1_Account_withdraw_from_balance)
- [Function `withdraw`](#0x1_Account_withdraw)
- [Function `withdraw_with_metadata`](#0x1_Account_withdraw_with_metadata)
@@ -80,9 +83,13 @@ The module for the account resource that governs every account
- [Function `key_rotation_capability_address`](#0x1_Account_key_rotation_capability_address)
- [Function `exists_at`](#0x1_Account_exists_at)
- [Function `is_dummy_auth_key`](#0x1_Account_is_dummy_auth_key)
+- [Function `is_dummy_auth_key_v2`](#0x1_Account_is_dummy_auth_key_v2)
- [Function `txn_prologue`](#0x1_Account_txn_prologue)
+- [Function `txn_prologue_v2`](#0x1_Account_txn_prologue_v2)
- [Function `txn_epilogue`](#0x1_Account_txn_epilogue)
+- [Function `transaction_fee_simulate`](#0x1_Account_transaction_fee_simulate)
- [Function `txn_epilogue_v2`](#0x1_Account_txn_epilogue_v2)
+- [Function `txn_epilogue_v3`](#0x1_Account_txn_epilogue_v3)
- [Function `remove_zero_balance_entry`](#0x1_Account_remove_zero_balance_entry)
- [Function `remove_zero_balance`](#0x1_Account_remove_zero_balance)
- [Function `make_event_store_if_not_exist`](#0x1_Account_make_event_store_if_not_exist)
@@ -95,6 +102,7 @@ The module for the account resource that governs every account
use 0x1::Errors;
use 0x1::Event;
use 0x1::Hash;
+use 0x1::Math;
use 0x1::Option;
use 0x1::STC;
use 0x1::Signer;
@@ -1570,6 +1578,81 @@ Helper to deposit amount
to the given account balance
+
+
+
+
+## Function `withdraw_from_balance_v2`
+
+
+
+
-fun withdraw_from_balance<TokenType: store>(balance: &mut Account::Balance<TokenType>, amount: u128): Token::Token<TokenType>
+public fun withdraw_from_balance<TokenType: store>(balance: &mut Account::Balance<TokenType>, amount: u128): Token::Token<TokenType>
@@ -1588,7 +1671,7 @@ Helper to withdraw amount
from the given account balance and return
Implementation
-fun withdraw_from_balance<TokenType: store>(balance: &mut Balance<TokenType>, amount: u128): Token<TokenType>{
+public fun withdraw_from_balance<TokenType: store>(balance: &mut Balance<TokenType>, amount: u128): Token<TokenType>{
Token::withdraw(&mut balance.token, amount)
}
@@ -3120,6 +3203,31 @@ Checks if an account exists at check_addr
+
+
+
+
+## Function `is_dummy_auth_key_v2`
+
+
+
+public fun is_dummy_auth_key_v2(account: address): bool
+
+
+
+
+
+Implementation
+
+
+public fun is_dummy_auth_key_v2(account: address): bool acquires Account {
+ let account = borrow_global_mut<Account>(account);
+ account.authentication_key == DUMMY_AUTH_KEY
+}
+
+
+
+
@@ -3149,6 +3257,64 @@ It verifies:
txn_authentication_key_preimage: vector<u8>,
txn_gas_price: u64,
txn_max_gas_units: u64,
+) acquires Account, Balance {
+ txn_prologue_v2<TokenType>(
+ account,
+ txn_sender,
+ txn_sequence_number,
+ txn_authentication_key_preimage,
+ txn_gas_price,
+ txn_max_gas_units,
+ 1,
+ 1,
+ )
+}
+
+
+
+
+
+
+
+Specification
+
+
+
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<Account>(txn_sender);
+aborts_if global<Account>(txn_sender).authentication_key == DUMMY_AUTH_KEY && Authenticator::spec_derived_address(Hash::sha3_256(txn_authentication_key_preimage)) != txn_sender;
+aborts_if global<Account>(txn_sender).authentication_key != DUMMY_AUTH_KEY && Hash::sha3_256(txn_authentication_key_preimage) != global<Account>(txn_sender).authentication_key;
+aborts_if txn_sequence_number < global<Account>(txn_sender).sequence_number;
+
+
+
+
+
+
+
+
+## Function `txn_prologue_v2`
+
+
+
+public fun txn_prologue_v2<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, stc_price: u128, stc_price_scaling: u128)
+
+
+
+
+
+Implementation
+
+
+public fun txn_prologue_v2<TokenType: store>(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector<u8>,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ stc_price: u128,
+ stc_price_scaling: u128
) acquires Account, Balance {
CoreAddresses::assert_genesis_address(account);
@@ -3173,54 +3339,29 @@ It verifies:
Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
);
};
-
// Check that the account has enough balance for all of the gas
+ let (max_transaction_fee_stc,max_transaction_fee_token) = transaction_fee_simulate(txn_gas_price,txn_max_gas_units,0, stc_price, stc_price_scaling);
assert!(
- (txn_gas_price as u128) * (txn_max_gas_units as u128) <= MAX_U64,
+ max_transaction_fee_stc <= MAX_U64,
Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT),
);
- let max_transaction_fee = txn_gas_price * txn_max_gas_units;
- if (max_transaction_fee > 0) {
- assert!(
- STC::is_stc<TokenType>(),
- Errors::invalid_argument(EBAD_TRANSACTION_FEE_TOKEN)
- );
-
- let balance_amount = balance<TokenType>(txn_sender);
- assert!(balance_amount >= (max_transaction_fee as u128), Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
-
+ if (max_transaction_fee_stc > 0) {
assert!(
(txn_sequence_number as u128) < MAX_U64,
Errors::limit_exceeded(EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG)
);
+ let balance_amount_token = balance<TokenType>(txn_sender);
+ assert!(balance_amount_token >= max_transaction_fee_token, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ if (!is_stc<TokenType>()){
+ let balance_amount_stc= balance<STC>(CoreAddresses::GENESIS_ADDRESS());
+ assert!(balance_amount_stc >= max_transaction_fee_stc, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ }
};
-
// Check that the transaction sequence number matches the sequence number of the account
assert!(txn_sequence_number >= sender_account.sequence_number, Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD));
assert!(txn_sequence_number == sender_account.sequence_number, Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW));
-}
-
-
-
-
-
-
-
-Specification
-
-
-aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-aborts_if !exists<Account>(txn_sender);
-aborts_if global<Account>(txn_sender).authentication_key == DUMMY_AUTH_KEY && Authenticator::spec_derived_address(Hash::sha3_256(txn_authentication_key_preimage)) != txn_sender;
-aborts_if global<Account>(txn_sender).authentication_key != DUMMY_AUTH_KEY && Hash::sha3_256(txn_authentication_key_preimage) != global<Account>(txn_sender).authentication_key;
-aborts_if txn_gas_price * txn_max_gas_units > max_u64();
-aborts_if txn_gas_price * txn_max_gas_units > 0 && !exists<Balance<TokenType>>(txn_sender);
-aborts_if txn_gas_price * txn_max_gas_units > 0 && Token::spec_token_code<TokenType>() != Token::spec_token_code<STC>();
-aborts_if txn_gas_price * txn_max_gas_units > 0 && global<Balance<TokenType>>(txn_sender).token.value < txn_gas_price * txn_max_gas_units;
-aborts_if txn_gas_price * txn_max_gas_units > 0 && txn_sequence_number >= max_u64();
-aborts_if txn_sequence_number < global<Account>(txn_sender).sequence_number;
-aborts_if txn_sequence_number != global<Account>(txn_sender).sequence_number;
+}
@@ -3252,7 +3393,7 @@ It collects gas and bumps the sequence number
txn_max_gas_units: u64,
gas_units_remaining: u64,
) acquires Account, Balance {
- txn_epilogue_v2<TokenType>(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining)
+ txn_epilogue_v3<TokenType>(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining,1,1)
}
@@ -3270,6 +3411,39 @@ It collects gas and bumps the sequence number
+
+
+
+
+## Function `transaction_fee_simulate`
+
+
+
+public fun transaction_fee_simulate(txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, stc_price: u128, stc_price_scaling: u128): (u128, u128)
+
+
+
+
+
+Implementation
+
+
+public fun transaction_fee_simulate(
+ txn_gas_price:u64,
+ txn_max_gas_units: u64,
+ gas_units_remaining:u64,
+ stc_price: u128,
+ stc_price_scaling: u128,
+): (u128, u128){
+ let transaction_fee_stc =(txn_gas_price * (txn_max_gas_units - gas_units_remaining) as u128);
+ let transaction_fee_token= Math::mul_div((transaction_fee_stc as u128), stc_price, stc_price_scaling);
+ transaction_fee_token = if (transaction_fee_token == 0 && transaction_fee_stc > 0 ) { 1 } else { transaction_fee_token};
+ (transaction_fee_stc, transaction_fee_token)
+}
+
+
+
+
@@ -3298,32 +3472,14 @@ It collects gas and bumps the sequence number
txn_max_gas_units: u64,
gas_units_remaining: u64,
) acquires Account, Balance {
- CoreAddresses::assert_genesis_address(account);
-
- // Load the transaction sender's account and balance resources
- let sender_account = borrow_global_mut<Account>(txn_sender);
- let sender_balance = borrow_global_mut<Balance<TokenType>>(txn_sender);
-
- // Charge for gas
- let transaction_fee_amount =(txn_gas_price * (txn_max_gas_units - gas_units_remaining) as u128);
- assert!(
- balance_for(sender_balance) >= transaction_fee_amount,
- Errors::limit_exceeded(EINSUFFICIENT_BALANCE)
- );
-
- // Bump the sequence number
- sender_account.sequence_number = txn_sequence_number + 1;
- // Set auth key when user send transaction first.
- if (is_dummy_auth_key(sender_account) && !Vector::is_empty(&txn_authentication_key_preimage)){
- sender_account.authentication_key = Hash::sha3_256(txn_authentication_key_preimage);
- };
- if (transaction_fee_amount > 0) {
- let transaction_fee = withdraw_from_balance(
- sender_balance,
- transaction_fee_amount
- );
- TransactionFee::pay_fee(transaction_fee);
- };
+ txn_epilogue_v3<TokenType>(
+ account,
+ txn_sender,
+ txn_sequence_number,
+ txn_authentication_key_preimage,
+ txn_gas_price,
+ txn_max_gas_units,
+ gas_units_remaining,1,1)
}
@@ -3346,11 +3502,93 @@ It collects gas and bumps the sequence number
aborts_if global<Balance<TokenType>>(txn_sender).token.value < transaction_fee_amount;
aborts_if txn_sequence_number + 1 > max_u64();
aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
- global<Balance<TokenType>>(txn_sender).token.value < txn_gas_price * (txn_max_gas_units - gas_units_remaining);
+ global<Balance<TokenType>>(txn_sender).token.value < txn_gas_price * (txn_max_gas_units - gas_units_remaining);
aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
- !exists<TransactionFee::TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS());
+ !exists<TransactionFee::TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS());
aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
- global<TransactionFee::TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS()).fee.value + txn_gas_price * (txn_max_gas_units - gas_units_remaining) > max_u128();
+ global<TransactionFee::TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS()).fee.value + txn_gas_price * (txn_max_gas_units - gas_units_remaining) > max_u128();
+
+
+
+
+
+pragma verify = false;
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<Account>(txn_sender);
+aborts_if !exists<Balance<TokenType>>(txn_sender);
+aborts_if txn_sequence_number + 1 > max_u64();
+aborts_if !exists<Balance<TokenType>>(txn_sender);
+aborts_if txn_max_gas_units < gas_units_remaining;
+
+
+
+
+
+
+
+
+## Function `txn_epilogue_v3`
+
+The epilogue is invoked at the end of transactions.
+It collects gas and bumps the sequence number
+
+
+public fun txn_epilogue_v3<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, stc_price: u128, stc_price_scaling: u128)
+
+
+
+
+
+Implementation
+
+
+public fun txn_epilogue_v3<TokenType: store>(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector<u8>,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ gas_units_remaining: u64,
+ stc_price: u128,
+ stc_price_scaling: u128,
+) acquires Account, Balance {
+ CoreAddresses::assert_genesis_address(account);
+ // Charge for gas
+ let (transaction_fee_amount_stc,transaction_fee_amount_token) = transaction_fee_simulate(
+ txn_gas_price,
+ txn_max_gas_units,
+ gas_units_remaining,
+ stc_price,
+ stc_price_scaling);
+ assert!(
+ balance<TokenType>(txn_sender) >= transaction_fee_amount_token,
+ Errors::limit_exceeded(EINSUFFICIENT_BALANCE)
+ );
+ if (!is_stc<TokenType>()){
+ let genesis_balance_amount_stc=balance<STC>(CoreAddresses::GENESIS_ADDRESS());
+ assert!(genesis_balance_amount_stc >= transaction_fee_amount_stc,
+ Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT)
+ );
+ };
+ // Load the transaction sender's account and balance resources
+ let sender_account = borrow_global_mut<Account>(txn_sender);
+ // Bump the sequence number
+ sender_account.sequence_number = txn_sequence_number + 1;
+ // Set auth key when user send transaction first.
+ if (is_dummy_auth_key(sender_account) && !Vector::is_empty(&txn_authentication_key_preimage)){
+ sender_account.authentication_key = Hash::sha3_256(txn_authentication_key_preimage);
+ };
+ if (transaction_fee_amount_stc > 0) {
+ let transaction_fee_token = withdraw_from_balance(
+ borrow_global_mut<Balance<TokenType>>(txn_sender),
+ transaction_fee_amount_token
+ );
+ deposit_to_balance(borrow_global_mut<Balance<TokenType>>(CoreAddresses::GENESIS_ADDRESS()), transaction_fee_token);
+ let stc_fee_token = withdraw_from_balance(borrow_global_mut<Balance<STC>>(CoreAddresses::GENESIS_ADDRESS()), transaction_fee_amount_stc);
+ TransactionFee::pay_fee(stc_fee_token);
+ };
+}
diff --git a/build/StarcoinFramework/docs/EasyGas.md b/build/StarcoinFramework/docs/EasyGas.md
new file mode 100644
index 00000000..c0faf26a
--- /dev/null
+++ b/build/StarcoinFramework/docs/EasyGas.md
@@ -0,0 +1,113 @@
+
+
+
+# Module `0x1::EasyGasScript`
+
+
+
+- [Function `register`](#0x1_EasyGasScript_register)
+- [Function `init_data_source`](#0x1_EasyGasScript_init_data_source)
+- [Function `update`](#0x1_EasyGasScript_update)
+- [Function `withdraw_gas_fee_entry`](#0x1_EasyGasScript_withdraw_gas_fee_entry)
+
+
+use 0x1::EasyGas;
+
+
+
+
+
+
+## Function `register`
+
+
+
+public entry fun register<TokenType: store>(sender: signer, precision: u8)
+
+
+
+
+
+Implementation
+
+
+public entry fun register<TokenType: store>(sender: signer, precision: u8) {
+ EasyGas::register_oracle<TokenType>(&sender, precision)
+}
+
+
+
+
+
+
+
+
+## Function `init_data_source`
+
+
+
+public entry fun init_data_source<TokenType: store>(sender: signer, init_value: u128)
+
+
+
+
+
+Implementation
+
+
+public entry fun init_data_source<TokenType: store>(sender: signer, init_value: u128) {
+ EasyGas::init_oracle_source<TokenType>(&sender, init_value);
+}
+
+
+
+
+
+
+
+
+## Function `update`
+
+
+
+public entry fun update<TokenType: store>(sender: signer, value: u128)
+
+
+
+
+
+Implementation
+
+
+public entry fun update<TokenType: store>(sender: signer, value: u128) {
+ EasyGas::update_oracle<TokenType>(&sender, value)
+}
+
+
+
+
+
+
+
+
+## Function `withdraw_gas_fee_entry`
+
+
+
+public entry fun withdraw_gas_fee_entry<TokenType: store>(sender: signer, amount: u128)
+
+
+
+
+
+Implementation
+
+
+public entry fun withdraw_gas_fee_entry<TokenType: store>(sender: signer, amount: u128) {
+ EasyGas::withdraw_gas_fee<TokenType>(&sender, amount);
+}
+
+
+
+
+
diff --git a/build/StarcoinFramework/docs/README.md b/build/StarcoinFramework/docs/README.md
index 8810b9b2..3f151f78 100644
--- a/build/StarcoinFramework/docs/README.md
+++ b/build/StarcoinFramework/docs/README.md
@@ -35,6 +35,8 @@ This is the root document for the Move StarcoinFramework module documentation. T
- [`0x1::DummyToken`](DummyToken.md#0x1_DummyToken)
- [`0x1::DummyTokenScripts`](DummyToken.md#0x1_DummyTokenScripts)
- [`0x1::EVMAddress`](Signature.md#0x1_EVMAddress)
+- [`0x1::EasyGas`](EasyGas.md#0x1_EasyGas)
+- [`0x1::EasyGasScript`](EasyGas.md#0x1_EasyGasScript)
- [`0x1::EmptyScripts`](EmptyScripts.md#0x1_EmptyScripts)
- [`0x1::Epoch`](Epoch.md#0x1_Epoch)
- [`0x1::Errors`](Errors.md#0x1_Errors)
diff --git a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md
index 58dfb3ff..a757b9ba 100644
--- a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md
+++ b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md
@@ -25,6 +25,7 @@ The module for StdlibUpgrade init scripts
use 0x1::Collection;
use 0x1::Config;
use 0x1::CoreAddresses;
+use 0x1::EasyGas;
use 0x1::GenesisNFT;
use 0x1::GenesisSignerCapability;
use 0x1::LanguageVersion;
@@ -339,6 +340,10 @@ deprecated, use do_upgrade_from_v6_to_v7_with_language_version
.
public fun do_upgrade_from_v11_to_v12(sender: &signer) {
{
+ EasyGas::initialize(sender,
+ @0x8c109349c6bd91411d6bc962e080c4a3,
+ b"STAR",b"STAR",
+ @0x8c109349c6bd91411d6bc962e080c4a3);
Block::checkpoints_init(sender);
};
}
diff --git a/build/StarcoinFramework/docs/TransactionManager.md b/build/StarcoinFramework/docs/TransactionManager.md
index f463b735..8cf62406 100644
--- a/build/StarcoinFramework/docs/TransactionManager.md
+++ b/build/StarcoinFramework/docs/TransactionManager.md
@@ -13,16 +13,21 @@
- [Function `epilogue`](#0x1_TransactionManager_epilogue)
- [Function `epilogue_v2`](#0x1_TransactionManager_epilogue_v2)
- [Function `block_prologue`](#0x1_TransactionManager_block_prologue)
+- [Function `txn_prologue_v2`](#0x1_TransactionManager_txn_prologue_v2)
+- [Function `txn_epilogue_v3`](#0x1_TransactionManager_txn_epilogue_v3)
- [Module Specification](#@Module_Specification_1)
use 0x1::Account;
+use 0x1::Authenticator;
use 0x1::Block;
use 0x1::BlockReward;
use 0x1::ChainId;
use 0x1::CoreAddresses;
+use 0x1::EasyGas;
use 0x1::Epoch;
use 0x1::Errors;
+use 0x1::Hash;
use 0x1::PackageTxnManager;
use 0x1::STC;
use 0x1::Signer;
@@ -31,6 +36,7 @@
use 0x1::TransactionFee;
use 0x1::TransactionPublishOption;
use 0x1::TransactionTimeout;
+use 0x1::Vector;
@@ -40,6 +46,24 @@
## Constants
+
+
+
+
+const MAX_U64: u128 = 18446744073709551615;
+
+
+
+
+
+
+
+
+const EDEPRECATED_FUNCTION: u64 = 19;
+
+
+
+
@@ -49,6 +73,150 @@
+
+
+
+
+const EADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 105;
+
+
+
+
+
+
+
+
+const EADDRESS_PUBLIC_KEY_INCONSISTENT: u64 = 104;
+
+
+
+
+
+
+
+
+const EBAD_TRANSACTION_FEE_TOKEN: u64 = 18;
+
+
+
+
+
+
+
+
+const ECOIN_DEPOSIT_IS_ZERO: u64 = 15;
+
+
+
+
+
+
+
+
+const EINSUFFICIENT_BALANCE: u64 = 10;
+
+
+
+
+
+
+
+
+const EKEY_ROTATION_CAPABILITY_ALREADY_EXTRACTED: u64 = 103;
+
+
+
+
+
+
+
+
+const EMALFORMED_AUTHENTICATION_KEY: u64 = 102;
+
+
+
+
+
+
+
+
+const EPROLOGUE_CANT_PAY_GAS_DEPOSIT: u64 = 4;
+
+
+
+
+
+
+
+
+const EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY: u64 = 1;
+
+
+
+
+
+
+
+
+const EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG: u64 = 9;
+
+
+
+
+
+
+
+
+const EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW: u64 = 3;
+
+
+
+
+
+
+
+
+const EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD: u64 = 2;
+
+
+
+
+
+
+
+
+const EPROLOGUE_SIGNER_ALREADY_DELEGATED: u64 = 200;
+
+
+
+
+
+
+
+
+const ERR_SIGNER_ALREADY_DELEGATED: u64 = 107;
+
+
+
+
+
+
+
+
+const ERR_TOKEN_NOT_ACCEPT: u64 = 106;
+
+
+
+
+
+
+
+
+const EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED: u64 = 101;
+
+
+
+
@@ -153,13 +321,21 @@ It verifies:
// Check that the chain ID stored on-chain matches the chain ID
// specified by the transaction
assert!(ChainId::get() == chain_id, Errors::invalid_argument(EPROLOGUE_BAD_CHAIN_ID));
- Account::txn_prologue<TokenType>(
+ let (stc_price,scaling_factor)= if (!STC::is_stc<TokenType>()){
+ (EasyGas::gas_oracle_read<TokenType>(), EasyGas::get_scaling_factor<TokenType>())
+ }else{
+ (1,1)
+ };
+
+ txn_prologue_v2<TokenType>(
&account,
txn_sender,
txn_sequence_number,
txn_authentication_key_preimage,
txn_gas_price,
txn_max_gas_units,
+ stc_price,
+ scaling_factor,
);
assert!(
TransactionTimeout::is_valid_transaction_timestamp(txn_expiration_time),
@@ -209,8 +385,6 @@ It verifies:
include Timestamp::AbortsIfTimestampNotExists;
include Block::AbortsIfBlockMetadataNotExist;
aborts_if txn_gas_price * txn_max_gas_units > 0 && !exists<Account::Balance<TokenType>>(txn_sender);
-aborts_if txn_gas_price * txn_max_gas_units > 0 && StarcoinFramework::Token::spec_token_code<TokenType>() != StarcoinFramework::Token::spec_token_code<STC>();
-aborts_if txn_gas_price * txn_max_gas_units > 0 && global<Account::Balance<TokenType>>(txn_sender).token.value < txn_gas_price * txn_max_gas_units;
aborts_if txn_gas_price * txn_max_gas_units > 0 && txn_sequence_number >= max_u64();
aborts_if txn_sequence_number < global<Account::Account>(txn_sender).sequence_number;
aborts_if txn_sequence_number != global<Account::Account>(txn_sender).sequence_number;
@@ -322,7 +496,13 @@ It collects gas and bumps the sequence number
success: bool,
) {
CoreAddresses::assert_genesis_address(&account);
- Account::txn_epilogue_v2<TokenType>(
+ let (stc_price,scaling_factor) =
+ if (!STC::is_stc<TokenType>()){
+ (EasyGas::gas_oracle_read<TokenType>(), EasyGas::get_scaling_factor<TokenType>())
+ }else{
+ (1,1)
+ };
+ txn_epilogue_v3<TokenType>(
&account,
txn_sender,
txn_sequence_number,
@@ -330,6 +510,8 @@ It collects gas and bumps the sequence number
txn_gas_price,
txn_max_gas_units,
gas_units_remaining,
+ stc_price,
+ scaling_factor
);
if (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE) {
PackageTxnManager::package_txn_epilogue(
@@ -413,6 +595,177 @@ The runtime always runs this before executing the transactions in a block.
+
+
+
+
+## Function `txn_prologue_v2`
+
+
+
+public fun txn_prologue_v2<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, stc_price: u128, stc_price_scaling: u128)
+
+
+
+
+
+Implementation
+
+
+public fun txn_prologue_v2<TokenType: store>(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector<u8>,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ stc_price: u128,
+ stc_price_scaling: u128
+) {
+ CoreAddresses::assert_genesis_address(account);
+
+ // Verify that the transaction sender's account exists
+ assert!(exists_at(txn_sender), Errors::requires_address(EPROLOGUE_ACCOUNT_DOES_NOT_EXIST));
+ // Verify the account has not delegate its signer cap.
+ assert!(!is_signer_delegated(txn_sender), Errors::invalid_state(EPROLOGUE_SIGNER_ALREADY_DELEGATED));
+
+ // Load the transaction sender's account
+ //let sender_account = borrow_global_mut<Account>(txn_sender);
+ if (Account::is_dummy_auth_key_v2(txn_sender)){
+ // if sender's auth key is empty, use address as auth key for check transaction.
+ assert!(
+ Authenticator::derived_address(Hash::sha3_256(txn_authentication_key_preimage)) == txn_sender,
+ Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
+ );
+ }else{
+ // Check that the hash of the transaction's public key matches the account's auth key
+ assert!(
+ Hash::sha3_256(txn_authentication_key_preimage) == Account::authentication_key(txn_sender),
+ Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
+ );
+ };
+ // Check that the account has enough balance for all of the gas
+ let (max_transaction_fee_stc,max_transaction_fee_token) = transaction_fee_simulate(txn_gas_price,txn_max_gas_units,0, stc_price, stc_price_scaling);
+ assert!(
+ max_transaction_fee_stc <= MAX_U64,
+ Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT),
+ );
+ if (max_transaction_fee_stc > 0) {
+ assert!(
+ (txn_sequence_number as u128) < MAX_U64,
+ Errors::limit_exceeded(EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG)
+ );
+ let balance_amount_token = balance<TokenType>(txn_sender);
+ assert!(balance_amount_token >= max_transaction_fee_token, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ if (!is_stc<TokenType>()){
+ let gas_fee_address = EasyGas::get_gas_fee_address();
+ let balance_amount_stc= balance<STC>(gas_fee_address);
+ assert!(balance_amount_stc >= max_transaction_fee_stc, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ }
+ };
+ // Check that the transaction sequence number matches the sequence number of the account
+ assert!(txn_sequence_number >= Account::sequence_number(txn_sender), Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD));
+ assert!(txn_sequence_number == Account::sequence_number(txn_sender), Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW));
+
+}
+
+
+
+
+
+
+
+
+## Function `txn_epilogue_v3`
+
+The epilogue is invoked at the end of transactions.
+It collects gas and bumps the sequence number
+
+
+public fun txn_epilogue_v3<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, stc_price: u128, stc_price_scaling: u128)
+
+
+
+
+
+Implementation
+
+
+public fun txn_epilogue_v3<TokenType: store>(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector<u8>,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ gas_units_remaining: u64,
+ stc_price: u128,
+ stc_price_scaling: u128,
+) {
+ CoreAddresses::assert_genesis_address(account);
+ // Charge for gas
+ let (transaction_fee_amount_stc,transaction_fee_amount_token) = transaction_fee_simulate(
+ txn_gas_price,
+ txn_max_gas_units,
+ gas_units_remaining,
+ stc_price,
+ stc_price_scaling);
+ assert!(
+ balance<TokenType>(txn_sender) >= transaction_fee_amount_token,
+ Errors::limit_exceeded(EINSUFFICIENT_BALANCE)
+ );
+
+ if (!is_stc<TokenType>()){
+ let gas_fee_address = EasyGas::get_gas_fee_address();
+ let genesis_balance_amount_stc=balance<STC>(gas_fee_address);
+ assert!(genesis_balance_amount_stc >= transaction_fee_amount_stc,
+ Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT)
+ );
+ };
+ // Bump the sequence number
+ Account::set_sequence_number(txn_sender,txn_sequence_number+1);
+ // Set auth key when user send transaction first.
+ if (Account::is_dummy_auth_key_v2(txn_sender) && !Vector::is_empty(&txn_authentication_key_preimage)){
+ Account::set_authentication_key(txn_sender, Hash::sha3_256(txn_authentication_key_preimage));
+ };
+
+ if (transaction_fee_amount_stc > 0) {
+ let transaction_fee_token = Account::withdraw_from_balance_v2<TokenType>(
+ txn_sender,
+ transaction_fee_amount_token
+ );
+ if(!is_stc<TokenType>()) {
+ let gas_fee_address = EasyGas::get_gas_fee_address();
+ Account::deposit<TokenType>(gas_fee_address, transaction_fee_token);
+ let stc_fee_token = Account::withdraw_from_balance_v2<STC>(gas_fee_address, transaction_fee_amount_stc);
+ TransactionFee::pay_fee(stc_fee_token);
+ }else{
+ TransactionFee::pay_fee(transaction_fee_token);
+ }
+ };
+}
+
+
+
+
+
+
+
+Specification
+
+
+
+pragma verify = false;
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<Account>(txn_sender);
+aborts_if !exists<Balance<TokenType>>(txn_sender);
+aborts_if txn_sequence_number + 1 > max_u64();
+aborts_if !exists<Balance<TokenType>>(txn_sender);
+aborts_if txn_max_gas_units < gas_units_remaining;
+
+
+
+
diff --git a/build/StarcoinFramework/source_maps/Account.mvsm b/build/StarcoinFramework/source_maps/Account.mvsm
index a732ac0a..afe77bad 100644
Binary files a/build/StarcoinFramework/source_maps/Account.mvsm and b/build/StarcoinFramework/source_maps/Account.mvsm differ
diff --git a/build/StarcoinFramework/source_maps/EasyGas.mvsm b/build/StarcoinFramework/source_maps/EasyGas.mvsm
new file mode 100644
index 00000000..e040ec35
Binary files /dev/null and b/build/StarcoinFramework/source_maps/EasyGas.mvsm differ
diff --git a/build/StarcoinFramework/source_maps/EasyGasScript.mvsm b/build/StarcoinFramework/source_maps/EasyGasScript.mvsm
new file mode 100644
index 00000000..02e6e053
Binary files /dev/null and b/build/StarcoinFramework/source_maps/EasyGasScript.mvsm differ
diff --git a/build/StarcoinFramework/source_maps/GenesisSignerCapability.mvsm b/build/StarcoinFramework/source_maps/GenesisSignerCapability.mvsm
index 70bc337e..41be8a29 100644
Binary files a/build/StarcoinFramework/source_maps/GenesisSignerCapability.mvsm and b/build/StarcoinFramework/source_maps/GenesisSignerCapability.mvsm differ
diff --git a/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm b/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm
index 104c652b..7f06a692 100644
Binary files a/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm and b/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm differ
diff --git a/build/StarcoinFramework/source_maps/TransactionManager.mvsm b/build/StarcoinFramework/source_maps/TransactionManager.mvsm
index 54e1151c..6f75505a 100644
Binary files a/build/StarcoinFramework/source_maps/TransactionManager.mvsm and b/build/StarcoinFramework/source_maps/TransactionManager.mvsm differ
diff --git a/integration-tests/account/txn_prologue_and_epilogue.exp b/integration-tests/account/txn_prologue_and_epilogue.exp
index c8f0ae6c..e771d6b8 100644
--- a/integration-tests/account/txn_prologue_and_epilogue.exp
+++ b/integration-tests/account/txn_prologue_and_epilogue.exp
@@ -1,14 +1,14 @@
-processed 12 tasks
+processed 16 tasks
-task 3 'run'. lines 8-23:
+task 3 'run'. lines 7-28:
{
- "gas_used": 401102,
+ "gas_used": 527547,
"status": "Executed"
}
-task 4 'run'. lines 27-59:
+task 4 'run'. lines 30-64:
{
- "gas_used": 91881,
+ "gas_used": 93051,
"status": {
"MoveAbort": {
"location": {
@@ -22,9 +22,9 @@ task 4 'run'. lines 27-59:
}
}
-task 5 'run'. lines 63-90:
+task 5 'run'. lines 68-94:
{
- "gas_used": 168011,
+ "gas_used": 169688,
"status": {
"MoveAbort": {
"location": {
@@ -38,9 +38,9 @@ task 5 'run'. lines 63-90:
}
}
-task 6 'run'. lines 94-122:
+task 6 'run'. lines 98-126:
{
- "gas_used": 140032,
+ "gas_used": 146018,
"status": {
"MoveAbort": {
"location": {
@@ -54,9 +54,9 @@ task 6 'run'. lines 94-122:
}
}
-task 7 'run'. lines 126-156:
+task 7 'run'. lines 130-160:
{
- "gas_used": 174473,
+ "gas_used": 193967,
"status": {
"MoveAbort": {
"location": {
@@ -70,15 +70,15 @@ task 7 'run'. lines 126-156:
}
}
-task 8 'run'. lines 160-205:
+task 8 'run'. lines 164-210:
{
- "gas_used": 239024,
+ "gas_used": 319957,
"status": "Executed"
}
-task 9 'run'. lines 209-239:
+task 9 'run'. lines 214-244:
{
- "gas_used": 174341,
+ "gas_used": 193835,
"status": {
"MoveAbort": {
"location": {
@@ -92,9 +92,9 @@ task 9 'run'. lines 209-239:
}
}
-task 10 'run'. lines 243-274:
+task 10 'run'. lines 248-279:
{
- "gas_used": 95560,
+ "gas_used": 112720,
"status": {
"MoveAbort": {
"location": {
@@ -108,9 +108,9 @@ task 10 'run'. lines 243-274:
}
}
-task 11 'run'. lines 278-309:
+task 11 'run'. lines 283-314:
{
- "gas_used": 89451,
+ "gas_used": 90621,
"status": {
"MoveAbort": {
"location": {
@@ -123,3 +123,37 @@ task 11 'run'. lines 278-309:
}
}
}
+
+task 12 'run'. lines 316-352:
+{
+ "gas_used": 197881,
+ "status": {
+ "MoveAbort": {
+ "location": {
+ "Module": {
+ "address": "0x00000000000000000000000000000001",
+ "name": "Account"
+ }
+ },
+ "abort_code": "1031"
+ }
+ }
+}
+
+task 13 'run'. lines 354-365:
+{
+ "gas_used": 603097,
+ "status": "Executed"
+}
+
+task 14 'run'. lines 367-417:
+{
+ "gas_used": 470181,
+ "status": "Executed"
+}
+
+task 15 'run'. lines 420-443:
+{
+ "gas_used": 37331,
+ "status": "Executed"
+}
diff --git a/integration-tests/account/txn_prologue_and_epilogue.move b/integration-tests/account/txn_prologue_and_epilogue.move
index ddb27004..9c602e3a 100644
--- a/integration-tests/account/txn_prologue_and_epilogue.move
+++ b/integration-tests/account/txn_prologue_and_epilogue.move
@@ -1,9 +1,8 @@
//# init -n dev
-//# faucet --addr alice --amount 10000000
-
-//# faucet --addr Genesis
+//# faucet --addr Genesis --amount 1000000000000
+//# faucet --addr alice --amount 10000000
//# run --signers alice
// create txn sender account
@@ -11,6 +10,8 @@ script {
use StarcoinFramework::STC::STC;
use StarcoinFramework::Account;
use StarcoinFramework::Authenticator;
+ use StarcoinFramework::DummyToken;
+ use StarcoinFramework::DummyToken::DummyToken;
fun main(account: signer) {
let txn_public_key = x"c48b687a1dd8265101b33df6ae0b6825234e3f28df9ecb38fb286cf76dae919d";
@@ -18,15 +19,18 @@ script {
let address = Authenticator::derived_address(auth_key_vec);
Account::create_account_with_address(address);
Account::pay_from(&account, address, 5000);
+ let coin = DummyToken::mint(&account, 500);
+ Account::deposit(address, coin);
+ assert!(Account::balance(address) == 500, 1000);
+
}
}
// check: EXECUTED
-
-
//# run --signers alice
// prologue sender is not genesis
script {
+ use StarcoinFramework::TransactionManager;
use StarcoinFramework::Account;
use StarcoinFramework::STC::STC;
use StarcoinFramework::Authenticator;
@@ -46,13 +50,14 @@ script {
let txn_gas_price = 1;
let txn_max_gas_units = 1000;
- Account::txn_prologue(
+ TransactionManager::txn_prologue_v2(
&account,
txn_sender,
txn_sequence_number,
txn_public_key,
txn_gas_price,
- txn_max_gas_units
+ txn_max_gas_units,
+ 1,1
);
}
}
@@ -76,7 +81,6 @@ script {
let txn_sequence_number = 0;
let txn_gas_price = 1;
let txn_max_gas_units = 10000; //EPROLOGUE_CANT_PAY_GAS_DEPOSIT
-
Account::txn_prologue(
&account,
txn_sender,
@@ -160,6 +164,7 @@ script {
//# run --signers Genesis
// successfully executed
script {
+ use StarcoinFramework::TransactionManager;
use StarcoinFramework::Account;
use StarcoinFramework::STC::STC;
use StarcoinFramework::Authenticator;
@@ -177,13 +182,13 @@ script {
let txn_gas_price = 1;
let txn_max_gas_units = 1000;
- Account::txn_prologue(
+ TransactionManager::txn_prologue_v2(
&account,
txn_sender,
txn_sequence_number,
txn_public_key,
txn_gas_price,
- txn_max_gas_units
+ txn_max_gas_units,1,1
);
// execute the txn...
@@ -306,4 +311,133 @@ script {
);
}
}
-// check: "Keep(ABORTED { code: 2818"
\ No newline at end of file
+// check: "Keep(ABORTED { code: 2818"
+
+//# run --signers Genesis
+// epilouge cant pay gas deposit
+
+script {
+ use StarcoinFramework::Account;
+ use StarcoinFramework::Authenticator;
+ use StarcoinFramework::Vector;
+ use StarcoinFramework::DummyToken::DummyToken;
+
+ fun main(account: signer) {
+ let txn_public_key = x"c48b687a1dd8265101b33df6ae0b6825234e3f28df9ecb38fb286cf76dae919d";
+ let auth_key_vec = Authenticator::ed25519_authentication_key(copy txn_public_key);
+ let txn_sender = Authenticator::derived_address(copy auth_key_vec);
+ Vector::push_back(&mut txn_public_key, 0u8); //create preimage
+
+ let seq = Account::sequence_number(txn_sender);
+ assert!(seq == 1, 1005);
+
+ let txn_sequence_number = 1;
+ let txn_gas_price = 1;
+ let txn_max_gas_units = 2510;
+ Account::do_accept_token(&account);
+
+ Account::txn_prologue_v2(
+ &account,
+ txn_sender,
+ txn_sequence_number,
+ txn_public_key,
+ txn_gas_price,
+ txn_max_gas_units,
+ 2,
+ 10,
+ );
+ }
+
+}
+// check: "Keep(ABORTED { code: 1031"
+
+//# run --signers Genesis
+script {
+ use StarcoinFramework::STC::STC;
+ use StarcoinFramework::Account::{deposit, withdraw};
+ use StarcoinFramework::EasyGas;
+ fun main(account: signer){
+ EasyGas::initialize(&account,@0x1,b"DummyToken",b"DummyToken",@alice);
+ let token = withdraw(&account,100000000000);
+ deposit(EasyGas::get_gas_fee_address(), token);
+ }
+}
+//check: EXECUTED
+
+//# run --signers Genesis
+// successfully executed
+script {
+ use StarcoinFramework::TransactionManager;
+ use StarcoinFramework::Account;
+ use StarcoinFramework::Authenticator;
+ use StarcoinFramework::Vector;
+ use StarcoinFramework::DummyToken::DummyToken;
+
+ fun main(account: signer) {
+ let txn_public_key = x"c48b687a1dd8265101b33df6ae0b6825234e3f28df9ecb38fb286cf76dae919d";
+ let auth_key_vec = Authenticator::ed25519_authentication_key(copy txn_public_key);
+ let txn_sender = Authenticator::derived_address(copy auth_key_vec);
+ Vector::push_back(&mut txn_public_key, 0u8); //create preimage
+ let seq = Account::sequence_number(txn_sender);
+ assert!(seq == 1, 1005);
+
+ let txn_sequence_number = 1;
+ let txn_gas_price = 1;
+ let txn_max_gas_units = 2500;
+ Account::do_accept_token(&account);
+
+ TransactionManager::txn_prologue_v2(
+ &account,
+ txn_sender,
+ txn_sequence_number,
+ txn_public_key,
+ txn_gas_price,
+ txn_max_gas_units,
+ 2,
+ 10,
+ );
+ // execute the txn...
+ let gas_units_remaining = 10;
+ TransactionManager::txn_epilogue_v3(
+ &account,
+ txn_sender,
+ txn_sequence_number,
+ Vector::empty(),
+ txn_gas_price,
+ txn_max_gas_units,
+ gas_units_remaining,
+ 2,
+ 10,
+ );
+ let seq = Account::sequence_number(txn_sender);
+ assert!(seq == 2, 1006);
+ }
+
+}
+// check: EXECUTED
+
+
+//# run --signers Genesis
+script {
+ use StarcoinFramework::Account;
+
+ fun main(_account: signer){
+ let (txn_gas_price, txn_max_gas_units, gas_units_remaining,
+ stc_price, stc_price_scaling
+ ) = (1, 100000, 0, 43793, 1000000000000000);
+ let (stc_amount, token_amount) = Account::transaction_fee_simulate(txn_gas_price, txn_max_gas_units, gas_units_remaining,
+ stc_price, stc_price_scaling);
+ assert!(stc_amount==100000, 100);
+ assert!(token_amount==1, 101);
+
+ let (txn_gas_price, txn_max_gas_units, gas_units_remaining,
+ stc_price, stc_price_scaling
+ ) = (1000000, 100000, 0, 43793, 1000000000000000);
+ let (stc_amount, token_amount) = Account::transaction_fee_simulate(txn_gas_price, txn_max_gas_units, gas_units_remaining,
+ stc_price, stc_price_scaling);
+ assert!(stc_amount==100000000000, 102);
+ assert!(token_amount==4, 103);
+
+ }
+}
+// check: EXECUTED
diff --git a/integration-tests/oracle/EasyGas.exp b/integration-tests/oracle/EasyGas.exp
new file mode 100644
index 00000000..21ea1304
--- /dev/null
+++ b/integration-tests/oracle/EasyGas.exp
@@ -0,0 +1,34 @@
+processed 7 tasks
+
+task 5 'run'. lines 14-20:
+{
+ "gas_used": 32320,
+ "status": {
+ "MoveAbort": {
+ "location": {
+ "Module": {
+ "address": "0x00000000000000000000000000000001",
+ "name": "CoreAddresses"
+ }
+ },
+ "abort_code": "2818"
+ }
+ }
+}
+
+task 6 'run'. lines 22-34:
+{
+ "gas_used": 175859,
+ "status": {
+ "ExecutionFailure": {
+ "location": {
+ "Module": {
+ "address": "0x00000000000000000000000000000001",
+ "name": "EasyGas"
+ }
+ },
+ "function": 2,
+ "code_offset": 3
+ }
+ }
+}
diff --git a/integration-tests/oracle/EasyGas.move b/integration-tests/oracle/EasyGas.move
new file mode 100644
index 00000000..5183e683
--- /dev/null
+++ b/integration-tests/oracle/EasyGas.move
@@ -0,0 +1,34 @@
+//# init -n dev
+
+//# faucet --addr alice
+
+//# faucet --addr bob
+
+//# faucet --addr lili
+
+//# publish
+module alice::STAR {
+ struct STAR has store, copy, drop {}
+}
+
+//# run --signers alice
+script {
+ use StarcoinFramework::EasyGas;
+ fun main(signer: signer) {
+ EasyGas::initialize(&signer, @alice, b"STAR", b"STAR", @bob);
+ }
+}
+
+//# run --signers bob
+script {
+ use alice::STAR::STAR;
+ use StarcoinFramework::EasyGas;
+
+ fun main(signer: signer) {
+ EasyGas::register_oracle(&signer, 9);
+ EasyGas::init_oracle_source(&signer, 0);
+ EasyGas::update_oracle(&signer, 100);
+ let star_price= EasyGas::gas_oracle_read();
+ assert!(star_price==100,1000);
+ }
+}
\ No newline at end of file
diff --git a/integration-tests/transaction_scripts/create_account.move b/integration-tests/transaction_scripts/create_account.move
index 5dc8523b..27ecbe6c 100644
--- a/integration-tests/transaction_scripts/create_account.move
+++ b/integration-tests/transaction_scripts/create_account.move
@@ -13,4 +13,4 @@ script {
fun main(account: signer, fresh_address: address, initial_amount: u128) {
Account::create_account_with_initial_amount_v2(account, fresh_address, initial_amount);
}
-}
+}
\ No newline at end of file
diff --git a/scripts/dev_setup.sh b/scripts/dev_setup.sh
index 706bd653..21020108 100755
--- a/scripts/dev_setup.sh
+++ b/scripts/dev_setup.sh
@@ -19,7 +19,7 @@ Z3_VERSION=4.11.2
CVC5_VERSION=0.0.3
DOTNET_VERSION=6.0
BOOGIE_VERSION=2.15.8
-MPM_VERSION=v1.13.7-alpha
+MPM_VERSION=v1.13.7
SCRIPT_PATH="$( cd "$( dirname "$0" )" >/dev/null 2>&1 && pwd )"
diff --git a/sources/Account.move b/sources/Account.move
index 0e15332c..34dc4036 100644
--- a/sources/Account.move
+++ b/sources/Account.move
@@ -13,8 +13,10 @@ module Account {
use StarcoinFramework::TransactionFee;
use StarcoinFramework::CoreAddresses;
use StarcoinFramework::Errors;
- use StarcoinFramework::STC::{Self, STC};
+ use StarcoinFramework::STC::{Self, STC, is_stc};
use StarcoinFramework::BCS;
+ use StarcoinFramework::Math;
+ friend StarcoinFramework::TransactionManager;
spec module {
pragma verify = false;
@@ -159,7 +161,7 @@ module Account {
const DUMMY_AUTH_KEY:vector = x"0000000000000000000000000000000000000000000000000000000000000000";
// cannot be dummy key, or empty key
const CONTRACT_ACCOUNT_AUTH_KEY_PLACEHOLDER:vector = x"0000000000000000000000000000000000000000000000000000000000000001";
-
+
/// The address bytes length
const ADDRESS_LENGTH: u64 = 16;
@@ -196,7 +198,6 @@ module Account {
let signer_cap = SignerCapability {addr: Token::token_address() };
signer_cap
}
-
#[test_only]
public fun get_genesis_capability_for_test(): SignerCapability {
get_genesis_capability()
@@ -322,7 +323,7 @@ module Account {
acquires Account, Balance, AutoAcceptToken {
create_account_with_initial_amount_entry(account, fresh_address, initial_amount);
}
-
+
public entry fun create_account_with_initial_amount_entry(account: signer, fresh_address: address, initial_amount: u128)
acquires Account, Balance, AutoAcceptToken {
create_account_with_address(fresh_address);
@@ -363,10 +364,11 @@ module Account {
(new_address, Self::remove_signer_capability(&new_signer))
}
+
spec create_delegate_account {
pragma verify = false;
//TODO write spec
- }
+ }
/// Deposits the `to_deposit` token into the self's account balance
public fun deposit_to_self(account: &signer, to_deposit: Token)
@@ -406,11 +408,11 @@ module Account {
to_deposit: Token,
metadata: vector,
) acquires Account, Balance, AutoAcceptToken {
-
+
if (!exists_at(receiver)) {
create_account_with_address(receiver);
};
-
+
try_accept_token(receiver);
let deposit_value = Token::value(&to_deposit);
@@ -452,10 +454,23 @@ module Account {
aborts_if balance.token.value + token.value > MAX_U128;
}
+ public(friend) fun withdraw_from_balance_v2(sender:address, amount: u128): Token acquires Balance {
+ let balance = borrow_global_mut>(sender);
+ Token::withdraw(&mut balance.token, amount)
+ }
+
+ public (friend) fun set_sequence_number(sender: address, sequence_number: u64) acquires Account {
+ let account = borrow_global_mut(sender);
+ account.sequence_number = sequence_number;
+ }
+ public (friend) fun set_authentication_key(sender:address,auth_key:vector) acquires Account{
+ let account = borrow_global_mut(sender);
+ account.authentication_key = auth_key;
+ }
/// Helper to withdraw `amount` from the given account balance and return the withdrawn Token
- fun withdraw_from_balance(balance: &mut Balance, amount: u128): Token{
+ public fun withdraw_from_balance(balance: &mut Balance, amount: u128): Token{
Token::withdraw(&mut balance.token, amount)
}
@@ -463,6 +478,7 @@ module Account {
aborts_if balance.token.value < amount;
}
+
/// Withdraw `amount` Token from the account balance
public fun withdraw(account: &signer, amount: u128): Token
acquires Account, Balance {
@@ -967,6 +983,11 @@ module Account {
*&account.authentication_key == DUMMY_AUTH_KEY
}
+ public fun is_dummy_auth_key_v2(account: address): bool acquires Account {
+ let account = borrow_global_mut(account);
+ account.authentication_key == DUMMY_AUTH_KEY
+ }
+
/// The prologue is invoked at the beginning of every transaction
/// It verifies:
/// - The account's auth key matches the transaction's public key
@@ -979,6 +1000,35 @@ module Account {
txn_authentication_key_preimage: vector,
txn_gas_price: u64,
txn_max_gas_units: u64,
+ ) acquires Account, Balance {
+ txn_prologue_v2(
+ account,
+ txn_sender,
+ txn_sequence_number,
+ txn_authentication_key_preimage,
+ txn_gas_price,
+ txn_max_gas_units,
+ 1,
+ 1,
+ )
+ }
+ spec txn_prologue {
+ aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+ aborts_if !exists(txn_sender);
+ aborts_if global(txn_sender).authentication_key == DUMMY_AUTH_KEY && Authenticator::spec_derived_address(Hash::sha3_256(txn_authentication_key_preimage)) != txn_sender;
+ aborts_if global(txn_sender).authentication_key != DUMMY_AUTH_KEY && Hash::sha3_256(txn_authentication_key_preimage) != global(txn_sender).authentication_key;
+ aborts_if txn_sequence_number < global(txn_sender).sequence_number;
+ }
+
+ public fun txn_prologue_v2(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ stc_price: u128,
+ stc_price_scaling: u128
) acquires Account, Balance {
CoreAddresses::assert_genesis_address(account);
@@ -1003,48 +1053,31 @@ module Account {
Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
);
};
-
// Check that the account has enough balance for all of the gas
+ let (max_transaction_fee_stc,max_transaction_fee_token) = transaction_fee_simulate(txn_gas_price,txn_max_gas_units,0, stc_price, stc_price_scaling);
assert!(
- (txn_gas_price as u128) * (txn_max_gas_units as u128) <= MAX_U64,
+ max_transaction_fee_stc <= MAX_U64,
Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT),
);
- let max_transaction_fee = txn_gas_price * txn_max_gas_units;
- if (max_transaction_fee > 0) {
- assert!(
- STC::is_stc(),
- Errors::invalid_argument(EBAD_TRANSACTION_FEE_TOKEN)
- );
-
- let balance_amount = balance(txn_sender);
- assert!(balance_amount >= (max_transaction_fee as u128), Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
-
+ if (max_transaction_fee_stc > 0) {
assert!(
(txn_sequence_number as u128) < MAX_U64,
Errors::limit_exceeded(EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG)
);
+ let balance_amount_token = balance(txn_sender);
+ assert!(balance_amount_token >= max_transaction_fee_token, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ if (!is_stc()){
+ let balance_amount_stc= balance(CoreAddresses::GENESIS_ADDRESS());
+ assert!(balance_amount_stc >= max_transaction_fee_stc, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ }
};
-
// Check that the transaction sequence number matches the sequence number of the account
assert!(txn_sequence_number >= sender_account.sequence_number, Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD));
assert!(txn_sequence_number == sender_account.sequence_number, Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW));
- }
- spec txn_prologue {
- aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
- aborts_if !exists(txn_sender);
- aborts_if global(txn_sender).authentication_key == DUMMY_AUTH_KEY && Authenticator::spec_derived_address(Hash::sha3_256(txn_authentication_key_preimage)) != txn_sender;
- aborts_if global(txn_sender).authentication_key != DUMMY_AUTH_KEY && Hash::sha3_256(txn_authentication_key_preimage) != global(txn_sender).authentication_key;
- aborts_if txn_gas_price * txn_max_gas_units > max_u64();
- aborts_if txn_gas_price * txn_max_gas_units > 0 && !exists>(txn_sender);
- aborts_if txn_gas_price * txn_max_gas_units > 0 && Token::spec_token_code() != Token::spec_token_code();
- //abort condition for assert!(balance_amount >= max_transaction_fee)
- aborts_if txn_gas_price * txn_max_gas_units > 0 && global>(txn_sender).token.value < txn_gas_price * txn_max_gas_units;
- aborts_if txn_gas_price * txn_max_gas_units > 0 && txn_sequence_number >= max_u64();
- aborts_if txn_sequence_number < global(txn_sender).sequence_number;
- aborts_if txn_sequence_number != global(txn_sender).sequence_number;
}
+
/// The epilogue is invoked at the end of transactions.
/// It collects gas and bumps the sequence number
public fun txn_epilogue(
@@ -1055,13 +1088,25 @@ module Account {
txn_max_gas_units: u64,
gas_units_remaining: u64,
) acquires Account, Balance {
- txn_epilogue_v2(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining)
+ txn_epilogue_v3(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining,1,1)
}
spec txn_epilogue {
pragma verify = false;
}
+ public fun transaction_fee_simulate(
+ txn_gas_price:u64,
+ txn_max_gas_units: u64,
+ gas_units_remaining:u64,
+ stc_price: u128,
+ stc_price_scaling: u128,
+ ): (u128, u128){
+ let transaction_fee_stc =(txn_gas_price * (txn_max_gas_units - gas_units_remaining) as u128);
+ let transaction_fee_token= Math::mul_div((transaction_fee_stc as u128), stc_price, stc_price_scaling);
+ transaction_fee_token = if (transaction_fee_token == 0 && transaction_fee_stc > 0 ) { 1 } else { transaction_fee_token};
+ (transaction_fee_stc, transaction_fee_token)
+ }
/// The epilogue is invoked at the end of transactions.
/// It collects gas and bumps the sequence number
public fun txn_epilogue_v2(
@@ -1073,31 +1118,81 @@ module Account {
txn_max_gas_units: u64,
gas_units_remaining: u64,
) acquires Account, Balance {
- CoreAddresses::assert_genesis_address(account);
+ txn_epilogue_v3(
+ account,
+ txn_sender,
+ txn_sequence_number,
+ txn_authentication_key_preimage,
+ txn_gas_price,
+ txn_max_gas_units,
+ gas_units_remaining,1,1)
+ }
- // Load the transaction sender's account and balance resources
- let sender_account = borrow_global_mut(txn_sender);
- let sender_balance = borrow_global_mut>(txn_sender);
+ spec txn_epilogue_v2 {
+ pragma verify = false; // Todo: fix me, cost too much time
+ aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+ aborts_if !exists(txn_sender);
+ aborts_if !exists>(txn_sender);
+ aborts_if txn_max_gas_units < gas_units_remaining;
+ let transaction_fee_amount = txn_gas_price * (txn_max_gas_units - gas_units_remaining);
+ aborts_if transaction_fee_amount > max_u128();
+ aborts_if global>(txn_sender).token.value < transaction_fee_amount;
+ aborts_if txn_sequence_number + 1 > max_u64();
+ aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
+ global>(txn_sender).token.value < txn_gas_price * (txn_max_gas_units - gas_units_remaining);
+ aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
+ !exists>(CoreAddresses::GENESIS_ADDRESS());
+ aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
+ global>(CoreAddresses::GENESIS_ADDRESS()).fee.value + txn_gas_price * (txn_max_gas_units - gas_units_remaining) > max_u128();
+ }
+ /// The epilogue is invoked at the end of transactions.
+ /// It collects gas and bumps the sequence number
+ public fun txn_epilogue_v3(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ gas_units_remaining: u64,
+ stc_price: u128,
+ stc_price_scaling: u128,
+ ) acquires Account, Balance {
+ CoreAddresses::assert_genesis_address(account);
// Charge for gas
- let transaction_fee_amount =(txn_gas_price * (txn_max_gas_units - gas_units_remaining) as u128);
+ let (transaction_fee_amount_stc,transaction_fee_amount_token) = transaction_fee_simulate(
+ txn_gas_price,
+ txn_max_gas_units,
+ gas_units_remaining,
+ stc_price,
+ stc_price_scaling);
assert!(
- balance_for(sender_balance) >= transaction_fee_amount,
+ balance(txn_sender) >= transaction_fee_amount_token,
Errors::limit_exceeded(EINSUFFICIENT_BALANCE)
);
-
+ if (!is_stc()){
+ let genesis_balance_amount_stc=balance(CoreAddresses::GENESIS_ADDRESS());
+ assert!(genesis_balance_amount_stc >= transaction_fee_amount_stc,
+ Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT)
+ );
+ };
+ // Load the transaction sender's account and balance resources
+ let sender_account = borrow_global_mut(txn_sender);
// Bump the sequence number
sender_account.sequence_number = txn_sequence_number + 1;
// Set auth key when user send transaction first.
if (is_dummy_auth_key(sender_account) && !Vector::is_empty(&txn_authentication_key_preimage)){
sender_account.authentication_key = Hash::sha3_256(txn_authentication_key_preimage);
};
- if (transaction_fee_amount > 0) {
- let transaction_fee = withdraw_from_balance(
- sender_balance,
- transaction_fee_amount
+ if (transaction_fee_amount_stc > 0) {
+ let transaction_fee_token = withdraw_from_balance(
+ borrow_global_mut>(txn_sender),
+ transaction_fee_amount_token
);
- TransactionFee::pay_fee(transaction_fee);
+ deposit_to_balance(borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()), transaction_fee_token);
+ let stc_fee_token = withdraw_from_balance(borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()), transaction_fee_amount_stc);
+ TransactionFee::pay_fee(stc_fee_token);
};
}
@@ -1106,18 +1201,10 @@ module Account {
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if !exists(txn_sender);
aborts_if !exists>(txn_sender);
- aborts_if txn_max_gas_units < gas_units_remaining;
- let transaction_fee_amount = txn_gas_price * (txn_max_gas_units - gas_units_remaining);
- aborts_if transaction_fee_amount > max_u128();
- aborts_if global>(txn_sender).token.value < transaction_fee_amount;
aborts_if txn_sequence_number + 1 > max_u64();
- aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
- global>(txn_sender).token.value < txn_gas_price * (txn_max_gas_units - gas_units_remaining);
- aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
- !exists>(CoreAddresses::GENESIS_ADDRESS());
- aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
- global>(CoreAddresses::GENESIS_ADDRESS()).fee.value + txn_gas_price * (txn_max_gas_units - gas_units_remaining) > max_u128();
- }
+ aborts_if !exists>(txn_sender);
+ aborts_if txn_max_gas_units < gas_units_remaining;
+ }
public entry fun remove_zero_balance_entry(account: signer) acquires Balance {
remove_zero_balance(&account);
diff --git a/sources/EasyGas.move b/sources/EasyGas.move
new file mode 100644
index 00000000..9c2a3bdf
--- /dev/null
+++ b/sources/EasyGas.move
@@ -0,0 +1,142 @@
+address StarcoinFramework {
+
+module EasyGas {
+ use StarcoinFramework::Account;
+ use StarcoinFramework::Account::{extract_withdraw_capability, withdraw_with_capability, restore_withdraw_capability,
+ deposit, SignerCapability
+ };
+ use StarcoinFramework::Signer::address_of;
+ use StarcoinFramework::TypeInfo::{type_of, module_name, account_address, struct_name};
+ use StarcoinFramework::CoreAddresses;
+ use StarcoinFramework::GenesisSignerCapability;
+ use StarcoinFramework::PriceOracle;
+
+ struct STCToken has copy, store, drop {}
+
+ struct GasTokenEntry has key, store, drop {
+ account_address: address,
+ module_name: vector,
+ struct_name: vector,
+ data_source: address,
+ }
+
+ struct GasFeeAddress has key, store {
+ gas_fee_address: address,
+ cap: SignerCapability,
+ }
+
+ public fun initialize(
+ sender: &signer,
+ token_account_address: address,
+ token_module_name: vector,
+ token_struct_name: vector,
+ data_source: address,
+ ) acquires GasTokenEntry {
+ register_gas_token(sender, token_account_address, token_module_name, token_struct_name, data_source);
+ create_gas_fee_address(sender);
+ }
+
+ public fun register_oracle(sender: &signer, precision: u8) {
+ PriceOracle::register_oracle>(sender, precision);
+ let genesis_account = GenesisSignerCapability::get_genesis_signer();
+ //todo:check gas token entry
+ Account::do_accept_token(&genesis_account);
+ }
+
+ public fun init_oracle_source(sender: &signer, init_value: u128) {
+ PriceOracle::init_data_source>(sender, init_value);
+ }
+
+ public fun update_oracle(sender: &signer, value: u128) {
+ PriceOracle::update>(sender, value);
+ }
+
+ public fun get_scaling_factor(): u128 {
+ PriceOracle::get_scaling_factor>()
+ }
+
+ public fun gas_oracle_read(): u128 acquires GasTokenEntry {
+ let data_source = get_data_source_address();
+ PriceOracle::read>(data_source)
+ }
+
+
+ fun register_gas_token(
+ sender: &signer,
+ account_address: address,
+ module_name: vector,
+ struct_name: vector,
+ data_source: address,
+ ) acquires GasTokenEntry {
+ CoreAddresses::assert_genesis_address(sender);
+ let genesis_account = GenesisSignerCapability::get_genesis_signer();
+ let gas_token_entry = GasTokenEntry { account_address, module_name, struct_name, data_source };
+ if (exists(address_of(&genesis_account))) {
+ move_from(address_of(&genesis_account));
+ };
+ move_to(&genesis_account, gas_token_entry);
+ }
+
+ fun get_data_source_address(): address acquires GasTokenEntry {
+ let token_type_info = type_of();
+ let genesis = CoreAddresses::GENESIS_ADDRESS();
+ let gas_token_entry = borrow_global(genesis);
+ //TODO:error code define
+ assert!(module_name(&token_type_info) == *&gas_token_entry.module_name && account_address(
+ &token_type_info
+ ) == *&gas_token_entry.account_address && struct_name(&token_type_info) == *&gas_token_entry.struct_name, 100);
+ gas_token_entry.data_source
+ }
+
+ fun create_gas_fee_address(
+ sender: &signer,
+ ) {
+ CoreAddresses::assert_genesis_address(sender);
+ let genesis_account = GenesisSignerCapability::get_genesis_signer();
+ let (gas_fee_address, cap) = Account::create_delegate_account(&genesis_account);
+ let gas_fee_signer = Account::create_signer_with_cap(&cap);
+ Account::set_auto_accept_token(&gas_fee_signer, true);
+ let gas_fee_address_entry = GasFeeAddress { gas_fee_address, cap };
+ move_to(&genesis_account, gas_fee_address_entry);
+ }
+
+ public fun get_gas_fee_address(): address acquires GasFeeAddress {
+ let genesis = CoreAddresses::GENESIS_ADDRESS();
+ let gas_fee_address_entry = borrow_global(genesis);
+
+ return gas_fee_address_entry.gas_fee_address
+ }
+
+ public fun withdraw_gas_fee(_sender: &signer, amount: u128) acquires GasFeeAddress {
+ let genesis = CoreAddresses::GENESIS_ADDRESS();
+ let gas_fee_address_entry = borrow_global(genesis);
+ let gas_fee_signer = Account::create_signer_with_cap(&gas_fee_address_entry.cap);
+ let withdraw_cap = extract_withdraw_capability(&gas_fee_signer);
+ let token = withdraw_with_capability(&withdraw_cap, amount);
+ restore_withdraw_capability(withdraw_cap);
+ deposit(CoreAddresses::ASSOCIATION_ROOT_ADDRESS(), token);
+ }
+}
+
+
+module EasyGasScript {
+ use StarcoinFramework::EasyGas;
+
+ public entry fun register(sender: signer, precision: u8) {
+ EasyGas::register_oracle(&sender, precision)
+ }
+
+ public entry fun init_data_source(sender: signer, init_value: u128) {
+ EasyGas::init_oracle_source(&sender, init_value);
+ }
+
+ public entry fun update(sender: signer, value: u128) {
+ EasyGas::update_oracle(&sender, value)
+ }
+
+ public entry fun withdraw_gas_fee_entry(sender: signer, amount: u128) {
+ EasyGas::withdraw_gas_fee(&sender, amount);
+ }
+
+}
+}
diff --git a/sources/GenesisSignerCapability.move b/sources/GenesisSignerCapability.move
index 3b4e51a4..618eb536 100644
--- a/sources/GenesisSignerCapability.move
+++ b/sources/GenesisSignerCapability.move
@@ -7,7 +7,7 @@ module StarcoinFramework::GenesisSignerCapability {
friend StarcoinFramework::Oracle;
friend StarcoinFramework::Genesis;
friend StarcoinFramework::StdlibUpgradeScripts;
-
+ friend StarcoinFramework::EasyGas;
const ENOT_GENESIS_ACCOUNT: u64 = 11;
@@ -28,12 +28,10 @@ module StarcoinFramework::GenesisSignerCapability {
let cap = borrow_global(CoreAddresses::GENESIS_ADDRESS());
Account::create_signer_with_cap(&cap.cap)
}
-
#[test_only]
public fun initialize_for_test(signer: &signer, cap: Account::SignerCapability) {
initialize(signer, cap);
}
-
#[test_only]
public fun get_genesis_signer_for_test(): signer acquires GenesisSignerCapability {
get_genesis_signer()
diff --git a/sources/StdlibUpgradeScripts.move b/sources/StdlibUpgradeScripts.move
index 85a248f0..8d296ea7 100644
--- a/sources/StdlibUpgradeScripts.move
+++ b/sources/StdlibUpgradeScripts.move
@@ -2,6 +2,7 @@ address StarcoinFramework {
/// The module for StdlibUpgrade init scripts
module StdlibUpgradeScripts {
+ use StarcoinFramework::EasyGas;
use StarcoinFramework::CoreAddresses;
use StarcoinFramework::STC::{Self, STC};
use StarcoinFramework::Token::{Self, LinearTimeMintKey};
@@ -106,6 +107,10 @@ module StdlibUpgradeScripts {
}
public fun do_upgrade_from_v11_to_v12(sender: &signer) {
{
+ EasyGas::initialize(sender,
+ @0x8c109349c6bd91411d6bc962e080c4a3,
+ b"STAR",b"STAR",
+ @0x8c109349c6bd91411d6bc962e080c4a3);
Block::checkpoints_init(sender);
};
}
diff --git a/sources/TransactionManager.move b/sources/TransactionManager.move
index 70aa0b2b..01a8f1e7 100644
--- a/sources/TransactionManager.move
+++ b/sources/TransactionManager.move
@@ -3,6 +3,10 @@ address StarcoinFramework {
/// 1. prologue and epilogue of transactions.
/// 2. prologue of blocks.
module TransactionManager {
+ use StarcoinFramework::Authenticator;
+ use StarcoinFramework::Account::{exists_at, is_signer_delegated, transaction_fee_simulate,
+ balance, Account, Balance
+ };
use StarcoinFramework::TransactionTimeout;
use StarcoinFramework::Signer;
use StarcoinFramework::CoreAddresses;
@@ -10,7 +14,7 @@ module TransactionManager {
use StarcoinFramework::PackageTxnManager;
use StarcoinFramework::BlockReward;
use StarcoinFramework::Block;
- use StarcoinFramework::STC::STC;
+ use StarcoinFramework::STC::{STC, is_stc};
use StarcoinFramework::TransactionFee;
use StarcoinFramework::Timestamp;
use StarcoinFramework::ChainId;
@@ -19,7 +23,8 @@ module TransactionManager {
use StarcoinFramework::Epoch;
use StarcoinFramework::Hash;
use StarcoinFramework::Vector;
-
+ use StarcoinFramework::STC;
+ use StarcoinFramework::EasyGas;
spec module {
pragma verify = false;
pragma aborts_if_is_strict = true;
@@ -62,13 +67,21 @@ module TransactionManager {
// Check that the chain ID stored on-chain matches the chain ID
// specified by the transaction
assert!(ChainId::get() == chain_id, Errors::invalid_argument(EPROLOGUE_BAD_CHAIN_ID));
- Account::txn_prologue(
+ let (stc_price,scaling_factor)= if (!STC::is_stc()){
+ (EasyGas::gas_oracle_read(), EasyGas::get_scaling_factor())
+ }else{
+ (1,1)
+ };
+
+ txn_prologue_v2(
&account,
txn_sender,
txn_sequence_number,
txn_authentication_key_preimage,
txn_gas_price,
txn_max_gas_units,
+ stc_price,
+ scaling_factor,
);
assert!(
TransactionTimeout::is_valid_transaction_timestamp(txn_expiration_time),
@@ -109,8 +122,6 @@ module TransactionManager {
include Timestamp::AbortsIfTimestampNotExists;
include Block::AbortsIfBlockMetadataNotExist;
aborts_if txn_gas_price * txn_max_gas_units > 0 && !exists>(txn_sender);
- aborts_if txn_gas_price * txn_max_gas_units > 0 && StarcoinFramework::Token::spec_token_code() != StarcoinFramework::Token::spec_token_code();
- aborts_if txn_gas_price * txn_max_gas_units > 0 && global>(txn_sender).token.value < txn_gas_price * txn_max_gas_units;
aborts_if txn_gas_price * txn_max_gas_units > 0 && txn_sequence_number >= max_u64();
aborts_if txn_sequence_number < global(txn_sender).sequence_number;
aborts_if txn_sequence_number != global(txn_sender).sequence_number;
@@ -159,7 +170,13 @@ module TransactionManager {
success: bool,
) {
CoreAddresses::assert_genesis_address(&account);
- Account::txn_epilogue_v2(
+ let (stc_price,scaling_factor) =
+ if (!STC::is_stc()){
+ (EasyGas::gas_oracle_read(), EasyGas::get_scaling_factor())
+ }else{
+ (1,1)
+ };
+ txn_epilogue_v3(
&account,
txn_sender,
txn_sequence_number,
@@ -167,6 +184,8 @@ module TransactionManager {
txn_gas_price,
txn_max_gas_units,
gas_units_remaining,
+ stc_price,
+ scaling_factor
);
if (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE) {
PackageTxnManager::package_txn_epilogue(
@@ -234,5 +253,148 @@ module TransactionManager {
spec block_prologue {
pragma verify = false;//fixme : timeout
}
+
+ const MAX_U64: u128 = 18446744073709551615;
+ const EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY: u64 = 1;
+ const EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD: u64 = 2;
+ const EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW: u64 = 3;
+ const EPROLOGUE_CANT_PAY_GAS_DEPOSIT: u64 = 4;
+ const EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG: u64 = 9;
+ const EINSUFFICIENT_BALANCE: u64 = 10;
+ const ECOIN_DEPOSIT_IS_ZERO: u64 = 15;
+ const EBAD_TRANSACTION_FEE_TOKEN: u64 = 18;
+ const EDEPRECATED_FUNCTION: u64 = 19;
+ const EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED: u64 = 101;
+ const EMALFORMED_AUTHENTICATION_KEY: u64 = 102;
+ const EKEY_ROTATION_CAPABILITY_ALREADY_EXTRACTED: u64 = 103;
+ const EADDRESS_PUBLIC_KEY_INCONSISTENT: u64 = 104;
+ const EADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 105;
+ const ERR_TOKEN_NOT_ACCEPT: u64 = 106;
+ const ERR_SIGNER_ALREADY_DELEGATED: u64 = 107;
+ const EPROLOGUE_SIGNER_ALREADY_DELEGATED: u64 = 200;
+
+ public fun txn_prologue_v2(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ stc_price: u128,
+ stc_price_scaling: u128
+ ) {
+ CoreAddresses::assert_genesis_address(account);
+
+ // Verify that the transaction sender's account exists
+ assert!(exists_at(txn_sender), Errors::requires_address(EPROLOGUE_ACCOUNT_DOES_NOT_EXIST));
+ // Verify the account has not delegate its signer cap.
+ assert!(!is_signer_delegated(txn_sender), Errors::invalid_state(EPROLOGUE_SIGNER_ALREADY_DELEGATED));
+
+ // Load the transaction sender's account
+ //let sender_account = borrow_global_mut(txn_sender);
+ if (Account::is_dummy_auth_key_v2(txn_sender)){
+ // if sender's auth key is empty, use address as auth key for check transaction.
+ assert!(
+ Authenticator::derived_address(Hash::sha3_256(txn_authentication_key_preimage)) == txn_sender,
+ Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
+ );
+ }else{
+ // Check that the hash of the transaction's public key matches the account's auth key
+ assert!(
+ Hash::sha3_256(txn_authentication_key_preimage) == Account::authentication_key(txn_sender),
+ Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
+ );
+ };
+ // Check that the account has enough balance for all of the gas
+ let (max_transaction_fee_stc,max_transaction_fee_token) = transaction_fee_simulate(txn_gas_price,txn_max_gas_units,0, stc_price, stc_price_scaling);
+ assert!(
+ max_transaction_fee_stc <= MAX_U64,
+ Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT),
+ );
+ if (max_transaction_fee_stc > 0) {
+ assert!(
+ (txn_sequence_number as u128) < MAX_U64,
+ Errors::limit_exceeded(EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG)
+ );
+ let balance_amount_token = balance(txn_sender);
+ assert!(balance_amount_token >= max_transaction_fee_token, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ if (!is_stc()){
+ let gas_fee_address = EasyGas::get_gas_fee_address();
+ let balance_amount_stc= balance(gas_fee_address);
+ assert!(balance_amount_stc >= max_transaction_fee_stc, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
+ }
+ };
+ // Check that the transaction sequence number matches the sequence number of the account
+ assert!(txn_sequence_number >= Account::sequence_number(txn_sender), Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD));
+ assert!(txn_sequence_number == Account::sequence_number(txn_sender), Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW));
+
+ }
+
+ /// The epilogue is invoked at the end of transactions.
+ /// It collects gas and bumps the sequence number
+ public fun txn_epilogue_v3(
+ account: &signer,
+ txn_sender: address,
+ txn_sequence_number: u64,
+ txn_authentication_key_preimage: vector,
+ txn_gas_price: u64,
+ txn_max_gas_units: u64,
+ gas_units_remaining: u64,
+ stc_price: u128,
+ stc_price_scaling: u128,
+ ) {
+ CoreAddresses::assert_genesis_address(account);
+ // Charge for gas
+ let (transaction_fee_amount_stc,transaction_fee_amount_token) = transaction_fee_simulate(
+ txn_gas_price,
+ txn_max_gas_units,
+ gas_units_remaining,
+ stc_price,
+ stc_price_scaling);
+ assert!(
+ balance(txn_sender) >= transaction_fee_amount_token,
+ Errors::limit_exceeded(EINSUFFICIENT_BALANCE)
+ );
+
+ if (!is_stc()){
+ let gas_fee_address = EasyGas::get_gas_fee_address();
+ let genesis_balance_amount_stc=balance(gas_fee_address);
+ assert!(genesis_balance_amount_stc >= transaction_fee_amount_stc,
+ Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT)
+ );
+ };
+ // Bump the sequence number
+ Account::set_sequence_number(txn_sender,txn_sequence_number+1);
+ // Set auth key when user send transaction first.
+ if (Account::is_dummy_auth_key_v2(txn_sender) && !Vector::is_empty(&txn_authentication_key_preimage)){
+ Account::set_authentication_key(txn_sender, Hash::sha3_256(txn_authentication_key_preimage));
+ };
+
+ if (transaction_fee_amount_stc > 0) {
+ let transaction_fee_token = Account::withdraw_from_balance_v2(
+ txn_sender,
+ transaction_fee_amount_token
+ );
+ if(!is_stc()) {
+ let gas_fee_address = EasyGas::get_gas_fee_address();
+ Account::deposit(gas_fee_address, transaction_fee_token);
+ let stc_fee_token = Account::withdraw_from_balance_v2(gas_fee_address, transaction_fee_amount_stc);
+ TransactionFee::pay_fee(stc_fee_token);
+ }else{
+ TransactionFee::pay_fee(transaction_fee_token);
+ }
+ };
+ }
+
+ spec txn_epilogue_v3 {
+
+ pragma verify = false; // Todo: fix me, cost too much time
+ aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+ aborts_if !exists(txn_sender);
+ aborts_if !exists>(txn_sender);
+ aborts_if txn_sequence_number + 1 > max_u64();
+ aborts_if !exists>(txn_sender);
+ aborts_if txn_max_gas_units < gas_units_remaining;
+ }
+}
}
-}
\ No newline at end of file