From 1ed82fb21bf73593bf352c06069626bb2a2ee036 Mon Sep 17 00:00:00 2001 From: simonjiao Date: Tue, 16 Jan 2024 16:13:51 +0800 Subject: [PATCH 1/9] new release v13 1. add parents_hash to BlockMetaData 2. add public function`get_parents_hash` to BlockMetaData 3. add flexidagconfig module 4. make flexidagconfig under dao's governship --- Cargo.toml | 4 +- build/StarcoinFramework/BuildInfo.yaml | 2 +- ...pose_update_flexi_dag_effective_height.abi | Bin 0 -> 107 bytes .../upgrade_from_v12_to_v13.abi | Bin 0 -> 65 bytes .../bytecode_modules/Block.mv | Bin 2561 -> 2705 bytes .../bytecode_modules/FlexiDagConfig.mv | Bin 0 -> 399 bytes .../bytecode_modules/Genesis.mv | Bin 3355 -> 3439 bytes .../bytecode_modules/OnChainConfigScripts.mv | Bin 1130 -> 1254 bytes .../StarcoinFramework/bytecode_modules/STC.mv | Bin 1339 -> 1371 bytes .../bytecode_modules/StdlibUpgradeScripts.mv | Bin 2068 -> 2199 bytes .../bytecode_modules/TransactionManager.mv | Bin 2483 -> 2510 bytes build/StarcoinFramework/docs/Block.md | 68 +- .../StarcoinFramework/docs/FlexiDagConfig.md | 166 + build/StarcoinFramework/docs/Genesis.md | 4 + .../docs/OnChainConfigScripts.md | 39 + build/StarcoinFramework/docs/README.md | 1 + build/StarcoinFramework/docs/STC.md | 2 + .../docs/StdlibUpgradeScripts.md | 55 + .../docs/TransactionManager.md | 5 +- .../StarcoinFramework/source_maps/Block.mvsm | Bin 17908 -> 18845 bytes .../source_maps/FlexiDagConfig.mvsm | Bin 0 -> 1368 bytes .../source_maps/Genesis.mvsm | Bin 25151 -> 25361 bytes .../source_maps/OnChainConfigScripts.mvsm | Bin 6912 -> 7493 bytes build/StarcoinFramework/source_maps/STC.mvsm | Bin 6152 -> 6236 bytes .../source_maps/StdlibUpgradeScripts.mvsm | Bin 6609 -> 7177 bytes .../source_maps/TransactionManager.mvsm | Bin 19005 -> 19100 bytes integration-tests/block/block_metadata.move | 6 + release/StarcoinFramework.v0.1.0.blob | Bin 0 -> 114284 bytes release/v13/BuildInfo.yaml | 20 + release/v13/abis/Account/accept_token.abi | Bin 0 -> 52 bytes .../v13/abis/Account/accept_token_entry.abi | Bin 0 -> 58 bytes .../create_account_with_initial_amount.abi | Bin 0 -> 117 bytes ...eate_account_with_initial_amount_entry.abi | Bin 0 -> 111 bytes .../create_account_with_initial_amount_v2.abi | Bin 0 -> 108 bytes .../Account/remove_zero_balance_entry.abi | Bin 0 -> 65 bytes .../Account/rotate_authentication_key.abi | Bin 0 -> 64 bytes .../rotate_authentication_key_entry.abi | Bin 0 -> 70 bytes .../Account/set_auto_accept_token_entry.abi | Bin 0 -> 64 bytes .../disable_auto_accept_token.abi | Bin 0 -> 143 bytes .../enable_auto_accept_token.abi | Bin 0 -> 141 bytes .../AccountScripts/remove_zero_balance.abi | Bin 0 -> 87 bytes release/v13/abis/Block/checkpoint_entry.abi | Bin 0 -> 43 bytes .../abis/Block/update_state_root_entry.abi | Bin 0 -> 59 bytes .../abis/Dao/destroy_terminated_proposal.abi | Bin 0 -> 141 bytes .../v13/abis/Dao/queue_proposal_action.abi | Bin 0 -> 128 bytes release/v13/abis/DaoVoteScripts/cast_vote.abi | Bin 0 -> 105 bytes release/v13/abis/DaoVoteScripts/flip_vote.abi | Bin 0 -> 144 bytes .../v13/abis/DaoVoteScripts/revoke_vote.abi | Bin 0 -> 122 bytes .../DaoVoteScripts/revoke_vote_of_power.abi | Bin 0 -> 139 bytes .../v13/abis/DaoVoteScripts/unstake_vote.abi | Bin 0 -> 92 bytes release/v13/abis/DummyToken/mint.abi | Bin 0 -> 51 bytes release/v13/abis/EasyGas/deposit.abi | Bin 0 -> 61 bytes release/v13/abis/EasyGas/init_data_source.abi | Bin 0 -> 74 bytes release/v13/abis/EasyGas/register.abi | Bin 0 -> 65 bytes release/v13/abis/EasyGas/update.abi | Bin 0 -> 59 bytes .../abis/EasyGas/withdraw_gas_fee_entry.abi | Bin 0 -> 76 bytes .../v13/abis/EmptyScripts/empty_script.abi | Bin 0 -> 46 bytes release/v13/abis/Genesis/initialize.abi | Bin 0 -> 939 bytes release/v13/abis/Genesis/initialize_v2.abi | Bin 0 -> 960 bytes release/v13/abis/GenesisNFT/mint.abi | Bin 0 -> 84 bytes release/v13/abis/GenesisNFT/mint_entry.abi | Bin 0 -> 65 bytes .../abis/ModifyDaoConfigProposal/execute.abi | Bin 0 -> 176 bytes .../abis/ModifyDaoConfigProposal/propose.abi | Bin 0 -> 168 bytes .../cancel_upgrade_plan.abi | Bin 0 -> 137 bytes .../execute_module_upgrade_plan_propose.abi | Bin 0 -> 249 bytes .../propose_module_upgrade_v2.abi | Bin 0 -> 135 bytes .../submit_module_upgrade_plan.abi | Bin 0 -> 184 bytes .../submit_upgrade_plan.abi | Bin 0 -> 241 bytes .../update_module_upgrade_strategy.abi | Bin 0 -> 137 bytes ..._module_upgrade_strategy_with_min_time.abi | Bin 0 -> 253 bytes release/v13/abis/NFT/accept.abi | Bin 0 -> 115 bytes release/v13/abis/NFT/accept_entry.abi | Bin 0 -> 125 bytes release/v13/abis/NFT/destroy_empty.abi | Bin 0 -> 101 bytes release/v13/abis/NFT/destroy_empty_entry.abi | Bin 0 -> 104 bytes release/v13/abis/NFT/remove_empty_gallery.abi | Bin 0 -> 113 bytes .../abis/NFT/remove_empty_gallery_entry.abi | Bin 0 -> 112 bytes release/v13/abis/NFT/transfer.abi | Bin 0 -> 148 bytes release/v13/abis/NFT/transfer_entry.abi | Bin 0 -> 119 bytes release/v13/abis/Offer/take_offer.abi | Bin 0 -> 112 bytes .../execute_on_chain_config_proposal.abi | Bin 0 -> 96 bytes .../execute_on_chain_config_proposal_v2.abi | Bin 0 -> 128 bytes .../propose_update_consensus_config.abi | Bin 0 -> 336 bytes ...pose_update_flexi_dag_effective_height.abi | Bin 0 -> 107 bytes .../propose_update_move_language_version.abi | Bin 0 -> 103 bytes .../propose_update_reward_config.abi | Bin 0 -> 96 bytes .../propose_update_txn_publish_option.abi | Bin 0 -> 130 bytes .../propose_update_txn_timeout_config.abi | Bin 0 -> 105 bytes .../propose_update_vm_config.abi | Bin 0 -> 416 bytes release/v13/abis/Oracle/init_data_source.abi | Bin 0 -> 77 bytes .../abis/Oracle/init_data_source_entry.abi | Bin 0 -> 76 bytes release/v13/abis/Oracle/register_oracle.abi | Bin 0 -> 75 bytes .../v13/abis/Oracle/register_oracle_entry.abi | Bin 0 -> 74 bytes release/v13/abis/Oracle/update.abi | Bin 0 -> 62 bytes release/v13/abis/Oracle/update_entry.abi | Bin 0 -> 61 bytes ...t_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2.abi | Bin 0 -> 100 bytes .../take_linear_withdraw_capability.abi | Bin 0 -> 146 bytes .../upgrade_from_v11_to_v12.abi | Bin 0 -> 65 bytes .../upgrade_from_v12_to_v13.abi | Bin 0 -> 65 bytes .../upgrade_from_v2_to_v3.abi | Bin 0 -> 117 bytes .../upgrade_from_v5_to_v6.abi | Bin 0 -> 63 bytes .../upgrade_from_v6_to_v7.abi | Bin 0 -> 63 bytes .../upgrade_from_v7_to_v8.abi | Bin 0 -> 63 bytes .../TransferScripts/batch_peer_to_peer.abi | Bin 0 -> 138 bytes .../TransferScripts/batch_peer_to_peer_v2.abi | Bin 0 -> 121 bytes .../v13/abis/TransferScripts/peer_to_peer.abi | Bin 0 -> 93 bytes .../TransferScripts/peer_to_peer_batch.abi | Bin 0 -> 105 bytes .../abis/TransferScripts/peer_to_peer_v2.abi | Bin 0 -> 78 bytes .../peer_to_peer_with_metadata.abi | Bin 0 -> 118 bytes .../peer_to_peer_with_metadata_v2.abi | Bin 0 -> 103 bytes .../execute_withdraw_proposal.abi | Bin 0 -> 101 bytes .../abis/TreasuryScripts/propose_withdraw.abi | Bin 0 -> 99 bytes .../withdraw_and_split_lt_withdraw_cap.abi | Bin 0 -> 113 bytes ..._token_with_linear_withdraw_capability.abi | Bin 0 -> 91 bytes release/v13/bytecode_modules/ACL.mv | Bin 0 -> 435 bytes release/v13/bytecode_modules/Account.mv | Bin 0 -> 6890 bytes .../v13/bytecode_modules/AccountScripts.mv | Bin 0 -> 275 bytes release/v13/bytecode_modules/Arith.mv | Bin 0 -> 467 bytes release/v13/bytecode_modules/Authenticator.mv | Bin 0 -> 801 bytes release/v13/bytecode_modules/BCS.mv | Bin 0 -> 3074 bytes release/v13/bytecode_modules/BitOperators.mv | Bin 0 -> 212 bytes release/v13/bytecode_modules/Block.mv | Bin 0 -> 2705 bytes release/v13/bytecode_modules/BlockReward.mv | Bin 0 -> 1514 bytes release/v13/bytecode_modules/ChainId.mv | Bin 0 -> 439 bytes release/v13/bytecode_modules/Collection.mv | Bin 0 -> 814 bytes release/v13/bytecode_modules/Collection2.mv | Bin 0 -> 1860 bytes release/v13/bytecode_modules/Compare.mv | Bin 0 -> 623 bytes release/v13/bytecode_modules/Config.mv | Bin 0 -> 1317 bytes .../v13/bytecode_modules/ConsensusConfig.mv | Bin 0 -> 1292 bytes .../v13/bytecode_modules/ConsensusStrategy.mv | Bin 0 -> 435 bytes release/v13/bytecode_modules/CoreAddresses.mv | Bin 0 -> 349 bytes release/v13/bytecode_modules/Dao.mv | Bin 0 -> 4845 bytes .../v13/bytecode_modules/DaoVoteScripts.mv | Bin 0 -> 650 bytes release/v13/bytecode_modules/Debug.mv | Bin 0 -> 100 bytes release/v13/bytecode_modules/DummyToken.mv | Bin 0 -> 731 bytes .../v13/bytecode_modules/DummyTokenScripts.mv | Bin 0 -> 292 bytes release/v13/bytecode_modules/EVMAddress.mv | Bin 0 -> 400 bytes release/v13/bytecode_modules/EasyGas.mv | Bin 0 -> 1589 bytes release/v13/bytecode_modules/EasyGasScript.mv | Bin 0 -> 430 bytes release/v13/bytecode_modules/EmptyScripts.mv | Bin 0 -> 85 bytes release/v13/bytecode_modules/Epoch.mv | Bin 0 -> 2724 bytes release/v13/bytecode_modules/Errors.mv | Bin 0 -> 480 bytes release/v13/bytecode_modules/Event.mv | Bin 0 -> 695 bytes release/v13/bytecode_modules/EventUtil.mv | Bin 0 -> 490 bytes release/v13/bytecode_modules/FixedPoint32.mv | Bin 0 -> 595 bytes .../v13/bytecode_modules/FlexiDagConfig.mv | Bin 0 -> 326 bytes release/v13/bytecode_modules/FromBCS.mv | Bin 0 -> 240 bytes release/v13/bytecode_modules/GasSchedule.mv | Bin 0 -> 8488 bytes release/v13/bytecode_modules/Genesis.mv | Bin 0 -> 3391 bytes release/v13/bytecode_modules/GenesisNFT.mv | Bin 0 -> 1242 bytes .../v13/bytecode_modules/GenesisNFTScripts.mv | Bin 0 -> 125 bytes .../GenesisSignerCapability.mv | Bin 0 -> 464 bytes release/v13/bytecode_modules/Hash.mv | Bin 0 -> 129 bytes release/v13/bytecode_modules/IdentifierNFT.mv | Bin 0 -> 1493 bytes .../bytecode_modules/IdentifierNFTScripts.mv | Bin 0 -> 204 bytes .../v13/bytecode_modules/LanguageVersion.mv | Bin 0 -> 143 bytes release/v13/bytecode_modules/Math.mv | Bin 0 -> 688 bytes .../bytecode_modules/MerkleNFTDistributor.mv | Bin 0 -> 1259 bytes release/v13/bytecode_modules/MerkleProof.mv | Bin 0 -> 322 bytes .../v13/bytecode_modules/MintDaoProposal.mv | Bin 0 -> 681 bytes release/v13/bytecode_modules/MintScripts.mv | Bin 0 -> 49 bytes .../ModifyDaoConfigProposal.mv | Bin 0 -> 850 bytes .../bytecode_modules/ModuleUpgradeScripts.mv | Bin 0 -> 901 bytes release/v13/bytecode_modules/NFT.mv | Bin 0 -> 4087 bytes release/v13/bytecode_modules/NFTGallery.mv | Bin 0 -> 2178 bytes .../v13/bytecode_modules/NFTGalleryScripts.mv | Bin 0 -> 271 bytes release/v13/bytecode_modules/Offer.mv | Bin 0 -> 538 bytes .../v13/bytecode_modules/OnChainConfigDao.mv | Bin 0 -> 649 bytes .../bytecode_modules/OnChainConfigScripts.mv | Bin 0 -> 1254 bytes release/v13/bytecode_modules/Option.mv | Bin 0 -> 1051 bytes release/v13/bytecode_modules/Oracle.mv | Bin 0 -> 1893 bytes .../v13/bytecode_modules/PackageTxnManager.mv | Bin 0 -> 3179 bytes release/v13/bytecode_modules/PriceOracle.mv | Bin 0 -> 825 bytes .../bytecode_modules/PriceOracleAggregator.mv | Bin 0 -> 498 bytes .../bytecode_modules/PriceOracleScripts.mv | Bin 0 -> 274 bytes release/v13/bytecode_modules/RewardConfig.mv | Bin 0 -> 419 bytes release/v13/bytecode_modules/Ring.mv | Bin 0 -> 1292 bytes release/v13/bytecode_modules/SIP_2.mv | Bin 0 -> 43 bytes release/v13/bytecode_modules/SIP_3.mv | Bin 0 -> 43 bytes release/v13/bytecode_modules/STC.mv | Bin 0 -> 1371 bytes release/v13/bytecode_modules/STCUSDOracle.mv | Bin 0 -> 322 bytes release/v13/bytecode_modules/Secp256k1.mv | Bin 0 -> 604 bytes .../SharedEd25519PublicKey.mv | Bin 0 -> 615 bytes release/v13/bytecode_modules/Signature.mv | Bin 0 -> 430 bytes .../v13/bytecode_modules/SignedInteger64.mv | Bin 0 -> 463 bytes release/v13/bytecode_modules/Signer.mv | Bin 0 -> 114 bytes release/v13/bytecode_modules/SimpleMap.mv | Bin 0 -> 1160 bytes .../v13/bytecode_modules/StarcoinVerifier.mv | Bin 0 -> 1910 bytes .../bytecode_modules/StdlibUpgradeScripts.mv | Bin 0 -> 2199 bytes release/v13/bytecode_modules/String.mv | Bin 0 -> 927 bytes .../v13/bytecode_modules/StructuredHash.mv | Bin 0 -> 270 bytes release/v13/bytecode_modules/Table.mv | Bin 0 -> 1107 bytes release/v13/bytecode_modules/Timestamp.mv | Bin 0 -> 636 bytes release/v13/bytecode_modules/Token.mv | Bin 0 -> 2435 bytes .../v13/bytecode_modules/TransactionFee.mv | Bin 0 -> 567 bytes .../bytecode_modules/TransactionManager.mv | Bin 0 -> 2510 bytes .../TransactionPublishOption.mv | Bin 0 -> 600 bytes .../bytecode_modules/TransactionTimeout.mv | Bin 0 -> 293 bytes .../TransactionTimeoutConfig.mv | Bin 0 -> 447 bytes .../v13/bytecode_modules/TransferScripts.mv | Bin 0 -> 719 bytes release/v13/bytecode_modules/Treasury.mv | Bin 0 -> 2454 bytes .../v13/bytecode_modules/TreasuryScripts.mv | Bin 0 -> 892 bytes .../TreasuryWithdrawDaoProposal.mv | Bin 0 -> 1013 bytes release/v13/bytecode_modules/TypeInfo.mv | Bin 0 -> 312 bytes release/v13/bytecode_modules/U256.mv | Bin 0 -> 1125 bytes .../UpgradeModuleDaoProposal.mv | Bin 0 -> 846 bytes release/v13/bytecode_modules/VMConfig.mv | Bin 0 -> 3967 bytes release/v13/bytecode_modules/Vector.mv | Bin 0 -> 1256 bytes release/v13/bytecode_modules/Version.mv | Bin 0 -> 195 bytes release/v13/bytecode_modules/YieldFarming.mv | Bin 0 -> 1610 bytes .../v13/bytecode_modules/YieldFarmingV2.mv | Bin 0 -> 3429 bytes release/v13/docs/ACL.md | 205 + release/v13/docs/Account.md | 3676 +++++++++++++++++ release/v13/docs/AccountScripts.md | 93 + release/v13/docs/Authenticator.md | 448 ++ release/v13/docs/BCS.md | 1599 +++++++ release/v13/docs/Bitwise.md | 179 + release/v13/docs/Block.md | 995 +++++ release/v13/docs/BlockReward.md | 397 ++ release/v13/docs/ChainId.md | 425 ++ release/v13/docs/Collection.md | 430 ++ release/v13/docs/Collection2.md | 878 ++++ release/v13/docs/Compare.md | 340 ++ release/v13/docs/Config.md | 773 ++++ release/v13/docs/ConsensusConfig.md | 700 ++++ release/v13/docs/ConsensusStrategy.md | 143 + release/v13/docs/CoreAddresses.md | 178 + release/v13/docs/Dao.md | 2330 +++++++++++ release/v13/docs/DaoVoteScripts.md | 197 + release/v13/docs/Debug.md | 72 + release/v13/docs/DummyToken.md | 46 + release/v13/docs/EasyGas.md | 140 + release/v13/docs/EmptyScripts.md | 48 + release/v13/docs/Epoch.md | 1041 +++++ release/v13/docs/Errors.md | 623 +++ release/v13/docs/Event.md | 300 ++ release/v13/docs/EventUtil.md | 175 + release/v13/docs/FixedPoint32.md | 439 ++ release/v13/docs/FlexiDagConfig.md | 168 + release/v13/docs/FromBCS.md | 205 + release/v13/docs/GasSchedule.md | 540 +++ release/v13/docs/Genesis.md | 656 +++ release/v13/docs/GenesisNFT.md | 49 + release/v13/docs/GenesisSignerCapability.md | 114 + release/v13/docs/Hash.md | 116 + release/v13/docs/LanguageVersion.md | 114 + release/v13/docs/Math.md | 377 ++ release/v13/docs/MerkleNFT.md | 330 ++ release/v13/docs/MintDaoProposal.md | 258 ++ release/v13/docs/MintScripts.md | 10 + release/v13/docs/ModifyDaoConfigProposal.md | 300 ++ release/v13/docs/ModuleUpgradeScripts.md | 314 ++ release/v13/docs/NFT.md | 104 + release/v13/docs/Offer.md | 305 ++ release/v13/docs/OnChainConfigDao.md | 257 ++ release/v13/docs/OnChainConfigScripts.md | 417 ++ release/v13/docs/Option.md | 787 ++++ release/v13/docs/Oracle.md | 88 + release/v13/docs/PackageTxnManager.md | 1454 +++++++ release/v13/docs/README.md | 111 + release/v13/docs/RewardConfig.md | 240 ++ release/v13/docs/Ring.md | 426 ++ release/v13/docs/SIPs.md | 11 + release/v13/docs/STC.md | 405 ++ release/v13/docs/Secp256k1.md | 296 ++ release/v13/docs/SharedEd25519PublicKey.md | 309 ++ release/v13/docs/Signature.md | 154 + release/v13/docs/SignedInteger64.md | 352 ++ release/v13/docs/Signer.md | 94 + release/v13/docs/SimpleMap.md | 543 +++ release/v13/docs/StarcoinVerifier.md | 715 ++++ release/v13/docs/StdlibUpgradeScripts.md | 422 ++ release/v13/docs/String.md | 530 +++ release/v13/docs/Table.md | 831 ++++ release/v13/docs/Timestamp.md | 461 +++ release/v13/docs/Token.md | 1845 +++++++++ release/v13/docs/TransactionFee.md | 245 ++ release/v13/docs/TransactionManager.md | 710 ++++ release/v13/docs/TransactionPublishOption.md | 348 ++ release/v13/docs/TransactionTimeout.md | 108 + release/v13/docs/TransactionTimeoutConfig.md | 235 ++ release/v13/docs/TransferScripts.md | 252 ++ release/v13/docs/Treasury.md | 1230 ++++++ release/v13/docs/TreasuryScripts.md | 204 + .../v13/docs/TreasuryWithdrawDaoProposal.md | 320 ++ release/v13/docs/TypeInfo.md | 192 + release/v13/docs/U256.md | 946 +++++ release/v13/docs/UpgradeModuleDaoProposal.md | 350 ++ release/v13/docs/VMConfig.md | 738 ++++ release/v13/docs/Vector.md | 861 ++++ release/v13/docs/Version.md | 146 + release/v13/docs/YieldFarming.md | 886 ++++ release/v13/docs/YieldFarmingV2.md | 1429 +++++++ release/v13/source_maps/ACL.mvsm | Bin 0 -> 2752 bytes release/v13/source_maps/Account.mvsm | Bin 0 -> 52990 bytes release/v13/source_maps/AccountScripts.mvsm | Bin 0 -> 875 bytes release/v13/source_maps/Arith.mvsm | Bin 0 -> 5637 bytes release/v13/source_maps/Authenticator.mvsm | Bin 0 -> 5974 bytes release/v13/source_maps/BCS.mvsm | Bin 0 -> 34843 bytes release/v13/source_maps/BitOperators.mvsm | Bin 0 -> 1831 bytes release/v13/source_maps/Block.mvsm | Bin 0 -> 18845 bytes release/v13/source_maps/BlockReward.mvsm | Bin 0 -> 9414 bytes release/v13/source_maps/ChainId.mvsm | Bin 0 -> 2200 bytes release/v13/source_maps/Collection.mvsm | Bin 0 -> 4680 bytes release/v13/source_maps/Collection2.mvsm | Bin 0 -> 15981 bytes release/v13/source_maps/Compare.mvsm | Bin 0 -> 7988 bytes release/v13/source_maps/Config.mvsm | Bin 0 -> 7768 bytes release/v13/source_maps/ConsensusConfig.mvsm | Bin 0 -> 9323 bytes .../v13/source_maps/ConsensusStrategy.mvsm | Bin 0 -> 913 bytes release/v13/source_maps/CoreAddresses.mvsm | Bin 0 -> 799 bytes release/v13/source_maps/Dao.mvsm | Bin 0 -> 50523 bytes release/v13/source_maps/DaoVoteScripts.mvsm | Bin 0 -> 5825 bytes release/v13/source_maps/Debug.mvsm | Bin 0 -> 246 bytes release/v13/source_maps/DummyToken.mvsm | Bin 0 -> 2528 bytes .../v13/source_maps/DummyTokenScripts.mvsm | Bin 0 -> 990 bytes release/v13/source_maps/EVMAddress.mvsm | Bin 0 -> 3461 bytes release/v13/source_maps/EasyGas.mvsm | Bin 0 -> 8532 bytes release/v13/source_maps/EasyGasScript.mvsm | Bin 0 -> 1928 bytes release/v13/source_maps/EmptyScripts.mvsm | Bin 0 -> 163 bytes release/v13/source_maps/Epoch.mvsm | Bin 0 -> 23967 bytes release/v13/source_maps/Errors.mvsm | Bin 0 -> 3114 bytes release/v13/source_maps/Event.mvsm | Bin 0 -> 4345 bytes release/v13/source_maps/EventUtil.mvsm | Bin 0 -> 2461 bytes release/v13/source_maps/FixedPoint32.mvsm | Bin 0 -> 5001 bytes release/v13/source_maps/FlexiDagConfig.mvsm | Bin 0 -> 1116 bytes release/v13/source_maps/FromBCS.mvsm | Bin 0 -> 1090 bytes release/v13/source_maps/GasSchedule.mvsm | Bin 0 -> 37488 bytes release/v13/source_maps/Genesis.mvsm | Bin 0 -> 25235 bytes release/v13/source_maps/GenesisNFT.mvsm | Bin 0 -> 5416 bytes .../v13/source_maps/GenesisNFTScripts.mvsm | Bin 0 -> 482 bytes .../source_maps/GenesisSignerCapability.mvsm | Bin 0 -> 1176 bytes release/v13/source_maps/Hash.mvsm | Bin 0 -> 437 bytes release/v13/source_maps/IdentifierNFT.mvsm | Bin 0 -> 10873 bytes .../v13/source_maps/IdentifierNFTScripts.mvsm | Bin 0 -> 715 bytes release/v13/source_maps/LanguageVersion.mvsm | Bin 0 -> 520 bytes release/v13/source_maps/Math.mvsm | Bin 0 -> 7919 bytes .../v13/source_maps/MerkleNFTDistributor.mvsm | Bin 0 -> 10035 bytes release/v13/source_maps/MerkleProof.mvsm | Bin 0 -> 2603 bytes release/v13/source_maps/MintDaoProposal.mvsm | Bin 0 -> 2957 bytes release/v13/source_maps/MintScripts.mvsm | Bin 0 -> 72 bytes .../source_maps/ModifyDaoConfigProposal.mvsm | Bin 0 -> 4303 bytes .../v13/source_maps/ModuleUpgradeScripts.mvsm | Bin 0 -> 4085 bytes release/v13/source_maps/NFT.mvsm | Bin 0 -> 34306 bytes release/v13/source_maps/NFTGallery.mvsm | Bin 0 -> 18809 bytes .../v13/source_maps/NFTGalleryScripts.mvsm | Bin 0 -> 1205 bytes release/v13/source_maps/Offer.mvsm | Bin 0 -> 4119 bytes release/v13/source_maps/OnChainConfigDao.mvsm | Bin 0 -> 2756 bytes .../v13/source_maps/OnChainConfigScripts.mvsm | Bin 0 -> 7493 bytes release/v13/source_maps/Option.mvsm | Bin 0 -> 8759 bytes release/v13/source_maps/Oracle.mvsm | Bin 0 -> 13219 bytes .../v13/source_maps/PackageTxnManager.mvsm | Bin 0 -> 25290 bytes release/v13/source_maps/PriceOracle.mvsm | Bin 0 -> 4190 bytes .../source_maps/PriceOracleAggregator.mvsm | Bin 0 -> 2538 bytes .../v13/source_maps/PriceOracleScripts.mvsm | Bin 0 -> 1159 bytes release/v13/source_maps/RewardConfig.mvsm | Bin 0 -> 1249 bytes release/v13/source_maps/Ring.mvsm | Bin 0 -> 11866 bytes release/v13/source_maps/SIP_2.mvsm | Bin 0 -> 66 bytes release/v13/source_maps/SIP_3.mvsm | Bin 0 -> 66 bytes release/v13/source_maps/STC.mvsm | Bin 0 -> 6236 bytes release/v13/source_maps/STCUSDOracle.mvsm | Bin 0 -> 961 bytes release/v13/source_maps/Secp256k1.mvsm | Bin 0 -> 2969 bytes .../source_maps/SharedEd25519PublicKey.mvsm | Bin 0 -> 2626 bytes release/v13/source_maps/Signature.mvsm | Bin 0 -> 2185 bytes release/v13/source_maps/SignedInteger64.mvsm | Bin 0 -> 4668 bytes release/v13/source_maps/Signer.mvsm | Bin 0 -> 373 bytes release/v13/source_maps/SimpleMap.mvsm | Bin 0 -> 10685 bytes release/v13/source_maps/StarcoinVerifier.mvsm | Bin 0 -> 16198 bytes .../v13/source_maps/StdlibUpgradeScripts.mvsm | Bin 0 -> 7177 bytes release/v13/source_maps/String.mvsm | Bin 0 -> 7367 bytes release/v13/source_maps/StructuredHash.mvsm | Bin 0 -> 1456 bytes release/v13/source_maps/Table.mvsm | Bin 0 -> 9428 bytes release/v13/source_maps/Timestamp.mvsm | Bin 0 -> 3370 bytes release/v13/source_maps/Token.mvsm | Bin 0 -> 16442 bytes release/v13/source_maps/TransactionFee.mvsm | Bin 0 -> 2528 bytes .../v13/source_maps/TransactionManager.mvsm | Bin 0 -> 19100 bytes .../source_maps/TransactionPublishOption.mvsm | Bin 0 -> 2360 bytes .../v13/source_maps/TransactionTimeout.mvsm | Bin 0 -> 1393 bytes .../source_maps/TransactionTimeoutConfig.mvsm | Bin 0 -> 1242 bytes release/v13/source_maps/TransferScripts.mvsm | Bin 0 -> 5656 bytes release/v13/source_maps/Treasury.mvsm | Bin 0 -> 16124 bytes release/v13/source_maps/TreasuryScripts.mvsm | Bin 0 -> 3680 bytes .../TreasuryWithdrawDaoProposal.mvsm | Bin 0 -> 4367 bytes release/v13/source_maps/TypeInfo.mvsm | Bin 0 -> 1387 bytes release/v13/source_maps/U256.mvsm | Bin 0 -> 9423 bytes .../source_maps/UpgradeModuleDaoProposal.mvsm | Bin 0 -> 4305 bytes release/v13/source_maps/VMConfig.mvsm | Bin 0 -> 31554 bytes release/v13/source_maps/Vector.mvsm | Bin 0 -> 14092 bytes release/v13/source_maps/Version.mvsm | Bin 0 -> 697 bytes release/v13/source_maps/YieldFarming.mvsm | Bin 0 -> 9552 bytes release/v13/source_maps/YieldFarmingV2.mvsm | Bin 0 -> 34091 bytes release/v13/sources/ACL.move | 46 + release/v13/sources/Account.move | 1228 ++++++ release/v13/sources/AccountScripts.move | 21 + release/v13/sources/Arith.move | 442 ++ release/v13/sources/Authenticator.move | 155 + release/v13/sources/BCS.move | 696 ++++ release/v13/sources/BitOperators.move | 39 + release/v13/sources/Block.move | 465 +++ release/v13/sources/BlockReward.move | 192 + release/v13/sources/ChainId.move | 94 + release/v13/sources/Collection.move | 118 + release/v13/sources/Collection2.move | 235 ++ release/v13/sources/Compare.move | 126 + release/v13/sources/Config.move | 281 ++ release/v13/sources/ConsensusConfig.move | 230 ++ release/v13/sources/ConsensusStrategy.move | 49 + release/v13/sources/CoreAddresses.move | 51 + release/v13/sources/Dao.move | 1073 +++++ release/v13/sources/DaoVoteScripts.move | 77 + release/v13/sources/Debug.move | 16 + release/v13/sources/DummyToken.move | 77 + release/v13/sources/DummyTokenScripts.move | 77 + release/v13/sources/EVMAddress.move | 131 + release/v13/sources/EasyGas.move | 147 + release/v13/sources/EasyGasScript.move | 147 + release/v13/sources/EmptyScripts.move | 14 + release/v13/sources/Epoch.move | 380 ++ release/v13/sources/Errors.move | 169 + release/v13/sources/Event.move | 95 + release/v13/sources/EventUtil.move | 36 + release/v13/sources/FixedPoint32.move | 157 + release/v13/sources/FlexiDagConfig.move | 55 + release/v13/sources/FromBCS.move | 85 + release/v13/sources/GasSchedule.move | 355 ++ release/v13/sources/Genesis.move | 560 +++ release/v13/sources/GenesisNFT.move | 82 + release/v13/sources/GenesisNFTScripts.move | 82 + .../v13/sources/GenesisSignerCapability.move | 39 + release/v13/sources/Hash.move | 14 + release/v13/sources/IdentifierNFT.move | 1023 +++++ release/v13/sources/IdentifierNFTScripts.move | 1023 +++++ release/v13/sources/LanguageVersion.move | 22 + release/v13/sources/Math.move | 155 + release/v13/sources/MerkleNFTDistributor.move | 131 + release/v13/sources/MerkleProof.move | 131 + release/v13/sources/MintDaoProposal.move | 98 + release/v13/sources/MintScripts.move | 4 + .../v13/sources/ModifyDaoConfigProposal.move | 125 + release/v13/sources/ModuleUpgradeScripts.move | 116 + release/v13/sources/NFT.move | 1023 +++++ release/v13/sources/NFTGallery.move | 1023 +++++ release/v13/sources/NFTGalleryScripts.move | 1023 +++++ release/v13/sources/Offer.move | 84 + release/v13/sources/OnChainConfigDao.move | 97 + release/v13/sources/OnChainConfigScripts.move | 148 + release/v13/sources/Option.move | 235 ++ release/v13/sources/Oracle.move | 325 ++ release/v13/sources/PackageTxnManager.move | 469 +++ release/v13/sources/PriceOracle.move | 325 ++ .../v13/sources/PriceOracleAggregator.move | 325 ++ release/v13/sources/PriceOracleScripts.move | 325 ++ release/v13/sources/RewardConfig.move | 71 + release/v13/sources/Ring.move | 152 + release/v13/sources/SIP_2.move | 15 + release/v13/sources/SIP_3.move | 15 + release/v13/sources/STC.move | 162 + release/v13/sources/STCUSDOracle.move | 325 ++ release/v13/sources/Secp256k1.move | 132 + .../v13/sources/SharedEd25519PublicKey.move | 110 + release/v13/sources/Signature.move | 131 + release/v13/sources/SignedInteger64.move | 109 + release/v13/sources/Signer.move | 28 + release/v13/sources/SimpleMap.move | 289 ++ release/v13/sources/StarcoinVerifier.move | 356 ++ release/v13/sources/StdlibUpgradeScripts.move | 133 + release/v13/sources/String.move | 128 + release/v13/sources/StructuredHash.move | 356 ++ release/v13/sources/Table.move | 235 ++ release/v13/sources/Timestamp.move | 131 + release/v13/sources/Token.move | 545 +++ release/v13/sources/TransactionFee.move | 95 + release/v13/sources/TransactionManager.move | 395 ++ .../v13/sources/TransactionPublishOption.move | 120 + release/v13/sources/TransactionTimeout.move | 53 + .../v13/sources/TransactionTimeoutConfig.move | 76 + release/v13/sources/TransferScripts.move | 69 + release/v13/sources/Treasury.move | 388 ++ release/v13/sources/TreasuryScripts.move | 79 + .../sources/TreasuryWithdrawDaoProposal.move | 119 + release/v13/sources/TypeInfo.move | 44 + release/v13/sources/U256.move | 442 ++ .../v13/sources/UpgradeModuleDaoProposal.move | 117 + release/v13/sources/VMConfig.move | 442 ++ release/v13/sources/Vector.move | 250 ++ release/v13/sources/Version.move | 38 + release/v13/sources/YieldFarming.move | 204 + release/v13/sources/YieldFarmingV2.move | 492 +++ sources/Block.move | 28 +- sources/FlexiDagConfig.move | 52 + sources/Genesis.move | 4 + sources/OnChainConfigScripts.move | 10 + sources/STC.move | 2 + sources/StdlibUpgradeScripts.move | 11 + sources/TransactionManager.move | 3 + 493 files changed, 64655 insertions(+), 17 deletions(-) create mode 100644 build/StarcoinFramework/abis/OnChainConfigScripts/propose_update_flexi_dag_effective_height.abi create mode 100644 build/StarcoinFramework/abis/StdlibUpgradeScripts/upgrade_from_v12_to_v13.abi create mode 100644 build/StarcoinFramework/bytecode_modules/FlexiDagConfig.mv create mode 100644 build/StarcoinFramework/docs/FlexiDagConfig.md create mode 100644 build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm create mode 100644 release/StarcoinFramework.v0.1.0.blob create mode 100644 release/v13/BuildInfo.yaml create mode 100644 release/v13/abis/Account/accept_token.abi create mode 100644 release/v13/abis/Account/accept_token_entry.abi create mode 100644 release/v13/abis/Account/create_account_with_initial_amount.abi create mode 100644 release/v13/abis/Account/create_account_with_initial_amount_entry.abi create mode 100644 release/v13/abis/Account/create_account_with_initial_amount_v2.abi create mode 100644 release/v13/abis/Account/remove_zero_balance_entry.abi create mode 100644 release/v13/abis/Account/rotate_authentication_key.abi create mode 100644 release/v13/abis/Account/rotate_authentication_key_entry.abi create mode 100644 release/v13/abis/Account/set_auto_accept_token_entry.abi create mode 100644 release/v13/abis/AccountScripts/disable_auto_accept_token.abi create mode 100644 release/v13/abis/AccountScripts/enable_auto_accept_token.abi create mode 100644 release/v13/abis/AccountScripts/remove_zero_balance.abi create mode 100644 release/v13/abis/Block/checkpoint_entry.abi create mode 100644 release/v13/abis/Block/update_state_root_entry.abi create mode 100644 release/v13/abis/Dao/destroy_terminated_proposal.abi create mode 100644 release/v13/abis/Dao/queue_proposal_action.abi create mode 100644 release/v13/abis/DaoVoteScripts/cast_vote.abi create mode 100644 release/v13/abis/DaoVoteScripts/flip_vote.abi create mode 100644 release/v13/abis/DaoVoteScripts/revoke_vote.abi create mode 100644 release/v13/abis/DaoVoteScripts/revoke_vote_of_power.abi create mode 100644 release/v13/abis/DaoVoteScripts/unstake_vote.abi create mode 100644 release/v13/abis/DummyToken/mint.abi create mode 100644 release/v13/abis/EasyGas/deposit.abi create mode 100644 release/v13/abis/EasyGas/init_data_source.abi create mode 100644 release/v13/abis/EasyGas/register.abi create mode 100644 release/v13/abis/EasyGas/update.abi create mode 100644 release/v13/abis/EasyGas/withdraw_gas_fee_entry.abi create mode 100644 release/v13/abis/EmptyScripts/empty_script.abi create mode 100644 release/v13/abis/Genesis/initialize.abi create mode 100644 release/v13/abis/Genesis/initialize_v2.abi create mode 100644 release/v13/abis/GenesisNFT/mint.abi create mode 100644 release/v13/abis/GenesisNFT/mint_entry.abi create mode 100644 release/v13/abis/ModifyDaoConfigProposal/execute.abi create mode 100644 release/v13/abis/ModifyDaoConfigProposal/propose.abi create mode 100644 release/v13/abis/ModuleUpgradeScripts/cancel_upgrade_plan.abi create mode 100644 release/v13/abis/ModuleUpgradeScripts/execute_module_upgrade_plan_propose.abi create mode 100644 release/v13/abis/ModuleUpgradeScripts/propose_module_upgrade_v2.abi create mode 100644 release/v13/abis/ModuleUpgradeScripts/submit_module_upgrade_plan.abi create mode 100644 release/v13/abis/ModuleUpgradeScripts/submit_upgrade_plan.abi create mode 100644 release/v13/abis/ModuleUpgradeScripts/update_module_upgrade_strategy.abi create mode 100644 release/v13/abis/ModuleUpgradeScripts/update_module_upgrade_strategy_with_min_time.abi create mode 100644 release/v13/abis/NFT/accept.abi create mode 100644 release/v13/abis/NFT/accept_entry.abi create mode 100644 release/v13/abis/NFT/destroy_empty.abi create mode 100644 release/v13/abis/NFT/destroy_empty_entry.abi create mode 100644 release/v13/abis/NFT/remove_empty_gallery.abi create mode 100644 release/v13/abis/NFT/remove_empty_gallery_entry.abi create mode 100644 release/v13/abis/NFT/transfer.abi create mode 100644 release/v13/abis/NFT/transfer_entry.abi create mode 100644 release/v13/abis/Offer/take_offer.abi create mode 100644 release/v13/abis/OnChainConfigScripts/execute_on_chain_config_proposal.abi create mode 100644 release/v13/abis/OnChainConfigScripts/execute_on_chain_config_proposal_v2.abi create mode 100644 release/v13/abis/OnChainConfigScripts/propose_update_consensus_config.abi create mode 100644 release/v13/abis/OnChainConfigScripts/propose_update_flexi_dag_effective_height.abi create mode 100644 release/v13/abis/OnChainConfigScripts/propose_update_move_language_version.abi create mode 100644 release/v13/abis/OnChainConfigScripts/propose_update_reward_config.abi create mode 100644 release/v13/abis/OnChainConfigScripts/propose_update_txn_publish_option.abi create mode 100644 release/v13/abis/OnChainConfigScripts/propose_update_txn_timeout_config.abi create mode 100644 release/v13/abis/OnChainConfigScripts/propose_update_vm_config.abi create mode 100644 release/v13/abis/Oracle/init_data_source.abi create mode 100644 release/v13/abis/Oracle/init_data_source_entry.abi create mode 100644 release/v13/abis/Oracle/register_oracle.abi create mode 100644 release/v13/abis/Oracle/register_oracle_entry.abi create mode 100644 release/v13/abis/Oracle/update.abi create mode 100644 release/v13/abis/Oracle/update_entry.abi create mode 100644 release/v13/abis/PackageTxnManager/convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2.abi create mode 100644 release/v13/abis/StdlibUpgradeScripts/take_linear_withdraw_capability.abi create mode 100644 release/v13/abis/StdlibUpgradeScripts/upgrade_from_v11_to_v12.abi create mode 100644 release/v13/abis/StdlibUpgradeScripts/upgrade_from_v12_to_v13.abi create mode 100644 release/v13/abis/StdlibUpgradeScripts/upgrade_from_v2_to_v3.abi create mode 100644 release/v13/abis/StdlibUpgradeScripts/upgrade_from_v5_to_v6.abi create mode 100644 release/v13/abis/StdlibUpgradeScripts/upgrade_from_v6_to_v7.abi create mode 100644 release/v13/abis/StdlibUpgradeScripts/upgrade_from_v7_to_v8.abi create mode 100644 release/v13/abis/TransferScripts/batch_peer_to_peer.abi create mode 100644 release/v13/abis/TransferScripts/batch_peer_to_peer_v2.abi create mode 100644 release/v13/abis/TransferScripts/peer_to_peer.abi create mode 100644 release/v13/abis/TransferScripts/peer_to_peer_batch.abi create mode 100644 release/v13/abis/TransferScripts/peer_to_peer_v2.abi create mode 100644 release/v13/abis/TransferScripts/peer_to_peer_with_metadata.abi create mode 100644 release/v13/abis/TransferScripts/peer_to_peer_with_metadata_v2.abi create mode 100644 release/v13/abis/TreasuryScripts/execute_withdraw_proposal.abi create mode 100644 release/v13/abis/TreasuryScripts/propose_withdraw.abi create mode 100644 release/v13/abis/TreasuryScripts/withdraw_and_split_lt_withdraw_cap.abi create mode 100644 release/v13/abis/TreasuryScripts/withdraw_token_with_linear_withdraw_capability.abi create mode 100644 release/v13/bytecode_modules/ACL.mv create mode 100644 release/v13/bytecode_modules/Account.mv create mode 100644 release/v13/bytecode_modules/AccountScripts.mv create mode 100644 release/v13/bytecode_modules/Arith.mv create mode 100644 release/v13/bytecode_modules/Authenticator.mv create mode 100644 release/v13/bytecode_modules/BCS.mv create mode 100644 release/v13/bytecode_modules/BitOperators.mv create mode 100644 release/v13/bytecode_modules/Block.mv create mode 100644 release/v13/bytecode_modules/BlockReward.mv create mode 100644 release/v13/bytecode_modules/ChainId.mv create mode 100644 release/v13/bytecode_modules/Collection.mv create mode 100644 release/v13/bytecode_modules/Collection2.mv create mode 100644 release/v13/bytecode_modules/Compare.mv create mode 100644 release/v13/bytecode_modules/Config.mv create mode 100644 release/v13/bytecode_modules/ConsensusConfig.mv create mode 100644 release/v13/bytecode_modules/ConsensusStrategy.mv create mode 100644 release/v13/bytecode_modules/CoreAddresses.mv create mode 100644 release/v13/bytecode_modules/Dao.mv create mode 100644 release/v13/bytecode_modules/DaoVoteScripts.mv create mode 100644 release/v13/bytecode_modules/Debug.mv create mode 100644 release/v13/bytecode_modules/DummyToken.mv create mode 100644 release/v13/bytecode_modules/DummyTokenScripts.mv create mode 100644 release/v13/bytecode_modules/EVMAddress.mv create mode 100644 release/v13/bytecode_modules/EasyGas.mv create mode 100644 release/v13/bytecode_modules/EasyGasScript.mv create mode 100644 release/v13/bytecode_modules/EmptyScripts.mv create mode 100644 release/v13/bytecode_modules/Epoch.mv create mode 100644 release/v13/bytecode_modules/Errors.mv create mode 100644 release/v13/bytecode_modules/Event.mv create mode 100644 release/v13/bytecode_modules/EventUtil.mv create mode 100644 release/v13/bytecode_modules/FixedPoint32.mv create mode 100644 release/v13/bytecode_modules/FlexiDagConfig.mv create mode 100644 release/v13/bytecode_modules/FromBCS.mv create mode 100644 release/v13/bytecode_modules/GasSchedule.mv create mode 100644 release/v13/bytecode_modules/Genesis.mv create mode 100644 release/v13/bytecode_modules/GenesisNFT.mv create mode 100644 release/v13/bytecode_modules/GenesisNFTScripts.mv create mode 100644 release/v13/bytecode_modules/GenesisSignerCapability.mv create mode 100644 release/v13/bytecode_modules/Hash.mv create mode 100644 release/v13/bytecode_modules/IdentifierNFT.mv create mode 100644 release/v13/bytecode_modules/IdentifierNFTScripts.mv create mode 100644 release/v13/bytecode_modules/LanguageVersion.mv create mode 100644 release/v13/bytecode_modules/Math.mv create mode 100644 release/v13/bytecode_modules/MerkleNFTDistributor.mv create mode 100644 release/v13/bytecode_modules/MerkleProof.mv create mode 100644 release/v13/bytecode_modules/MintDaoProposal.mv create mode 100644 release/v13/bytecode_modules/MintScripts.mv create mode 100644 release/v13/bytecode_modules/ModifyDaoConfigProposal.mv create mode 100644 release/v13/bytecode_modules/ModuleUpgradeScripts.mv create mode 100644 release/v13/bytecode_modules/NFT.mv create mode 100644 release/v13/bytecode_modules/NFTGallery.mv create mode 100644 release/v13/bytecode_modules/NFTGalleryScripts.mv create mode 100644 release/v13/bytecode_modules/Offer.mv create mode 100644 release/v13/bytecode_modules/OnChainConfigDao.mv create mode 100644 release/v13/bytecode_modules/OnChainConfigScripts.mv create mode 100644 release/v13/bytecode_modules/Option.mv create mode 100644 release/v13/bytecode_modules/Oracle.mv create mode 100644 release/v13/bytecode_modules/PackageTxnManager.mv create mode 100644 release/v13/bytecode_modules/PriceOracle.mv create mode 100644 release/v13/bytecode_modules/PriceOracleAggregator.mv create mode 100644 release/v13/bytecode_modules/PriceOracleScripts.mv create mode 100644 release/v13/bytecode_modules/RewardConfig.mv create mode 100644 release/v13/bytecode_modules/Ring.mv create mode 100644 release/v13/bytecode_modules/SIP_2.mv create mode 100644 release/v13/bytecode_modules/SIP_3.mv create mode 100644 release/v13/bytecode_modules/STC.mv create mode 100644 release/v13/bytecode_modules/STCUSDOracle.mv create mode 100644 release/v13/bytecode_modules/Secp256k1.mv create mode 100644 release/v13/bytecode_modules/SharedEd25519PublicKey.mv create mode 100644 release/v13/bytecode_modules/Signature.mv create mode 100644 release/v13/bytecode_modules/SignedInteger64.mv create mode 100644 release/v13/bytecode_modules/Signer.mv create mode 100644 release/v13/bytecode_modules/SimpleMap.mv create mode 100644 release/v13/bytecode_modules/StarcoinVerifier.mv create mode 100644 release/v13/bytecode_modules/StdlibUpgradeScripts.mv create mode 100644 release/v13/bytecode_modules/String.mv create mode 100644 release/v13/bytecode_modules/StructuredHash.mv create mode 100644 release/v13/bytecode_modules/Table.mv create mode 100644 release/v13/bytecode_modules/Timestamp.mv create mode 100644 release/v13/bytecode_modules/Token.mv create mode 100644 release/v13/bytecode_modules/TransactionFee.mv create mode 100644 release/v13/bytecode_modules/TransactionManager.mv create mode 100644 release/v13/bytecode_modules/TransactionPublishOption.mv create mode 100644 release/v13/bytecode_modules/TransactionTimeout.mv create mode 100644 release/v13/bytecode_modules/TransactionTimeoutConfig.mv create mode 100644 release/v13/bytecode_modules/TransferScripts.mv create mode 100644 release/v13/bytecode_modules/Treasury.mv create mode 100644 release/v13/bytecode_modules/TreasuryScripts.mv create mode 100644 release/v13/bytecode_modules/TreasuryWithdrawDaoProposal.mv create mode 100644 release/v13/bytecode_modules/TypeInfo.mv create mode 100644 release/v13/bytecode_modules/U256.mv create mode 100644 release/v13/bytecode_modules/UpgradeModuleDaoProposal.mv create mode 100644 release/v13/bytecode_modules/VMConfig.mv create mode 100644 release/v13/bytecode_modules/Vector.mv create mode 100644 release/v13/bytecode_modules/Version.mv create mode 100644 release/v13/bytecode_modules/YieldFarming.mv create mode 100644 release/v13/bytecode_modules/YieldFarmingV2.mv create mode 100644 release/v13/docs/ACL.md create mode 100644 release/v13/docs/Account.md create mode 100644 release/v13/docs/AccountScripts.md create mode 100644 release/v13/docs/Authenticator.md create mode 100644 release/v13/docs/BCS.md create mode 100644 release/v13/docs/Bitwise.md create mode 100644 release/v13/docs/Block.md create mode 100644 release/v13/docs/BlockReward.md create mode 100644 release/v13/docs/ChainId.md create mode 100644 release/v13/docs/Collection.md create mode 100644 release/v13/docs/Collection2.md create mode 100644 release/v13/docs/Compare.md create mode 100644 release/v13/docs/Config.md create mode 100644 release/v13/docs/ConsensusConfig.md create mode 100644 release/v13/docs/ConsensusStrategy.md create mode 100644 release/v13/docs/CoreAddresses.md create mode 100644 release/v13/docs/Dao.md create mode 100644 release/v13/docs/DaoVoteScripts.md create mode 100644 release/v13/docs/Debug.md create mode 100644 release/v13/docs/DummyToken.md create mode 100644 release/v13/docs/EasyGas.md create mode 100644 release/v13/docs/EmptyScripts.md create mode 100644 release/v13/docs/Epoch.md create mode 100644 release/v13/docs/Errors.md create mode 100644 release/v13/docs/Event.md create mode 100644 release/v13/docs/EventUtil.md create mode 100644 release/v13/docs/FixedPoint32.md create mode 100644 release/v13/docs/FlexiDagConfig.md create mode 100644 release/v13/docs/FromBCS.md create mode 100644 release/v13/docs/GasSchedule.md create mode 100644 release/v13/docs/Genesis.md create mode 100644 release/v13/docs/GenesisNFT.md create mode 100644 release/v13/docs/GenesisSignerCapability.md create mode 100644 release/v13/docs/Hash.md create mode 100644 release/v13/docs/LanguageVersion.md create mode 100644 release/v13/docs/Math.md create mode 100644 release/v13/docs/MerkleNFT.md create mode 100644 release/v13/docs/MintDaoProposal.md create mode 100644 release/v13/docs/MintScripts.md create mode 100644 release/v13/docs/ModifyDaoConfigProposal.md create mode 100644 release/v13/docs/ModuleUpgradeScripts.md create mode 100644 release/v13/docs/NFT.md create mode 100644 release/v13/docs/Offer.md create mode 100644 release/v13/docs/OnChainConfigDao.md create mode 100644 release/v13/docs/OnChainConfigScripts.md create mode 100644 release/v13/docs/Option.md create mode 100644 release/v13/docs/Oracle.md create mode 100644 release/v13/docs/PackageTxnManager.md create mode 100644 release/v13/docs/README.md create mode 100644 release/v13/docs/RewardConfig.md create mode 100644 release/v13/docs/Ring.md create mode 100644 release/v13/docs/SIPs.md create mode 100644 release/v13/docs/STC.md create mode 100644 release/v13/docs/Secp256k1.md create mode 100644 release/v13/docs/SharedEd25519PublicKey.md create mode 100644 release/v13/docs/Signature.md create mode 100644 release/v13/docs/SignedInteger64.md create mode 100644 release/v13/docs/Signer.md create mode 100644 release/v13/docs/SimpleMap.md create mode 100644 release/v13/docs/StarcoinVerifier.md create mode 100644 release/v13/docs/StdlibUpgradeScripts.md create mode 100644 release/v13/docs/String.md create mode 100644 release/v13/docs/Table.md create mode 100644 release/v13/docs/Timestamp.md create mode 100644 release/v13/docs/Token.md create mode 100644 release/v13/docs/TransactionFee.md create mode 100644 release/v13/docs/TransactionManager.md create mode 100644 release/v13/docs/TransactionPublishOption.md create mode 100644 release/v13/docs/TransactionTimeout.md create mode 100644 release/v13/docs/TransactionTimeoutConfig.md create mode 100644 release/v13/docs/TransferScripts.md create mode 100644 release/v13/docs/Treasury.md create mode 100644 release/v13/docs/TreasuryScripts.md create mode 100644 release/v13/docs/TreasuryWithdrawDaoProposal.md create mode 100644 release/v13/docs/TypeInfo.md create mode 100644 release/v13/docs/U256.md create mode 100644 release/v13/docs/UpgradeModuleDaoProposal.md create mode 100644 release/v13/docs/VMConfig.md create mode 100644 release/v13/docs/Vector.md create mode 100644 release/v13/docs/Version.md create mode 100644 release/v13/docs/YieldFarming.md create mode 100644 release/v13/docs/YieldFarmingV2.md create mode 100644 release/v13/source_maps/ACL.mvsm create mode 100644 release/v13/source_maps/Account.mvsm create mode 100644 release/v13/source_maps/AccountScripts.mvsm create mode 100644 release/v13/source_maps/Arith.mvsm create mode 100644 release/v13/source_maps/Authenticator.mvsm create mode 100644 release/v13/source_maps/BCS.mvsm create mode 100644 release/v13/source_maps/BitOperators.mvsm create mode 100644 release/v13/source_maps/Block.mvsm create mode 100644 release/v13/source_maps/BlockReward.mvsm create mode 100644 release/v13/source_maps/ChainId.mvsm create mode 100644 release/v13/source_maps/Collection.mvsm create mode 100644 release/v13/source_maps/Collection2.mvsm create mode 100644 release/v13/source_maps/Compare.mvsm create mode 100644 release/v13/source_maps/Config.mvsm create mode 100644 release/v13/source_maps/ConsensusConfig.mvsm create mode 100644 release/v13/source_maps/ConsensusStrategy.mvsm create mode 100644 release/v13/source_maps/CoreAddresses.mvsm create mode 100644 release/v13/source_maps/Dao.mvsm create mode 100644 release/v13/source_maps/DaoVoteScripts.mvsm create mode 100644 release/v13/source_maps/Debug.mvsm create mode 100644 release/v13/source_maps/DummyToken.mvsm create mode 100644 release/v13/source_maps/DummyTokenScripts.mvsm create mode 100644 release/v13/source_maps/EVMAddress.mvsm create mode 100644 release/v13/source_maps/EasyGas.mvsm create mode 100644 release/v13/source_maps/EasyGasScript.mvsm create mode 100644 release/v13/source_maps/EmptyScripts.mvsm create mode 100644 release/v13/source_maps/Epoch.mvsm create mode 100644 release/v13/source_maps/Errors.mvsm create mode 100644 release/v13/source_maps/Event.mvsm create mode 100644 release/v13/source_maps/EventUtil.mvsm create mode 100644 release/v13/source_maps/FixedPoint32.mvsm create mode 100644 release/v13/source_maps/FlexiDagConfig.mvsm create mode 100644 release/v13/source_maps/FromBCS.mvsm create mode 100644 release/v13/source_maps/GasSchedule.mvsm create mode 100644 release/v13/source_maps/Genesis.mvsm create mode 100644 release/v13/source_maps/GenesisNFT.mvsm create mode 100644 release/v13/source_maps/GenesisNFTScripts.mvsm create mode 100644 release/v13/source_maps/GenesisSignerCapability.mvsm create mode 100644 release/v13/source_maps/Hash.mvsm create mode 100644 release/v13/source_maps/IdentifierNFT.mvsm create mode 100644 release/v13/source_maps/IdentifierNFTScripts.mvsm create mode 100644 release/v13/source_maps/LanguageVersion.mvsm create mode 100644 release/v13/source_maps/Math.mvsm create mode 100644 release/v13/source_maps/MerkleNFTDistributor.mvsm create mode 100644 release/v13/source_maps/MerkleProof.mvsm create mode 100644 release/v13/source_maps/MintDaoProposal.mvsm create mode 100644 release/v13/source_maps/MintScripts.mvsm create mode 100644 release/v13/source_maps/ModifyDaoConfigProposal.mvsm create mode 100644 release/v13/source_maps/ModuleUpgradeScripts.mvsm create mode 100644 release/v13/source_maps/NFT.mvsm create mode 100644 release/v13/source_maps/NFTGallery.mvsm create mode 100644 release/v13/source_maps/NFTGalleryScripts.mvsm create mode 100644 release/v13/source_maps/Offer.mvsm create mode 100644 release/v13/source_maps/OnChainConfigDao.mvsm create mode 100644 release/v13/source_maps/OnChainConfigScripts.mvsm create mode 100644 release/v13/source_maps/Option.mvsm create mode 100644 release/v13/source_maps/Oracle.mvsm create mode 100644 release/v13/source_maps/PackageTxnManager.mvsm create mode 100644 release/v13/source_maps/PriceOracle.mvsm create mode 100644 release/v13/source_maps/PriceOracleAggregator.mvsm create mode 100644 release/v13/source_maps/PriceOracleScripts.mvsm create mode 100644 release/v13/source_maps/RewardConfig.mvsm create mode 100644 release/v13/source_maps/Ring.mvsm create mode 100644 release/v13/source_maps/SIP_2.mvsm create mode 100644 release/v13/source_maps/SIP_3.mvsm create mode 100644 release/v13/source_maps/STC.mvsm create mode 100644 release/v13/source_maps/STCUSDOracle.mvsm create mode 100644 release/v13/source_maps/Secp256k1.mvsm create mode 100644 release/v13/source_maps/SharedEd25519PublicKey.mvsm create mode 100644 release/v13/source_maps/Signature.mvsm create mode 100644 release/v13/source_maps/SignedInteger64.mvsm create mode 100644 release/v13/source_maps/Signer.mvsm create mode 100644 release/v13/source_maps/SimpleMap.mvsm create mode 100644 release/v13/source_maps/StarcoinVerifier.mvsm create mode 100644 release/v13/source_maps/StdlibUpgradeScripts.mvsm create mode 100644 release/v13/source_maps/String.mvsm create mode 100644 release/v13/source_maps/StructuredHash.mvsm create mode 100644 release/v13/source_maps/Table.mvsm create mode 100644 release/v13/source_maps/Timestamp.mvsm create mode 100644 release/v13/source_maps/Token.mvsm create mode 100644 release/v13/source_maps/TransactionFee.mvsm create mode 100644 release/v13/source_maps/TransactionManager.mvsm create mode 100644 release/v13/source_maps/TransactionPublishOption.mvsm create mode 100644 release/v13/source_maps/TransactionTimeout.mvsm create mode 100644 release/v13/source_maps/TransactionTimeoutConfig.mvsm create mode 100644 release/v13/source_maps/TransferScripts.mvsm create mode 100644 release/v13/source_maps/Treasury.mvsm create mode 100644 release/v13/source_maps/TreasuryScripts.mvsm create mode 100644 release/v13/source_maps/TreasuryWithdrawDaoProposal.mvsm create mode 100644 release/v13/source_maps/TypeInfo.mvsm create mode 100644 release/v13/source_maps/U256.mvsm create mode 100644 release/v13/source_maps/UpgradeModuleDaoProposal.mvsm create mode 100644 release/v13/source_maps/VMConfig.mvsm create mode 100644 release/v13/source_maps/Vector.mvsm create mode 100644 release/v13/source_maps/Version.mvsm create mode 100644 release/v13/source_maps/YieldFarming.mvsm create mode 100644 release/v13/source_maps/YieldFarmingV2.mvsm create mode 100644 release/v13/sources/ACL.move create mode 100644 release/v13/sources/Account.move create mode 100644 release/v13/sources/AccountScripts.move create mode 100644 release/v13/sources/Arith.move create mode 100644 release/v13/sources/Authenticator.move create mode 100644 release/v13/sources/BCS.move create mode 100644 release/v13/sources/BitOperators.move create mode 100644 release/v13/sources/Block.move create mode 100644 release/v13/sources/BlockReward.move create mode 100644 release/v13/sources/ChainId.move create mode 100644 release/v13/sources/Collection.move create mode 100644 release/v13/sources/Collection2.move create mode 100644 release/v13/sources/Compare.move create mode 100644 release/v13/sources/Config.move create mode 100644 release/v13/sources/ConsensusConfig.move create mode 100644 release/v13/sources/ConsensusStrategy.move create mode 100644 release/v13/sources/CoreAddresses.move create mode 100644 release/v13/sources/Dao.move create mode 100644 release/v13/sources/DaoVoteScripts.move create mode 100644 release/v13/sources/Debug.move create mode 100644 release/v13/sources/DummyToken.move create mode 100644 release/v13/sources/DummyTokenScripts.move create mode 100644 release/v13/sources/EVMAddress.move create mode 100644 release/v13/sources/EasyGas.move create mode 100644 release/v13/sources/EasyGasScript.move create mode 100644 release/v13/sources/EmptyScripts.move create mode 100644 release/v13/sources/Epoch.move create mode 100644 release/v13/sources/Errors.move create mode 100644 release/v13/sources/Event.move create mode 100644 release/v13/sources/EventUtil.move create mode 100644 release/v13/sources/FixedPoint32.move create mode 100644 release/v13/sources/FlexiDagConfig.move create mode 100644 release/v13/sources/FromBCS.move create mode 100644 release/v13/sources/GasSchedule.move create mode 100644 release/v13/sources/Genesis.move create mode 100644 release/v13/sources/GenesisNFT.move create mode 100644 release/v13/sources/GenesisNFTScripts.move create mode 100644 release/v13/sources/GenesisSignerCapability.move create mode 100644 release/v13/sources/Hash.move create mode 100644 release/v13/sources/IdentifierNFT.move create mode 100644 release/v13/sources/IdentifierNFTScripts.move create mode 100644 release/v13/sources/LanguageVersion.move create mode 100644 release/v13/sources/Math.move create mode 100644 release/v13/sources/MerkleNFTDistributor.move create mode 100644 release/v13/sources/MerkleProof.move create mode 100644 release/v13/sources/MintDaoProposal.move create mode 100644 release/v13/sources/MintScripts.move create mode 100644 release/v13/sources/ModifyDaoConfigProposal.move create mode 100644 release/v13/sources/ModuleUpgradeScripts.move create mode 100644 release/v13/sources/NFT.move create mode 100644 release/v13/sources/NFTGallery.move create mode 100644 release/v13/sources/NFTGalleryScripts.move create mode 100644 release/v13/sources/Offer.move create mode 100644 release/v13/sources/OnChainConfigDao.move create mode 100644 release/v13/sources/OnChainConfigScripts.move create mode 100644 release/v13/sources/Option.move create mode 100644 release/v13/sources/Oracle.move create mode 100644 release/v13/sources/PackageTxnManager.move create mode 100644 release/v13/sources/PriceOracle.move create mode 100644 release/v13/sources/PriceOracleAggregator.move create mode 100644 release/v13/sources/PriceOracleScripts.move create mode 100644 release/v13/sources/RewardConfig.move create mode 100644 release/v13/sources/Ring.move create mode 100644 release/v13/sources/SIP_2.move create mode 100644 release/v13/sources/SIP_3.move create mode 100644 release/v13/sources/STC.move create mode 100644 release/v13/sources/STCUSDOracle.move create mode 100644 release/v13/sources/Secp256k1.move create mode 100644 release/v13/sources/SharedEd25519PublicKey.move create mode 100644 release/v13/sources/Signature.move create mode 100644 release/v13/sources/SignedInteger64.move create mode 100644 release/v13/sources/Signer.move create mode 100644 release/v13/sources/SimpleMap.move create mode 100644 release/v13/sources/StarcoinVerifier.move create mode 100644 release/v13/sources/StdlibUpgradeScripts.move create mode 100644 release/v13/sources/String.move create mode 100644 release/v13/sources/StructuredHash.move create mode 100644 release/v13/sources/Table.move create mode 100644 release/v13/sources/Timestamp.move create mode 100644 release/v13/sources/Token.move create mode 100644 release/v13/sources/TransactionFee.move create mode 100644 release/v13/sources/TransactionManager.move create mode 100644 release/v13/sources/TransactionPublishOption.move create mode 100644 release/v13/sources/TransactionTimeout.move create mode 100644 release/v13/sources/TransactionTimeoutConfig.move create mode 100644 release/v13/sources/TransferScripts.move create mode 100644 release/v13/sources/Treasury.move create mode 100644 release/v13/sources/TreasuryScripts.move create mode 100644 release/v13/sources/TreasuryWithdrawDaoProposal.move create mode 100644 release/v13/sources/TypeInfo.move create mode 100644 release/v13/sources/U256.move create mode 100644 release/v13/sources/UpgradeModuleDaoProposal.move create mode 100644 release/v13/sources/VMConfig.move create mode 100644 release/v13/sources/Vector.move create mode 100644 release/v13/sources/Version.move create mode 100644 release/v13/sources/YieldFarming.move create mode 100644 release/v13/sources/YieldFarmingV2.move create mode 100644 sources/FlexiDagConfig.move diff --git a/Cargo.toml b/Cargo.toml index a3bc053b..e6811b27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "starcoin-framework" -version = "11.0.0" +version = "13.0.0" authors = ["Starcoin Core Dev "] license = "Apache-2.0" publish = false @@ -14,4 +14,4 @@ once_cell = "1.8.0" tempfile = "3.2.0" log = "0.4.14" -[dev-dependencies] \ No newline at end of file +[dev-dependencies] diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index 01cb339d..19cd449d 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: CFA067D7641D37F19CD134995335BEBEE1410E9745B0846D1E1D05149FA4D90B + source_digest: D44931F7D1A422F556EC2F1A0AC206D39AB15F0F8669C202ED2BFCBD020CB302 build_flags: dev_mode: false test_mode: false diff --git a/build/StarcoinFramework/abis/OnChainConfigScripts/propose_update_flexi_dag_effective_height.abi b/build/StarcoinFramework/abis/OnChainConfigScripts/propose_update_flexi_dag_effective_height.abi new file mode 100644 index 0000000000000000000000000000000000000000..1c33d9a50a70defc9d79feb3f39a8fde1fd8c99c GIT binary patch literal 107 zcmY+*u?>JA5Cu@6q;?7CZ~zMjxDfcjB?Jhd;`TN+zW&Lzwo*$6oz5Tg;N@K#3Lo$zg0Xz61K>z>% literal 0 HcmV?d00001 diff --git a/build/StarcoinFramework/abis/StdlibUpgradeScripts/upgrade_from_v12_to_v13.abi b/build/StarcoinFramework/abis/StdlibUpgradeScripts/upgrade_from_v12_to_v13.abi new file mode 100644 index 0000000000000000000000000000000000000000..b1ce39d4b86795c182ea4ebf62cd95fe22aa8d76 GIT binary patch literal 65 zcmZP+FD*zfN=!+OPbZMb5Ur}7neORsd!`-RaU3Uc96NRrc3D_H3}pG(4a)(EJEtgGIUf>Q&~Ahf zLbCYy0iZb`j!66f5I+F1Cr(I62z~>CBN7*ccIOrGRDzXff1nMw?~Mi8^eFR$z^~ z49TiT*2@8FH750#F{H0?!DOxnpnklu1iVo+fln0ZY@Tcz;LYU*n466bL{CAKJ)P&o z&vXs({Mm@p?ke$fF?&A33*8>s{q@-3)f0|h6Y6SGf#B9uaPU6TwkbkPLRbEGRR}Q z*o2K@m&OFHaU-qXl-;6!_pRA`X9q_ociz5#e0EZOEPwm*WOjb|&e4O}{qu*_`|6XL zzbp<p4~e?dv|ttIy*Z#J+D4bKX@%$R~uIP>82XMft4-15U&+A zQrlL>3r<8$7PfZOu2Pb&tA4tt{!?IZs9wF1-Qc2{XScakJ<7hh*BJ}=l}}mgu;Pn4 z$2ne{(DiwpT^?4wMYN&ko%hIGSo3ZX*DquDe{q9-St}e*tt-Mx^^5*>zcW^G*rn%# zjzhXQ%btVr6h^z^*ij%!IKd^B0QHn>Nm49AMH_@H3iFnPa0yWn}W%_Dos-` z)>mcT6pI#I50lu$V#O|x<1o4^rsQZ^Hs~6`1F>*|-V#`_Crsmg*xH7{Id;;fR^z2t z_S>6DJza8|wF<@9!c^EDCM)Us1=Rs%b)j2U5VDqI1k1*- zvaWuW8@8|XZ^qsDzIo$6_kVfO2~esAW8-!JgNY_~`Jprj8AY-jsa ze|S&^JX$P4eY89TK326DjO}Q2uldZD{TBJ2oW)y~tqHWMdnV(k%NXlQLwC>RqWfOnbib(GPuKbdcQ@6S zkE^*l@Up0u>M&?_ibWl%V=rr*2R))rpuq8|+CZV6t3`FDmbe;Rb@zk0;->r4TyxtU z+aJG}Yy|!3H*9U5#?){z*zL-*ST`K%yca#9&-*dNh%DrJ47c&%F3$cJ7aaS&6nN`H z%G2(l`+YIlsNzD|kJ%Rg+^$LF>>}lLcUe!(QS_8gx~KK|ZhepXrWM!`PnAn)TY*jf zEnO?cW8BM|!t!wT-3px7{}r_D59mG#{K>)^qa?GyqfDol0nEI82XuJ6e^SO?jQ{$P0oQ1x9cquMz4|Fv*81NKio!)HVxjkE5XaLU4dck2PuqT@jZf Q3^NI~l+RIq&GKXZ4aGM~=l}o! diff --git a/build/StarcoinFramework/bytecode_modules/FlexiDagConfig.mv b/build/StarcoinFramework/bytecode_modules/FlexiDagConfig.mv new file mode 100644 index 0000000000000000000000000000000000000000..4845bb9b88b05bde7823d7d610c46fb572c844bc GIT binary patch literal 399 zcmYk2OHRWu5Qb;QuQX0WTM!6|1$z!aHy|Mp7eHcbrLE&ys!|k(=N&i#3%CT=Vb3L) z5|C=i@;v_etoh%MzO4p;93i7jisD3`YISyKZa*=5rBVJys`#Mu;TI9h5C{Z-0gxPn zB2F}NY(Sx*ObZYL=3x#74cbhg5mHMdQK2AR2*3<*0H_N@&IeFlul!TIs>0>EsbkRn zGrU~4{$jCceM&y*n;073j(lDFc^4nNTlyH5T^^g*#cCB_{BGkPUA;jqs^I3otTOn{ z&7NJ=bM`A{wVeyT@hPVNa{kwL>-wOdb4*Fwlassq*(#=`+kDb%*o^JN#-QZo*cfAB n3I&!pf;~d6h@Bk9lCPTLu`DcD9MhCkX#t5g0%2jo&I0@ZDOpf; literal 0 HcmV?d00001 diff --git a/build/StarcoinFramework/bytecode_modules/Genesis.mv b/build/StarcoinFramework/bytecode_modules/Genesis.mv index 78701566bc289c4f9bc8bc6bb1045d23b4addc26..78659547354e59fd73b0d53c4a14b6e126b99573 100644 GIT binary patch delta 798 zcmY*XJ8#oa6h6nke#F;tebdHn-f`Y>>@-Q!5*~$ymO?@N1EeZQP%2Tn1k?p07FGmS z2gKA7BnFg;Kfn(_VrE7lAy&k|F=F9L=hOGu=kcAZ`#Sq0+da*H<0=3o5H_XFp*%g6 z*omB1-pjuw?Vb8Pp}(?i^^N@$&9~y@MR#KcMJQp70oEDh8YTj!QX04}BbIB%x>VA@ zwlxHBw`1*Ii4n>a;7J4(B&d>fTEr4QWkTU?MUjF3+vH%gC07 zCJkT9(AV60Hb;0SPdq;=5H81g#k0i{**|BJ|MMQs056nDZWBjGjhMj(^j`iuHFg+1PGn{kOCRZF_JoRSX4mR+UDSD3 zG^n&@`j*c%(mv@>G|hlU2ckv1ZG{@B`|&fRqoMGvQ2nPsbSQ&zMM%-*p;+M^u_DoJ zLH#+39+MS?u01}HFs4|Eo*90kZw0hNKs$Ue>R5=r7~^)$q!xcIgk-@dOKq#oRkGA3 Q9Z>Utn)_m9zRN%1A1;nz-2eap delta 728 zcmY*XJ8#rL5T3EuuiL#n@8#^o_sHJ+&OY0@O9B{3ct09`0|gWas`L~Qv=k_D$4jE& z51jZJ2#Jy=lt>ixh=Q@8VWjyqpFOkRH}?K)zi#L6yFa)M03O1Daj|#e?e= z!ZsyngP@ND1EQ@dRo)Egv^le&rELVJY0|C0&@RHJCR-g{L)fa`I+`OKb4@3DG0pXo zx&(XCKy(@@`XDpaL}=t22xisq4_X1>jzDC!YA9N6ZXs)~1WE2j^fcOQcL?{pRJYId z2*awcdwyG!=?kI{SPZDT*eAFohEUg|hY0F2H3>aN*f=1WjYFcXD+GAeqUr`}@bwfS zxH%)e;Fg#Z-i{N(I|~xA?viEJl&$(!*bcj4FWe4wIPiDEWw;7=!@czx{=)LRIa>Qn z8SB`7fa?!Vf%v98b5Gmc;1fROGd@?FVkNV}kPFI8MdgVX%D7lnd42%YxO| zF8$&EV$7bDpShPU{Roj&J_&gqpjHD|o8CgllS}bF36OW0fB$Sd+qSEzS{ssR4jDAt* diff --git a/build/StarcoinFramework/bytecode_modules/OnChainConfigScripts.mv b/build/StarcoinFramework/bytecode_modules/OnChainConfigScripts.mv index 0f740c0f6df21985ee711eba23d3b09ba32d0854..8d847cdf257fe6e822b0a9ca4710a4573aa7c13a 100644 GIT binary patch delta 496 zcmYL>zityj5Ql#=yL+>DyZ6t&T;kY~XedJC4!K1_JOCAl;$$UvjwKXZU?75mB2R#> zMM%_0yagQ+9UV$X0S%A9UXa2TvopW%oB3sb#&18)e!B>OCDdHsQg=K3o<`;~eIWVD zm&SgR!e7Y`3J!sxpkWX}U=bsUA_0+rS)i1_m;kIGjs-~~fV;+?iA9jAa3<5C@$EqpF9QR{<%<3(Y2=YC!o-XgCUC9XoPd7G4KeJGF>d bLOdDV^2QamA)NO2^ei3uJgB+L7MAfBSd%`^ delta 375 zcmX|)D^dhe3`KA9@;*Iz{hgj4j75W-6|f2f4v9h`*Z_v=s!58FdPIP0TBs> z_Yp)9%n>3HF&a)0MG=9?Zlp|XG&?&`ibXX>?JXMXPSFNJ=wgDK?o{ft!p*92jpt1b zSu`Eua@HfQngxo3gOxofCR%E%Q=RKl5AQxMJ0ea%+MJz1r@V122D=fKdnoJ;_JxviTV*j<)NMQm!;8_a W_io^5a5cQjx@>Z7YOU2KGX4SUPa#48 diff --git a/build/StarcoinFramework/bytecode_modules/STC.mv b/build/StarcoinFramework/bytecode_modules/STC.mv index b462ed908f1f2910168bbd9515060d11ca25c6e4..213831b4eadcf00d73097aba35795e5f129f2575 100644 GIT binary patch delta 404 zcmWlVJxT;Y5QSe=*Gy0U%%=r7P zh|k$C$p ziRECZ^P6#`+#0psZAw_g6`D-KJNmrarPU^-b;*}|E6pA~a2A^nsyoHx^899Yd^SD0 zzPgxA-+t(j(*Y6FusM(^?Ke+yGV!Q=K-~$BjV@1IcUkXmMahYZap_Sm>Mv2<8`L4P PO0Hux>dNaPnD*v>@kA$* delta 373 zcmWlVJx&BM427Q^&m@y%W@ncD-&t5-si8qiLB$ym9D!qOK}k6+LZadTloVWm22pYY zH~R^DloebXb^d-E#p)7JT~HU7_5@z(uN zdE;5@2@C^4h8z|S1v~;GN@$2G!Z{&OXrj{1dghCWqOd4S3nB|^EwM$JHYQ=W(Wl)JwOyn&4;S4D-F0tt`ZVS<&L>1n)9y;H>9~85%kzNbL%~L8 kBu)d?6?;*0refK6G$Z{6O3gHd$SOI-Xw+4vDwuw?e;JV>Jpcdz diff --git a/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv b/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv index b53e7f3f3f9a2d1ee96f357fcec55bae401585af..86dbbec48c8d76bb2d444b2814bf40508a906a82 100644 GIT binary patch delta 789 zcmZ{iyKfUg5XNWb_HOUxwb$pf9otFlBG{5^a-|T2~bI%Jebmvv$d*A?ohtQ?&jCK77 ziceItztIPjZ^UQUy`L*M&vJLe$Lh<|&ioO?P6D>m0RqIS z(NHnEYA|9@GpG}zVbrL_7&90*XbMKls0o8fhC780xQRq?5*LBmaD)&}qX#nKHuem+ zDI|>IEF))>m-q<5oELzY4-sX40g$BhI;QjlDDaa!ml}m9757*|8`QEcqKH>Yh{9S0 z)}_e2*rB&g+D zg^6e~o{Fa9nRqsuix;9!)XnZ;%STH%p-+}i*=zioS66Rt9qwG|4=xXHZSM@SC$wgZ zjsE_P>?1v>*EWZ}gWH3>{^nM1dvCbgyR*2|+aL04Ioq(_RxAHAe_D@Rd9b?D+wC8| zdnm5aQBErfA^PB>R)8pizfI?n@Zl)BXVk@;2 zq$0JE4@tI>6B@`pmPj7U>MUm?b3rGer`y>}*~Izmy=EyoS>2o=4wfK#ZYRBf%JZ zOeACK)y!kgP!)!tYK0Ki5dtl^BG_XjH6z>KF^!i|%_HjrZ9pDcMAcaWl2Xyi=WZZ@ zxK26MD?CcL$rb~!H(idhxYb3J;tsIR@AmpA)BD2_1P?evJPgL{J(^4r@@B@Kcs%B8 z_XIT*Pv@%&Wp`QgjeWLYmZsO4X0u{mR>fYqUmg^P<*Ha0oAw>nT837W(1fDB#Gma2 z9k;*fb$c!@+86Tl%auH#opDxyrzbd#BWhco5aK1)r`e%Ydbk>3GI=+$=h7Ii=eUpkj=Y%1Mlr zry;@iXFZVFsX$@gugRXxpx!w&u>L%1<%N#v;s&VN4K2A#Xz8@v(*eUpY-n(~Z7A)J zK!Yn9VY#_QxY}w@c}+e3y4rDLTerNa<>uD70ma*s3E|FE#k(`z0S7y}UcQ%hYC mKuIc!oMT0TXd=fVIw^CfI$c|cVFyyuqRWVNPF~f(t+Zm>6GwzCdDUnnE|K!GG23*g?KvL@=Oq(OP*g$CI7M) z|9KxNByOv=ZktxOrX8=}pw1yjRz|jBwSI?Jrvwk!42Bw1B6%^}tgIEMQA!y($dVrs zp(QF7kM%#yLF)-Ggy;Nrv*Ew$^mgY;|)NhO`)=8yf!{{j3use 0x1::CoreAddresses; use 0x1::Errors; use 0x1::Event; +use 0x1::FlexiDagConfig; use 0x1::Hash; use 0x1::Option; use 0x1::Ring; @@ -83,6 +85,12 @@ Block metadata struct. number of uncles.
+parents_hash: Option::Option<vector<u8>> +
+
+ Hash of the parents hash for a Dag block. +
+
new_block_events: Event::EventHandle<Block::NewBlockEvent>
@@ -133,6 +141,12 @@ Events emitted when new block generated.
+
+
+parents_hash: Option::Option<vector<u8>> +
+
+
@@ -309,9 +323,10 @@ This can only be invoked by the GENESIS_ACCOUNT at genesis account, BlockMetadata { number: 0, - parent_hash: parent_hash, + parent_hash, author: CoreAddresses::GENESIS_ADDRESS(), uncles: 0, + parents_hash: Option::none<vector<u8>>(), new_block_events: Event::new_event_handle<Self::NewBlockEvent>(account), }); } @@ -407,6 +422,42 @@ Get the hash of the parent block. + + + + +## Function `get_parents_hash` + + + +
public fun get_parents_hash(): Option::Option<vector<u8>>
+
+ + + +
+Implementation + + +
public fun get_parents_hash(): Option::Option<vector<u8>> acquires BlockMetadata {
+    *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parents_hash
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
+ + +
@@ -453,7 +504,7 @@ Gets the address of the author of the current block Call at block prologue -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64)
+
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: Option::Option<vector<u8>>)
 
@@ -462,23 +513,26 @@ Call at block prologue Implementation -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64) acquires BlockMetadata{
+
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option<vector<u8>>) acquires BlockMetadata{
     CoreAddresses::assert_genesis_address(account);
 
     let block_metadata_ref = borrow_global_mut<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
     assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
+    assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH));
     block_metadata_ref.number = number;
     block_metadata_ref.author= author;
     block_metadata_ref.parent_hash = parent_hash;
     block_metadata_ref.uncles = uncles;
+    block_metadata_ref.parents_hash = parents_hash;
 
     Event::emit_event<NewBlockEvent>(
       &mut block_metadata_ref.new_block_events,
       NewBlockEvent {
-          number: number,
-          author: author,
-          timestamp: timestamp,
-          uncles: uncles,
+          number,
+          author,
+          timestamp,
+          uncles,
+          parents_hash,
       }
     );
 }
diff --git a/build/StarcoinFramework/docs/FlexiDagConfig.md b/build/StarcoinFramework/docs/FlexiDagConfig.md
new file mode 100644
index 00000000..81441e26
--- /dev/null
+++ b/build/StarcoinFramework/docs/FlexiDagConfig.md
@@ -0,0 +1,166 @@
+
+
+
+# Module `0x1::FlexiDagConfig`
+
+
+
+-  [Struct `FlexiDagConfig`](#0x1_FlexiDagConfig_FlexiDagConfig)
+-  [Function `new_flexidag_config`](#0x1_FlexiDagConfig_new_flexidag_config)
+-  [Function `initialize`](#0x1_FlexiDagConfig_initialize)
+-  [Function `effective_height`](#0x1_FlexiDagConfig_effective_height)
+-  [Module Specification](#@Module_Specification_0)
+
+
+
use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::Signer;
+
+ + + + + +## Struct `FlexiDagConfig` + +The struct to hold all config data needed for Flexidag. + + +
struct FlexiDagConfig has copy, drop, store
+
+ + + +
+Fields + + +
+
+effective_height: u64 +
+
+ +
+
+ + +
+ + + +## Function `new_flexidag_config` + +Create a new configuration for flexidag, mainly used in DAO. + + +
public fun new_flexidag_config(effective_height: u64): FlexiDagConfig::FlexiDagConfig
+
+ + + +
+Implementation + + +
public fun new_flexidag_config(effective_height: u64): FlexiDagConfig {
+    FlexiDagConfig {
+        effective_height,
+    }
+}
+
+ + + +
+ + + +## Function `initialize` + + + +
public fun initialize(account: &signer, effective_height: u64)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, effective_height: u64) {
+    CoreAddresses::assert_genesis_address(account);
+    if (!Config::config_exist_by_address<FlexiDagConfig>(Signer::address_of(account))) {
+        Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height))
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+ensures exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
+ensures
+    exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(
+        Signer::address_of(account),
+    );
+
+ + + +
+ + + +## Function `effective_height` + + + +
public fun effective_height(account: address): u64
+
+ + + +
+Implementation + + +
public fun effective_height(account: address): u64 {
+    let flexi_dag_config = Config::get_by_address<FlexiDagConfig>(account);
+    flexi_dag_config.effective_height
+}
+
+ + + +
+ +
+Specification + + + +
include Config::AbortsIfConfigNotExist<FlexiDagConfig> { addr: account };
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+
diff --git a/build/StarcoinFramework/docs/Genesis.md b/build/StarcoinFramework/docs/Genesis.md index b04939f0..1f9b39c3 100644 --- a/build/StarcoinFramework/docs/Genesis.md +++ b/build/StarcoinFramework/docs/Genesis.md @@ -24,8 +24,10 @@ The module for init Genesis use 0x1::CoreAddresses; use 0x1::DummyToken; use 0x1::Epoch; +use 0x1::FlexiDagConfig; use 0x1::GenesisNFT; use 0x1::GenesisSignerCapability; +use 0x1::Math; use 0x1::Option; use 0x1::PackageTxnManager; use 0x1::STC; @@ -464,6 +466,7 @@ The module for init Genesis Option::some(0u64), ); BlockReward::initialize(&genesis_account, reward_delay); + FlexiDagConfig::initialize(&genesis_account, u64_max()); // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init. let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay); @@ -509,6 +512,7 @@ The module for init Genesis }; StdlibUpgradeScripts::do_upgrade_from_v6_to_v7_with_language_version(&genesis_account, 6); StdlibUpgradeScripts::do_upgrade_from_v11_to_v12(&genesis_account); + StdlibUpgradeScripts::do_upgrade_from_v12_to_v13(&genesis_account); //Start time, Timestamp::is_genesis() will return false. this call should at the end of genesis init. Timestamp::set_time_has_started(&genesis_account); Account::release_genesis_signer(genesis_account); diff --git a/build/StarcoinFramework/docs/OnChainConfigScripts.md b/build/StarcoinFramework/docs/OnChainConfigScripts.md index f2072a84..42b2ea89 100644 --- a/build/StarcoinFramework/docs/OnChainConfigScripts.md +++ b/build/StarcoinFramework/docs/OnChainConfigScripts.md @@ -11,11 +11,13 @@ - [Function `propose_update_txn_timeout_config`](#0x1_OnChainConfigScripts_propose_update_txn_timeout_config) - [Function `propose_update_vm_config`](#0x1_OnChainConfigScripts_propose_update_vm_config) - [Function `propose_update_move_language_version`](#0x1_OnChainConfigScripts_propose_update_move_language_version) +- [Function `propose_update_flexi_dag_effective_height`](#0x1_OnChainConfigScripts_propose_update_flexi_dag_effective_height) - [Function `execute_on_chain_config_proposal`](#0x1_OnChainConfigScripts_execute_on_chain_config_proposal) - [Function `execute_on_chain_config_proposal_v2`](#0x1_OnChainConfigScripts_execute_on_chain_config_proposal_v2)
use 0x1::ConsensusConfig;
+use 0x1::FlexiDagConfig;
 use 0x1::LanguageVersion;
 use 0x1::OnChainConfigDao;
 use 0x1::RewardConfig;
@@ -303,6 +305,43 @@
 
 
 
+
+
+
+
+## Function `propose_update_flexi_dag_effective_height`
+
+
+
+
public entry fun propose_update_flexi_dag_effective_height(account: signer, new_height: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_flexi_dag_effective_height(account: signer, new_height: u64, exec_delay: u64) {
+    let config = FlexiDagConfig::new_flexidag_config(new_height);
+    OnChainConfigDao::propose_update<STC::STC, FlexiDagConfig::FlexiDagConfig>(&account, config, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + +
diff --git a/build/StarcoinFramework/docs/README.md b/build/StarcoinFramework/docs/README.md index 3f151f78..abbf5f43 100644 --- a/build/StarcoinFramework/docs/README.md +++ b/build/StarcoinFramework/docs/README.md @@ -43,6 +43,7 @@ This is the root document for the Move StarcoinFramework module documentation. T - [`0x1::Event`](Event.md#0x1_Event) - [`0x1::EventUtil`](EventUtil.md#0x1_EventUtil) - [`0x1::FixedPoint32`](FixedPoint32.md#0x1_FixedPoint32) +- [`0x1::FlexiDagConfig`](FlexiDagConfig.md#0x1_FlexiDagConfig) - [`0x1::FromBCS`](FromBCS.md#0x1_FromBCS) - [`0x1::GasSchedule`](GasSchedule.md#0x1_GasSchedule) - [`0x1::Genesis`](Genesis.md#0x1_Genesis) diff --git a/build/StarcoinFramework/docs/STC.md b/build/StarcoinFramework/docs/STC.md index b22272d5..9abaa8ef 100644 --- a/build/StarcoinFramework/docs/STC.md +++ b/build/StarcoinFramework/docs/STC.md @@ -22,6 +22,7 @@ It uses apis defined in the Token
use 0x1::ConsensusConfig;
 use 0x1::CoreAddresses;
 use 0x1::Dao;
+use 0x1::FlexiDagConfig;
 use 0x1::ModifyDaoConfigProposal;
 use 0x1::OnChainConfigDao;
 use 0x1::PackageTxnManager;
@@ -268,6 +269,7 @@ STC initialization.
     OnChainConfigDao::plugin<STC, ConsensusConfig::ConsensusConfig>(account);
     OnChainConfigDao::plugin<STC, RewardConfig::RewardConfig>(account);
     OnChainConfigDao::plugin<STC, TransactionTimeoutConfig::TransactionTimeoutConfig>(account);
+    OnChainConfigDao::plugin<STC, FlexiDagConfig::FlexiDagConfig>(account);
     withdraw_cap
 }
 
diff --git a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md index c0cec6c5..358ba2c9 100644 --- a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md +++ b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md @@ -17,6 +17,8 @@ The module for StdlibUpgrade init scripts - [Function `do_upgrade_from_v7_to_v8`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v7_to_v8) - [Function `upgrade_from_v11_to_v12`](#0x1_StdlibUpgradeScripts_upgrade_from_v11_to_v12) - [Function `do_upgrade_from_v11_to_v12`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v11_to_v12) +- [Function `upgrade_from_v12_to_v13`](#0x1_StdlibUpgradeScripts_upgrade_from_v12_to_v13) +- [Function `do_upgrade_from_v12_to_v13`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v12_to_v13) - [Module Specification](#@Module_Specification_0) @@ -26,10 +28,12 @@ The module for StdlibUpgrade init scripts use 0x1::Config; use 0x1::CoreAddresses; use 0x1::EasyGas; +use 0x1::FlexiDagConfig; use 0x1::GasSchedule; use 0x1::GenesisNFT; use 0x1::GenesisSignerCapability; use 0x1::LanguageVersion; +use 0x1::Math; use 0x1::NFT; use 0x1::Offer; use 0x1::OnChainConfigDao; @@ -354,6 +358,57 @@ deprecated, use do_upgrade_from_v6_to_v7_with_language_version. + + + + +## Function `upgrade_from_v12_to_v13` + + + +
public entry fun upgrade_from_v12_to_v13(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun upgrade_from_v12_to_v13(sender: signer) {
+    do_upgrade_from_v12_to_v13(&sender);
+}
+
+ + + +
+ + + +## Function `do_upgrade_from_v12_to_v13` + + + +
public fun do_upgrade_from_v12_to_v13(sender: &signer)
+
+ + + +
+Implementation + + +
public fun do_upgrade_from_v12_to_v13(sender: &signer) {
+    {
+        FlexiDagConfig::initialize(sender, u64_max());
+        Block::checkpoints_init(sender);
+    };
+}
+
+ + +
diff --git a/build/StarcoinFramework/docs/TransactionManager.md b/build/StarcoinFramework/docs/TransactionManager.md index 08ac2657..6477ab0d 100644 --- a/build/StarcoinFramework/docs/TransactionManager.md +++ b/build/StarcoinFramework/docs/TransactionManager.md @@ -28,6 +28,7 @@ use 0x1::Epoch; use 0x1::Errors; use 0x1::Hash; +use 0x1::Option; use 0x1::PackageTxnManager; use 0x1::STC; use 0x1::Signer; @@ -464,7 +465,7 @@ Set the metadata for the current block and distribute transaction fees and block The runtime always runs this before executing the transactions in a block. -
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64)
+
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: Option::Option<vector<u8>>)
 
@@ -483,6 +484,7 @@ The runtime always runs this before executing the transactions in a block. number: u64, chain_id: u8, parent_gas_used: u64, + parents_hash: Option::Option<vector<u8>>, ) { // Can only be invoked by genesis account CoreAddresses::assert_genesis_address(&account); @@ -502,6 +504,7 @@ The runtime always runs this before executing the transactions in a block. timestamp, uncles, number, + parents_hash, ); let reward = Epoch::adjust_epoch(&account, number, timestamp, uncles, parent_gas_used); // pass in previous block gas fees. diff --git a/build/StarcoinFramework/source_maps/Block.mvsm b/build/StarcoinFramework/source_maps/Block.mvsm index d8622d6945e2508b88dfe63c3ea905c9b6f1a4e2..496f52b178d1292b16b76122ee2d551612b11341 100644 GIT binary patch literal 18845 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 xqN2hg@8rS~@6Q8Ok7@t_ literal 17908 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 G3+G>YAp)uZ diff --git a/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm b/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..54039ad5cf8f753a09ca27ac5390e28f5bf33bfe GIT binary patch literal 1368 zcmb8vKS%;$7{~GVPR}ciurX?B3fhCnO~oOIrsm@~?;nW{ofS=ia}YGSL{M2nqXZRg zjnNhq(biUr5Dg8{_YH)$=MsLCpXYhs_jz9(>^7?Vmp9L!=h4T`T`97=?)}>9pgZmM z9-WuM`>axGo*3ls#~80Q{H?g^hLu(`h(o>~2(8+fj_zYfa>7(ad0 zd98Lck(!s#WnvTqeFCTMhK~1p2C1@6Rif9j!HaQOfL literal 0 HcmV?d00001 diff --git a/build/StarcoinFramework/source_maps/Genesis.mvsm b/build/StarcoinFramework/source_maps/Genesis.mvsm index e57886a24d34045aa153bb0793d4dbbf20d70c17..666697f9d8888c8e4b77e2cbc80520446aca0537 100644 GIT binary patch literal 25361 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 diff --git a/build/StarcoinFramework/source_maps/OnChainConfigScripts.mvsm b/build/StarcoinFramework/source_maps/OnChainConfigScripts.mvsm index bbb6c439775f53cc4d06fd655dbab3c903ddd7d0..69c18b0b35ff0f49ebd4e71be7f4b5b454d0d55a 100644 GIT binary patch literal 7493 zcmb7}ZHQD=7=X{X+kUV6y}GXUp#~N9!!RZ*8n%5Hb>+?l!U%)R5>8E01t zqoN|xABBJFM}kzMk!x7AScVwNVhZNR_Cfi9L>W|;MPXsjncV>k;yoig;*aM&=bm%k z^WM3y_SW^g-v05$?%OMdnlHq6HVrQPBJ$J0`Q6EuzwdgecW~J>rPN%Az_ouOttS7Ivc8LrEFoum6MbTAW}IR+9L&|k@GOF(srC6=VzsWEy!D;Hk}F5 zL1-r}FDk{nj=vL>x=vog6~wYmy(!YL-(i+xjuXuatR^TE&3%m7j9D(4+G+uV2Ynjt z4H#G56ZE-$&p_Ih*7hd)ZZJK^L%2uv6pf?j;$|#68qK(2D9v<%sLN2wfnLS0nXC`A zTt3hT5Z8iypbulkKt9k;tT@OAs;vYV40?roIB6Vez3FA>#GVRGIp0aTR>sb{R@TnM zUGW;lh{{8IuN}HpZ!&QDtgM$Z4gY}9W6)Lz&$xLz6SdMDdSN8#$Q#O(nhsO`8$G%V z#&KM^62utc8EA6Tfs+_pgHa9ngs4+6`I^N?y;#h1a>?v~mG}H;ke3$GPU>|*TgvlG z-@uT_7YfmKf9cV~M1BJug$1M-qOfzJ`4QYeC7cJX*K9%D4y~k@^2FpBAaFBOg;||) z@d0VCjv=3h8n@qdtf-r`#gO(2rEY{sqZ9a{>xa3};$OUuq{(Izbswl^xiP2&Il~VV@c+p&lwF(+Ua}CxyXcWzhtmaY7 zCehTE1qNw%V4_kNL6w=lXMVu`1!{aZZzWtWo)BxqU+5JbC0+S?^a&8DFuUk8aJzuK z6t`zBo}k3`f{V^ea$8MvkDLgGh6>-!D#S1?j9oHT|8q zsycRtZI>$V61>$Qr)3XT3gon`#qvQ;%i@#DX*t4pXFyKNb6CHEoR+^~T?IKU`>|BL zzUR_@YAXT;gRVz=S*yms&tAcP6&j;CKFG)fD|D$;QL*`QmY|=Zgan*5Ua7lbGy!$b zAjoA6Kh0JX7X_2LxD9Vm&m(Sa9BU8A30Rz8PQXbGbXGu4!0A|XKu*AUSc^bTz`|b*2SaPC!y8z`O?ohqnYI-TwU&@gl}q8>Sk#0$;b_^6&l9H zh{-``JQ?)T-c7lwATu!9*%+X|4Qv# zPWnV%DwneST&kB=T@Wh_W3-4zh|fd2-iCC>b9mb^L~#?ON7zH?;X*jAs?x(FEvz1< z=uX$QhY)%jT}!v$*aq<+RxyIFM=CxwDQPG5+d9UX1{rA)JBa-lTBB~vrcr2({f~vE zpF#@$lfe4ck_zqp=&K-7y&+{-UlZu-L4ou{FX3zhxxT)G^%2PR^$6CtAlKK+SZ!@4 z^>rH7e30wwGOS*Z>uVb8d64VtR;)pgU-0{}PJ-O}I*;`S$gQu6cBQ6)-1?e{wG`ym z*MnG(gWUScaz=faa_g&@cXI1%FXMd(a_eh9)?tuaU&B}@pjpiM9M(x_5lwBK0;T=| D;CfLm literal 6912 zcmb7|ZHQD=7=X{Ly0f3|uFihy5-Mon4@)bFO){6X4^6BMvJWnI?%bKZdFS3??p${_ zGJ?|BBC!l9TEq`9*VgPq-5-JeO42C&q5i2rq9jtY=tB+4o;$MxTM+LV;gS9Eyywh0 z=RNN|=M3M7?^x1RZQMA0>rac0bgUTJy~@43=!fUe4d2`K)~Vpbc}l6J5QEA8Vu`h0 zZ@=kyy}p-rGLKq$CsznmjZ(uxi#s}$ItsCPDYQ=t7)L$^RdLg@{Lm{%0cVlFhWcFI z&-sDr8cs@zxq$x*C^bzU!ir9%9)y@U*hN?mL6vB(!Fn8~h-MYmdYCGjk@W;<{LqtV zm!PV)&);BseM320nzGC2e}L{fHg+kMfU4%wy4ZQcOr`R65J){OB&r80SmZsZ zaiX>%?gDv1_h20ac|ns{?}NOck#z_(8a>TEyb|rjM%~TuGxk+z2|dfTjl5Z~je?oa z*y1+osZwe+v?a~JHj=JyZ7>Q>RyX`LLia*zF+6V%nE8~EW6_H(NlX46k=LR7ztN>( z(2ixxm7r$|n+jU&oNx6{j6ti0yiL>rm_2FmDJPwFtk5kC83T@&@&}|rT%>_G>DQWd zyvir=ej=YPMw^3`NAD!^W9TdnAWIX)nG5un;5VWhsfLM3Q;;zO!*#Nbm^=>?n1q_3 z5T#sZNSdp?$nQa&J!o4-%63gL{%xi*YqodCJmpTYVbris<=SFEPEQq`i_jkOr!qPZOFF{lwu3+p+k z70p+$c0!$Kj$s{!deQ7=>_;#gM6;YDjiTAWsV4!`MY9cSJ~WBu%~*?}Su~F`nkASm zq8VAYgGSo5v@3N7s42SNnLDwULA_@W7#r<;;P{@j4Oihm0u}7}_2?GF8eG%M=yo(n z#7m%aJ{`e(H|jy0&zG_GgS_9%{mc9P2JOW;hsyiC7ONHH{oal>2ju#`ex`&iIR!lqHTsn?@0vaYx4O(A=c&$=1p@L*uhyEnQ8Yeo^`+DRE*#tV-vO#z>7qAY3oK5BaK|7q>V_Mtfya+W3&jKHQ+rNn#l5rRI2 z3KFnpI)`E?C17;j^TUGXsd@o%cY#h_4DmKc{fMc0H`W%A6R_OBoPbwo?<&X%cpa<0 zNhbjtvD!gSz-_eIfhi|oWOaguI*hhEQk!(^;vVc#NH`vsw9qPLmep@Zgh2SyZ!JPkTV<7Knwsf9W zVl7dP=Yq~f)eFqhG(`8@&~pmn7V9Cp4?5iFP32#0SYg3Wr=^M9O7K2tFRlXrIhGOi zUVJHGMx^-j#9oD2T=AW3m^HjGo8*{3U_kLIs6(c7m%Q#A-KYHS6m#^p&7M`b8#A2y%UW5$g?* z>+3G8Pe87(C$WA6xxQY*YH8J}uQy>W1-ZW7hxHW5_4OI7%^-i^w_}Zh{Aw|d^##bU z7GGgq1NqgWx{d7t@~g!{tb0IywRnJ;UydoiT9ornezh2;z1Km0wb+g|0`jZHPOSYf SL(KUHu|{F0XhzlnQ0gBB6x8nk diff --git a/build/StarcoinFramework/source_maps/STC.mvsm b/build/StarcoinFramework/source_maps/STC.mvsm index 5eb95a23f022310c189e14d075a8b1d76bd8dc72..b3995b5ed6ada3d9ebfc7f1fffb8710e0235167a 100644 GIT binary patch literal 6236 zcmbW5Yiv_x7{}js*KQrO9pE7brxcumvYSPTNHQ7^tE%%<{0M=YReRF$WV$z)v{DgO znxV{HV2rOf8Vg#XR5TuQwo)HOwcsv(GM$VCLsmjvstzEnEVowUM{V4}xzR5;6% ze-%uF{snC30y{uIq@7q{&=2W)tO)3b^lhy7K|iGXu|5F(kY=~7P(IF|(eFzrlI9Os zzd*4xzry+zJktCa>m-y&vz)W6f>LQVVciK{X>P`9gEDD$VZ~vdGzYOpVZJo4bKl1> zebSu7ItPAfzJv8G1fnT_)%?GdsV2LzOVSNMD(maTD7HXvF_pn2-RGJs)SBY6G z%{122P$$g>tU;)krfuy92d~;*FIx|$(CL_c2KxwjQ}LA56SR7r%;q;JIBpl^GMi6Q za2j%(&C^s|f?Jr)zf+c1b_=uFPf;D@JD$yF<{2{up8s~SFBMYL{2cu+*o(_`nz#6j zX$9}zXlhqDY3+5A9p|%Y!P*Qu0+eC}Ku3VxSV_oVvF@Gw>ebOcz+t85wQ2ylab%Q1BX7{D3^9RVJ~8UY;v zvaeko0luK$BUJ81{n!<157X{v+d9Er;_CI7I>BX+K_|El`gPhXkUQUnwG(uL zyAP`ybb`yCyiRcM((gFv1UH0r0(63#z?ud95$9*DIpDprZF}pMt?gUe9x>)$ZctPJ literal 6152 zcmbW5U2Icj7{}jk?O038y3Z;Ijt@al$U^X9_z@zY3=^o`a7vVN*49~FKP;z=`2|rE z4Hu#p#)wl9Ok@M2Sx}HjAet$9A(%MyLeU5t+)P9iCVu{^H1Y0#YLnmH?|IJY`@ZKq z|2FvKoY4ap|D4%!G&H68)l+8=hWeIQ4d3zhqJ92kZ{vGIn~X6}fD8Wnah12WEiN-A zDC*nGjad!G<d0ik_ihD+DeTWfQq%Ca$XbsCXA@E>%64&*bu{XwI?|s&tUDFCmyp zrlVHOPG-{1?sS-nC6q z7nle7kTzj8gFd8wtc9Qt>3Xb3K_Ajqtj9nf(&DmJ$m9Gh{a%1^(tHQ&08~ozMXZD1 zmFCk}TfisH(^zL zyRlw}8flJU{ROqs9K_;ym^x_|pSgNz-blYC&>+nSRtJQn>BCCFWzuw4a*p6~X%5iO zk2z7A%dl3$BxyEah2aWmZpC^HCQEZQ)^?a8%@M3oxKf(Cv3`I?X)gB~b306x<{14V znA4vtM+C;OAn^P>6pC>doB3wjBRyAt(245ypDp6g`!es^A-wTg3@MlKNWl7 zf6V5ODEkUZp3Nf^od>t$*}QFnF+0Kg?<%gdV``f32pF>)N}lGvAkQH9yOZ{P@toD| zBs-ksN> z104a1&zg<^r|EYFbOZ=g8B-5B0-U8^2vbLZ?=Vk+jsT13cPr=!unNlp9RV^}kARK< zo3VO9M}U5;{h%YjG^|0;5#VR6-#|xzBUrzKjsRg^kL{o%z+|jDK}Ue%YqwFpKcA;x zFX#x+kF_6k1n9sTgz56?cUKz|gBjBFVa4GpX>P-M17=DyjkObIN%JSHU*T$L4q#n` z+0wkJ#+aorN1AS|Ti_aLZpZ3_Yo!^+>W8_~+=F!p9E`(UtuY(G$HdVzv+ zA9=-jOxuON2TDp?p7H!Z1%{bi|0vDx1)a8acDAowkZQuhZ5B`fUWAwpL+n0-d%t aV-0{#Tkm5X2Hq>-$kN3vtt~5881pw%3dyDb diff --git a/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm b/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm index 34fb9e4f915f1d6450c50da7094f2353aa6ae0ce..60eb9a5c2b2c54d96f13b5be183ab965c24e1b41 100644 GIT binary patch literal 7177 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 DD*J)R diff --git a/build/StarcoinFramework/source_maps/TransactionManager.mvsm b/build/StarcoinFramework/source_maps/TransactionManager.mvsm index 7857e07039d31ee721c5970b2f7517ba216d5f3a..2d9cf9915d3a66a35fc57844edb193159384abb6 100644 GIT binary patch literal 19100 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 literal 19005 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 diff --git a/integration-tests/block/block_metadata.move b/integration-tests/block/block_metadata.move index d759ca9e..5a5d47a4 100644 --- a/integration-tests/block/block_metadata.move +++ b/integration-tests/block/block_metadata.move @@ -4,6 +4,7 @@ //# run --signers alice script { + use StarcoinFramework::Option; use StarcoinFramework::Block; use StarcoinFramework::Debug; @@ -11,5 +12,10 @@ script { let hash = Block::get_parent_hash(); Debug::print>(&hash); } + + fun get_parents_hash(_account: signer) { + let hash = Block::get_parents_hash(); + Debug::print>>(&hash); + } } // check: EXECUTED diff --git a/release/StarcoinFramework.v0.1.0.blob b/release/StarcoinFramework.v0.1.0.blob new file mode 100644 index 0000000000000000000000000000000000000000..0113b47224d724fc1f0f4cc9d87cafddf0bdbbe0 GIT binary patch literal 114284 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 Gm45*QfxX@U literal 0 HcmV?d00001 diff --git a/release/v13/BuildInfo.yaml b/release/v13/BuildInfo.yaml new file mode 100644 index 00000000..f8c5d3a0 --- /dev/null +++ b/release/v13/BuildInfo.yaml @@ -0,0 +1,20 @@ +--- +compiled_package_info: + package_name: StarcoinFramework + address_alias_instantiation: + StarcoinAssociation: "0x0000000000000000000000000a550c18" + StarcoinFramework: "0x00000000000000000000000000000001" + VMReserved: "0x00000000000000000000000000000000" + source_digest: DAD01288B0F425AF6BF3F9B3EB48FD863E6736AC99B2C8B99B0C73C848ACE126 + build_flags: + dev_mode: false + test_mode: false + generate_docs: true + generate_abis: true + install_dir: ~ + force_recompilation: true + additional_named_addresses: {} + architecture: ~ + fetch_deps_only: false + skip_fetch_latest_git_deps: false +dependencies: [] diff --git a/release/v13/abis/Account/accept_token.abi b/release/v13/abis/Account/accept_token.abi new file mode 100644 index 0000000000000000000000000000000000000000..9d200103bba4cab95e514b53ebb285d0c755d619 GIT binary patch literal 52 rcmZSNNlZ>oEhvdE$Z_oEUXM5 literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/accept_token_entry.abi b/release/v13/abis/Account/accept_token_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..2b482dca062b2318b5715c6fbd3be6f34420187e GIT binary patch literal 58 wcmZP+N=!~pEhvdE$tTo6?yl?AB`0Jb0ww*UYD literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/create_account_with_initial_amount.abi b/release/v13/abis/Account/create_account_with_initial_amount.abi new file mode 100644 index 0000000000000000000000000000000000000000..3a0f339cc353d4570b0cde92a85dbb530355c5fc GIT binary patch literal 117 zcmZQnN-j!GEJ=+|Ois=(%`1s7&n(G^&&21c%u{Or`c n_>#(kRA%0^qSWGy_{5YHAYIJD8J}1RG$}i^l8uoM)jVbZNYf;R literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/create_account_with_initial_amount_entry.abi b/release/v13/abis/Account/create_account_with_initial_amount_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..85e0e210662cfb028ed70d85cd0bf586e27de61b GIT binary patch literal 111 zcmZS7NG?iEEJ=+|Ois=(%`1s7&n(G^&&b8nw4&7FjQGTq6d+y9!iQ=SGXTNfBT@hW literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/create_account_with_initial_amount_v2.abi b/release/v13/abis/Account/create_account_with_initial_amount_v2.abi new file mode 100644 index 0000000000000000000000000000000000000000..4c1f45295a18a8131e201e656fe1455d6ab3bb48 GIT binary patch literal 108 zcmZQnO)g4JEJ=+|Ois=(%`1s7&n(G^&&FKOw~c literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/remove_zero_balance_entry.abi b/release/v13/abis/Account/remove_zero_balance_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..fbf4971e07f1b4f09419d14af5065dc92ff9ac6f GIT binary patch literal 65 zcmZRSEK1GIFH4QDN-fHdPfE;5%u7yod$@!&uB@B#QCHdK@dGRHc H1*r@GXD1P$ literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/rotate_authentication_key.abi b/release/v13/abis/Account/rotate_authentication_key.abi new file mode 100644 index 0000000000000000000000000000000000000000..d69bd3711090057f9356eb8be41ea954ddfce013 GIT binary patch literal 64 zcmZRSEXprQEJ=+|EG@}M%`3@FPAtjH&x_Aatzod$@!&uB@7IV?0Ko>ASG;! E08^3>X8-^I literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/rotate_authentication_key_entry.abi b/release/v13/abis/Account/rotate_authentication_key_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..81a17ade1bde1b646230c12657146299bc2584b8 GIT binary patch literal 70 zcmZRSFUl`TEJ=+|EG@}M%`3@FPAtjH&x_Aat&9h9iz*pV0VBI(a&mrYUI_yOBYR$I JIY=QJBLMs_68-=H literal 0 HcmV?d00001 diff --git a/release/v13/abis/Account/set_auto_accept_token_entry.abi b/release/v13/abis/Account/set_auto_accept_token_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..9b5dab255076407f3479733b0c47c4deac06427f GIT binary patch literal 64 zcmZRSE>10pPb@9Tk55caPAw>jFUikN&5KXXD=DgEKn0BKj>*aSrFkU`42*24d5K9m GsSE&O@erf{ literal 0 HcmV?d00001 diff --git a/release/v13/abis/AccountScripts/disable_auto_accept_token.abi b/release/v13/abis/AccountScripts/disable_auto_accept_token.abi new file mode 100644 index 0000000000000000000000000000000000000000..3661e68024d18bfd36fc740cc47c41d61d85495b GIT binary patch literal 143 zcmY+8F%H5o5Col;f}U1`dw;X+-|t;CVo=qXG3p{dt=-hn3=p)P6s^Rgl#J3rsBCMvZ0dd Jto_0i!U}23Ei#!e?;@$HJtfE8$^%OmaXJm(3R+_NC8nOh%3w8fzTmYHrJGo*ip8Xe1({T1 IZVzVX4*7pAVgLXD literal 0 HcmV?d00001 diff --git a/release/v13/abis/AccountScripts/remove_zero_balance.abi b/release/v13/abis/AccountScripts/remove_zero_balance.abi new file mode 100644 index 0000000000000000000000000000000000000000..f0ffaf791dfb308dd7fb43027e6724298f135c24 GIT binary patch literal 87 zcmZP+E=tYKFH4QDN-fHdPfE;5%u7yXKn09^j>*aSrFkX6$wiq3CB>o&L0~-!AUz6B U5IqWvTqXJ0sd@1wl?AB`03GfbVE_OC literal 0 HcmV?d00001 diff --git a/release/v13/abis/Block/checkpoint_entry.abi b/release/v13/abis/Block/checkpoint_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..951dc0d50be147f0a28dd610cacc2f651ab344fc GIT binary patch literal 43 kcmZP+NX|%2&MwH$%qxjc%_}LYWIzRstWG)k$=N_b0Pbf9yZ`_I literal 0 HcmV?d00001 diff --git a/release/v13/abis/Block/update_state_root_entry.abi b/release/v13/abis/Block/update_state_root_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..b9e52802f2acbc99f04bca4b766e0c944707f2b8 GIT binary patch literal 59 zcmZP+FD*z(EJ=+oE&-86`S~UBsd*(ul?Z~d?f4Ej literal 0 HcmV?d00001 diff --git a/release/v13/abis/Dao/destroy_terminated_proposal.abi b/release/v13/abis/Dao/destroy_terminated_proposal.abi new file mode 100644 index 0000000000000000000000000000000000000000..ce2f1889bbeaf26c89e3660d2ffbbc34dce0c104 GIT binary patch literal 141 zcmY+*!3u*w3kO+tmW@hH5>M^mG;$jwVn9BIf6ea*T<|YgP literal 0 HcmV?d00001 diff --git a/release/v13/abis/DaoVoteScripts/revoke_vote_of_power.abi b/release/v13/abis/DaoVoteScripts/revoke_vote_of_power.abi new file mode 100644 index 0000000000000000000000000000000000000000..23389794941963603744099b20158a509fe01b6b GIT binary patch literal 139 zcmZP+DM~HN&rXdm%P&cd&rgdl$S+SVVn79qd@hOkVL%1J$wiq3CB+H~5KRij`MIeI zAf3eu`FRS73I#>^1^LB^IZUi2Kr{2$5|c|Z^YfSmAmXV-@rfxZMXANbEZi`a@tG-1 ItYABt0e5mNhX4Qo literal 0 HcmV?d00001 diff --git a/release/v13/abis/DaoVoteScripts/unstake_vote.abi b/release/v13/abis/DaoVoteScripts/unstake_vote.abi new file mode 100644 index 0000000000000000000000000000000000000000..2d215ed5b289f54c3d649a0e8a5be45ebcad09b9 GIT binary patch literal 92 zcmZSNDa|V`Nz6`-FUv1UWk3atd@hOkVLS*#g{&4u;?^UR3NQS zF5Z+8?S#hvpuG<0Yw@9%LAwZ@q;6Z3lE^ERk(ofI*uje)x5Yy{%UMCUs*~sd>tc5f zW>$*Q_F|WuG8%%68lnuXj$)^KuR5rVS1+KlOmV0r=>?e-FR9;Fc#TbiDw#OKfUfp~ z*iX^L1a4w3aP#~Yo+WUC;`YRzJ-R}*xAOND_&62Iv8f8dg-4VtajhgUXfcXgin-Z# zEbd7K>?25H{GjX2(fT^E7k#P>Qira+gi3ULEvd0xDa%5w#pJ2< GDT=@P_gq8( literal 0 HcmV?d00001 diff --git a/release/v13/abis/Genesis/initialize_v2.abi b/release/v13/abis/Genesis/initialize_v2.abi new file mode 100644 index 0000000000000000000000000000000000000000..3c0fe67b2c2780b6544131d0940a2aa7839cede3 GIT binary patch literal 960 zcmaJ=+iu%142@MFE3mdp)+Alf^(nQMMDfMK(Ve&>_Wh zct{oZ=#Wqv{G;LYWA*kcKK#^9M~ti0_lHQ8!4gh7MD$MF1>MU~L8Xlx#D+Xc1CbO+ z>yx9K$1Z5F==2iY5!w-@|Dc@?=qvHDlR-OzR>pQ+>|~5yp(N%8nW%+VJ*1(qe*Oa=T!@(@#+;+)-DdEjCw{!#dGS{1zurY zqe_Mb=+RZa7yB_f+rmvu1#Vv6!;=I~P~4u_vqx8`_E!GB0w2d>IW|^_aN!ZVg}6pW zFldp)ZKT|6GZYU|1?&iS%qH*o!We24jn^xrBD;_*zn<*-^DRC$5W6j_p73 zKrhI1V|>YTx7zwJOkxJMR{2Qc+dqPRz;ntmH_rlHloMGNo_Hgp_+s*S-UL-5U)SPk zRL4J5kn=|im{mNpFKCkmmu$)Y`+AH|^$wY;3#hnbj-83bA)9#xf64e#TFg%*&x)y{ zcsdtgH~96ic{R7-gV9H<6R`a~29@sI((CzeG8nFS@qKF(l`3dyBK zMX7lu3Qz+SKnCb2lw_nTBowFSrKA=mDCCwFmndW;mH~yJW&{8gIVTn*CS~SimQ*I_ HF)#oCI#?`y literal 0 HcmV?d00001 diff --git a/release/v13/abis/ModuleUpgradeScripts/execute_module_upgrade_plan_propose.abi b/release/v13/abis/ModuleUpgradeScripts/execute_module_upgrade_plan_propose.abi new file mode 100644 index 0000000000000000000000000000000000000000..0f59d6f0975549ee781be2c645f639e027d95ddb GIT binary patch literal 249 zcmZvW!3x4K42JE{lNS#@K)~zpEj)UXolDomS=`#vq~Kn_=XTm62nPO3`11Wx2YQgr zLV60AN76YC$sp-C8n0stF)*!uNA1rawkznxCKrXD>QqcnOi)emHbFH(KLh7}a`KOA zL2mR#r_2I9kq0v*B5c8UTrvkwU>9fod^vIq*X*sh;E!q};ZDBU)ykv|Vj|}CwrtF( G9X2mP)mEYa literal 0 HcmV?d00001 diff --git a/release/v13/abis/ModuleUpgradeScripts/propose_module_upgrade_v2.abi b/release/v13/abis/ModuleUpgradeScripts/propose_module_upgrade_v2.abi new file mode 100644 index 0000000000000000000000000000000000000000..a949b2605f38ed346a7270ad9ac26a181cf615b5 GIT binary patch literal 135 zcmY+*F%E)25Jur$0&0k{vhf<;!^&81COf}Cz@5nq5WT&L+W6}4#gm$-IMPFSnUEIk zj2LM>hyUX7@)5T$xMmx4_7Iy{MwI68`-$1$UhkFiNF7p7-f!Y|h4~<*YVkx)jEP>= K4&^SE!QlH9BYDpOVmEvqQX=Z d!ZzM`t~!S0X!40atw|eE$-DXB#X>ct8W;}oFADZq?VD9Hz^f|{Mcz{mk(GXenAIW2Vn literal 0 HcmV?d00001 diff --git a/release/v13/abis/ModuleUpgradeScripts/update_module_upgrade_strategy_with_min_time.abi b/release/v13/abis/ModuleUpgradeScripts/update_module_upgrade_strategy_with_min_time.abi new file mode 100644 index 0000000000000000000000000000000000000000..f8e8ad1c3526deda24b77d0ab2352ce33291f1d6 GIT binary patch literal 253 zcmY+-O%8%E5CvdiWn8%O0JC#rxC0BK8>5jD<7z-UfkxVrwn(^xhZgyXVV0BkzULj9 znrDtsYTi_YO}W*(gGQ`1%ozcHA{uo6~2 literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/accept.abi b/release/v13/abis/NFT/accept.abi new file mode 100644 index 0000000000000000000000000000000000000000..8e678ebdf6e0745c2c4686c13d2b8b43e6d23750 GIT binary patch literal 115 zcmZQ%OH58qEhu3?1&o4zZXxc8IXS6CmBGnHnFS@qCJLT;nI#H|3JM4*g|z%41&9G4 iQ5zukO)W{(0dbu2Q!4G4IP%g;;&XvwU`7&9i~#_UKOpJ= literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/accept_entry.abi b/release/v13/abis/NFT/accept_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..6bbac000954dd76372168a442b862c87ca6a029e GIT binary patch literal 125 zcmZSNNlZ>oEhvdk%_}LYWIzRsTz+mL?uj`$sYR9c3Z8kHB?^fO2qA@%dVP;-`6-ol3TgR83JJxjc`2zy2}~S$X(jQwKm}k%5>NpH05b|C;Q#;t literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/destroy_empty.abi b/release/v13/abis/NFT/destroy_empty.abi new file mode 100644 index 0000000000000000000000000000000000000000..456cb71a6b807e3ff1ded3a0ea1ea4c87edc1257 GIT binary patch literal 101 zcmZSNO-U^-Dax;mPt7eTsboL}j3S;Xsd*)tX_=`-er_Sb$wiq3CB-rdE)YEmU_A;b WYM40k(n{iUQ%e%TjHLXON(KOtS02Ow literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/destroy_empty_entry.abi b/release/v13/abis/NFT/destroy_empty_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..808b5de8e4b340feeb698404fb44aae9cc74d1c0 GIT binary patch literal 104 zcmZP+PDw2;Dax;mPt7eT0g`zoMU@PwfRWcT1t^}GmYG`Q=N6)%-~!R2P?C|V0M@2} XqJW7bFRdg#H?<@Y%t*>lsbl~EAG9CQ literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/remove_empty_gallery.abi b/release/v13/abis/NFT/remove_empty_gallery.abi new file mode 100644 index 0000000000000000000000000000000000000000..17b89be0420c216f5af1c708508d8a372ca81587 GIT binary patch literal 113 zcmZP+DN4=FFH4P2%`GUYj89L@$w@7$WIzRsf_`ox?hvWq~GssI20 literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/remove_empty_gallery_entry.abi b/release/v13/abis/NFT/remove_empty_gallery_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..b1fbfa40febd7d2d8712cf8f229861b1b293a1de GIT binary patch literal 112 zcmZRSDoV}GFH4P2%`GUYj89L@$w@7$j8DxgDXL^Z1&myNZXxav1u6;I6luA22CXT$clK5Pp0GN>k6l4GZS0Ex% literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/transfer.abi b/release/v13/abis/NFT/transfer.abi new file mode 100644 index 0000000000000000000000000000000000000000..492b218d3f592f9a7ec995649a9e69386ebd4e33 GIT binary patch literal 148 zcmZSNC@D(JD^5!-Vn79qf_`ox?uj`$sYR8+$wiq3CB?1^AyBmnKsg&A_DwBG)B$mv z@>4496v{J8G87UrQxX)?it=+65{gsvQc{Z&6iV_H5{gojQ!~qeJSL93w37H-piVF& Q38<5aDKmwM1Ezun020?NT>t<8 literal 0 HcmV?d00001 diff --git a/release/v13/abis/NFT/transfer_entry.abi b/release/v13/abis/NFT/transfer_entry.abi new file mode 100644 index 0000000000000000000000000000000000000000..8d60d00add5eb81a28d97db17b8cd7fc533c05a1 GIT binary patch literal 119 zcmZSND=A9MD^5!-icifeDXL^Z1&myNZXxc8IXS6Cm6{46P^Ah$L4~xU{9J{E;?%s9 t)S?81l6-}PqSWNn%rYR4i6bwqBtAE_BoWL=%1^0eV#-Wm;()1O0RX&3Beehk literal 0 HcmV?d00001 diff --git a/release/v13/abis/Offer/take_offer.abi b/release/v13/abis/Offer/take_offer.abi new file mode 100644 index 0000000000000000000000000000000000000000..a9ad0fa82daa7b9d54a2bda74f4d8a74d3198b16 GIT binary patch literal 112 zcmZSNDoM;vjn7X@OD$qR1&plzAW;*A5TFVLFk2xpFGZoCv_zpKU!gcNJukILy;#9H nKPM+Oxg;|`&jze0HN{SkksWMeY6>GSm=T|tl2VjfT+9LhZ_FU^ literal 0 HcmV?d00001 diff --git a/release/v13/abis/OnChainConfigScripts/execute_on_chain_config_proposal.abi b/release/v13/abis/OnChainConfigScripts/execute_on_chain_config_proposal.abi new file mode 100644 index 0000000000000000000000000000000000000000..884f242133a0dfd3c23c4124f88188cc5eb7697a GIT binary patch literal 96 zcmZQnNUcasE-guo&(Dib&PdDzlKFXQnd$KbMfnB!#fdo#sDM$#KhGJY&KayMIJqdZ Vprn|Akprr&gpnJjGd?qg2>_4i9Yz2E literal 0 HcmV?d00001 diff --git a/release/v13/abis/OnChainConfigScripts/execute_on_chain_config_proposal_v2.abi b/release/v13/abis/OnChainConfigScripts/execute_on_chain_config_proposal_v2.abi new file mode 100644 index 0000000000000000000000000000000000000000..4fa4c35ae48059c06d426e5a35cd997092d34d6c GIT binary patch literal 128 zcmZQnPOV5yE-guo&(Dib&PdDzlKFXQnd$KbMfnB!#fdrbWkw9BfKkLh&l#lD8LTom wxhS)sq?mz;t0X@=H7~xTvLKZMYDfu_0K}ZsqWHv=l%mw)Vis<=$(bok03miMaR2}S literal 0 HcmV?d00001 diff --git a/release/v13/abis/OnChainConfigScripts/propose_update_consensus_config.abi b/release/v13/abis/OnChainConfigScripts/propose_update_consensus_config.abi new file mode 100644 index 0000000000000000000000000000000000000000..543cd101e7edf2498e698efba40846aa2c98e310 GIT binary patch literal 336 zcmZvX-3r1m3`VzlBjSyqf}r>?K7bcKK&ffA1-rJiDRXb{enh7%SK%a_FUik7IPW6L z5WU;@i&U-fw9+Ij4 z@ZG=zHY#Z8F^nsV(?1@K-2$Lxu|e;kdh5WY4jm@}nu>xT8E$1mR=Y;*YO-_bwR+Cr k!{F*?Lu~vWCbpB9QblQ~CKk)c{j+78ukeW=H5%257l6TdQUCw| literal 0 HcmV?d00001 diff --git a/release/v13/abis/OnChainConfigScripts/propose_update_flexi_dag_effective_height.abi b/release/v13/abis/OnChainConfigScripts/propose_update_flexi_dag_effective_height.abi new file mode 100644 index 0000000000000000000000000000000000000000..1c33d9a50a70defc9d79feb3f39a8fde1fd8c99c GIT binary patch literal 107 zcmY+*u?>JA5Cu@6q;?7CZ~zMjxDfcjB?Jhd;`TN+zW&Lzwo*$6oz5Tg;N@K#3Lo$zg0Xz61K>z>% literal 0 HcmV?d00001 diff --git a/release/v13/abis/OnChainConfigScripts/propose_update_move_language_version.abi b/release/v13/abis/OnChainConfigScripts/propose_update_move_language_version.abi new file mode 100644 index 0000000000000000000000000000000000000000..20cc2fa37bdc490fcebd86f4502be32b5f8fb34d GIT binary patch literal 103 zcmY+*y$ygM5C%}7)YcK)!~rZE;BwJVB*8lZ__w{4g|C0MPg#=|(2*9dpj}T;Wbp@k m(1~1viutqMD8t4<29-7VY0e?lVvK7A*LPfl8#674{J0mKfgk<= literal 0 HcmV?d00001 diff --git a/release/v13/abis/OnChainConfigScripts/propose_update_reward_config.abi b/release/v13/abis/OnChainConfigScripts/propose_update_reward_config.abi new file mode 100644 index 0000000000000000000000000000000000000000..8a2a050dc4420618735cd693b78e4d566b7c1b55 GIT binary patch literal 96 zcmZRSDJaS>$S+QfFD*z(EJ=+oN-a+;N{LU-&r8cpXFvsvBK~>K8Ht&B&S2T#KWN+zzOs#QwU6cj-_gVKf4 q6r%7(yZL9Qh5ZqT{ikazl(ib;#?(qs5{8QJnW`JGV}yifxZMNGiy+$o literal 0 HcmV?d00001 diff --git a/release/v13/abis/OnChainConfigScripts/propose_update_vm_config.abi b/release/v13/abis/OnChainConfigScripts/propose_update_vm_config.abi new file mode 100644 index 0000000000000000000000000000000000000000..2a990bca6b7f541e34e8d467df74325ac39c4ee0 GIT binary patch literal 416 zcmZ`#J8r`;47D|M=+G`kk|OBPv*Z9BdH{l!DTjbW3HqdQPhZJ_fdptZXn2qBL-vOd zeej8(gb6dj#ew!>c>{nC*`PF?phu%sM|&g=z}KGRezJ@v1GnJ;vQ z9B1oCwBX43xImx?<5Cl~Pg#BZLw-lzM&29?c<+|{FbVY4zKKr11WB-RlHgGo8PWQg~*y#!4{-;RrDAB-thZsiGK*HM_Vwd{bo?F hftF8T+VdA^Bx XKt>S*10#O{L@+)vC8a2}xR?b1NjV;M literal 0 HcmV?d00001 diff --git a/release/v13/abis/StdlibUpgradeScripts/take_linear_withdraw_capability.abi b/release/v13/abis/StdlibUpgradeScripts/take_linear_withdraw_capability.abi new file mode 100644 index 0000000000000000000000000000000000000000..aa00d595bca5c1539c642797b187a94fb93168bb GIT binary patch literal 146 zcmY++F%H5o3_#KJ4(#{@3~&nOiaBzflvtQJik(*6z7kCQ`RPw*$5)QRHDixEdr2Ml zNZ4>;VgH2xrqk?6czLvE$CPL4+}!SfW=f3CS^qj3U7$DLI)*p%Asf$wiq3CB-TV5K#rF o5emg%aRrb`3S~wLCHV?KlNbd`@=FqP;)_d?;}di9OY=&Y0np4ODF6Tf literal 0 HcmV?d00001 diff --git a/release/v13/abis/StdlibUpgradeScripts/upgrade_from_v5_to_v6.abi b/release/v13/abis/StdlibUpgradeScripts/upgrade_from_v5_to_v6.abi new file mode 100644 index 0000000000000000000000000000000000000000..4556e0dee177ee7b6fc436f0300a236dbec1203e GIT binary patch literal 63 zcmZP+EiFhdN=!+OPb)m!JNQDcm>@LWBC#(CShi}$nCAcP5r2(*boVX*)>WLRLi!qGy JDQk9%!xsmXDwzNP literal 0 HcmV?d00001 diff --git a/release/v13/abis/TransferScripts/batch_peer_to_peer_v2.abi b/release/v13/abis/TransferScripts/batch_peer_to_peer_v2.abi new file mode 100644 index 0000000000000000000000000000000000000000..77a837ee22e0c1774f99ac5ed3c6804d7a0d7b86 GIT binary patch literal 121 zcmZP+O-d|D&WJBaO)ZKq$%oKoMhvKckw2s;F|Rl+wJ12bD6^oXSV6%Fq)nj&Dy&eF vpPiZqBo*>YGE$3*^%%LpBJm}a1*uHz1&NiZsj0dk=a$SpYZe-i literal 0 HcmV?d00001 diff --git a/release/v13/abis/TransferScripts/peer_to_peer_batch.abi b/release/v13/abis/TransferScripts/peer_to_peer_batch.abi new file mode 100644 index 0000000000000000000000000000000000000000..0e6a00b00275b6a7d0b4a825ad8e90095b6f20e5 GIT binary patch literal 105 zcmY+2!3uyN5Cs*XqD#@Q)qUCIg(0cvdhqXyIyILWMlT7-B#~b4EY_(%dfGCFav-lZ jpGk_+qePED(h|%-i5q~@>G@0IDvmtbvwGqy)*$8v1hgLr literal 0 HcmV?d00001 diff --git a/release/v13/abis/TransferScripts/peer_to_peer_v2.abi b/release/v13/abis/TransferScripts/peer_to_peer_v2.abi new file mode 100644 index 0000000000000000000000000000000000000000..b3e5683aa44a9e5b325dbb3dd40571434908cc07 GIT binary patch literal 78 zcmZSNFGx)-iZ98J2h(Ln45)ySKcpxzuQ)BWC^)$&v!JAyfsv~uKRY!qzNE4sm5H?= Ru`)H4g)K2RzcjCe82}9b6;}WN literal 0 HcmV?d00001 diff --git a/release/v13/abis/TransferScripts/peer_to_peer_with_metadata.abi b/release/v13/abis/TransferScripts/peer_to_peer_with_metadata.abi new file mode 100644 index 0000000000000000000000000000000000000000..1520ef4a5321644322edccb872cb99758a3116e1 GIT binary patch literal 118 zcmY++I|_g>5Jgc3HHb}mx263s=o3ZqA&y9PuLLZ-&FL-;5lF0oi}$V@JE$z8QvD-4 qCGqEqG|p*{dREkHIN(`xMAJseKx4Vca=oVm*^m(zF0Xa>eGNS!Fe9n} literal 0 HcmV?d00001 diff --git a/release/v13/abis/TransferScripts/peer_to_peer_with_metadata_v2.abi b/release/v13/abis/TransferScripts/peer_to_peer_with_metadata_v2.abi new file mode 100644 index 0000000000000000000000000000000000000000..461b7ede9224195aa646f979d7d4ba2ee548cd4a GIT binary patch literal 103 zcmZRSEl5o*iZ98J2h-)5B^mL#sU?Xii6x2gWkw9BfRR6>C^4@%Ewv~(xhS)sq?mz` kt0X@=H7~xTvLKb2wIH!FHI;=eF*m<7uY{QcW)K@A05a$vaR2}S literal 0 HcmV?d00001 diff --git a/release/v13/abis/TreasuryScripts/execute_withdraw_proposal.abi b/release/v13/abis/TreasuryScripts/execute_withdraw_proposal.abi new file mode 100644 index 0000000000000000000000000000000000000000..c718e096beaa6aa06e261b96d12b0fcf14ba2a49 GIT binary patch literal 101 zcmZRSOsz;wE-guoFV8H=NGVDzk1r_7FUT)W%wa$UjQk-*sfop hCHdK@dGRGo0uVi^Me&I#DMhKp#Vp(~Q{ppIm;eMIA9nx% literal 0 HcmV?d00001 diff --git a/release/v13/abis/TreasuryScripts/propose_withdraw.abi b/release/v13/abis/TreasuryScripts/propose_withdraw.abi new file mode 100644 index 0000000000000000000000000000000000000000..471d3f1c6edbe320d07b58cdd7f4869564b55421 GIT binary patch literal 99 zcmY+x%L;%X5CzbzuxL~NR(lb>kn|WC$IQQP-8pKBOpy{y39@^(rTJ6y#;_@KT^)xg isZoQ_f!jzwG91DK?zO!r-_q#_4&>VjFP!l>ZEZhEtQ_J1 literal 0 HcmV?d00001 diff --git a/release/v13/abis/TreasuryScripts/withdraw_and_split_lt_withdraw_cap.abi b/release/v13/abis/TreasuryScripts/withdraw_and_split_lt_withdraw_cap.abi new file mode 100644 index 0000000000000000000000000000000000000000..2aa691183e004ca09cf0fe6558fe85e5454fcfeb GIT binary patch literal 113 zcmY+&!45z$3;<9=I5_wRzr?+1)``WeOIs0t&q?APpPQ~|8wp;3nLta52Fc)CkEQx^ o<01j|lza9Pi)rP0<2_`sW>{GOi6p4D9UgqbSHzxa-OZ-#UfL9+ue zT7e}^Oa?&E4zRN93<4(J0|gfpa4|(-apHxX2L=+&i0A=@kx4=Vk^mYKHl&wRz@VPX zt6RBg+otX0u3Yp@Yx1HP3?Xv3ntg6@fvMT0z z`}n*n>)uy&QNGNZ2UW5gX#BP{UN!v(p$|Oh|;u&k*08L1CJu0gRz`MWg=b+ zp$=jawHcFT_70V$!6D=bnLeKasW&QgHkiJN10btVa=5zyQ?uPL{IS_!ri6q4f9r!V AbpQYW literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Account.mv b/release/v13/bytecode_modules/Account.mv new file mode 100644 index 0000000000000000000000000000000000000000..1a3465588cf2f4a091e256a0ecd694ebae2ea0ee GIT binary patch literal 6890 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 literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Arith.mv b/release/v13/bytecode_modules/Arith.mv new file mode 100644 index 0000000000000000000000000000000000000000..61d6433fab0c527c68fecb535bdabf4cfeae51a2 GIT binary patch literal 467 zcmZutNlwE+5bU0w&F(oQ64*i{5*LIx0Eq+~5El--Bg!VQlm$7<6Zi+8;8Q$-19U@3 z5TYbcS51vw<#}nnu?K*FV96f1c01hM#&yF#V<)}hJBo*3W_vzoKFYUY}{L2U(#YQ$QDnNYN@JG&DQ-%HR|>2ht+gE zTT1G0AjNZSBA|G-WvW%!hBC#*`XY3in?3)tb8Nk1HW;vJPZ*k%C|O3CE_o()g`6%# z#uV7HFF2^m*z9x0v57|h7i?tc9$hf{4}m7O4vpT6yZSc_{)UAVgJF`dm-0d>33+nc klI+TqiEj&zC1+}L@;lp?T8BB8I;3?%E_FH#yE+Cw0k?20UjP6A literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Authenticator.mv b/release/v13/bytecode_modules/Authenticator.mv new file mode 100644 index 0000000000000000000000000000000000000000..c5a74c50726f9630bc63c08e50f2b5271cbbcc8f GIT binary patch literal 801 zcmZuv-D(q25T2Ryw|mZRvMEte0>+k7ylgd^-q~nTD1sn(8@AbFcQH-E?xv7i-^4f2 zTVF`jC-BbMn8p?y4$I7Z-sY>$>g<{Mgx@jvL5coNL;F>P z(Kqph;-5+~8G%561Z4m;M_@<*1VjL#@-O-HUvJXLx@k7b?#?%F-hxrDMl~e>C>{Dmz8{-R=Ixf zC!D_XW;v~k)9h$4I6Qv4Jf9YmGr#IiN}tw#eA$3w{}*j%zAUbMHcqpw^i_3#lOL!5 zbc*?G{L!!aw=VvN;1+AChFgVo&gJs?G)s!vRXQzLp}bgL^3!cSzg7#XJbgSq8a&nM zV&P|5z|i@s_7yk!rlAP>o0!`tf{RTcf_&@wt@mL|Z+P~Ir!TK0MHN+U=T?6yHI}! zrT-K^i11(hQAaPMPViH7P0?HV9tGD5Q0z!1P-1YofN z;8@y31JFVX&}M0eLCjzU9Y7bG06ivGkvt{P23Ug*KtCpI9b@e76u*YD?V4uMOgPRNv+baOKx@`gCb{qq~ClWf)`)dRb+qc>>FeoJ;zmOj-Q4q$c zloYt|g6yqG!VgJM3M83OLJBQ{1_%*IT88%u(kD&>Jj-u39_ra1QjrH;3&id8{oD0z!~ zdHS>#+tujkWUZ>ljJE}HH5%6fySjH&r^m-Ne^=w<%uK6h{$!&@UQ8de!_&ot3`S3< zOMf)W$Sg~51^0TS-!E^0ws~%9$nh;rvP)=qg0pW@jME;MXck|(C-atytI6#94OLFI zFE!8k>Ufn(=Aw)-&UB9Mk24k>GL?;w+c}ciGs}4%c|@qMt>*dcIaS-)WU)M5PStEa zo2te9n<Jl>gIiqFtTY>#rV80aDt5>gHWCZlq4E04~;p5hUY8hdL#boHD?lhdV zQgw9_LVWWO1x+9kSui4?IpJ5_wIz`tl13a_up$-?<9*AmN<*m6o8lEmEjALnsu|HP z;`^1L#S!ePq)}sr@=%dV*feY{aMIC0Fx2AYQc{4ZNxHh1NtKg4SN(GMfF@Xmhcpx9 zP;KcJX{uN`?Sf`#gGX(vow8VlK{K;K6T*g8d9G0Y95gXGj1}*w;c!P;(mJ6zOYvAF zi}FNRi4ke_uL)=Ux^TiGob`8wL!S%C!l41k#A~&578

L8-xx^2Qx?Nb$_xqUCb)fKF%tigM)x$3B+&cE1U)fD_ zpw{`tw&FA{c)&jNbqmJQ1IDE0v#Q)7=d-uUo;yFJQ0 z6)zW*k!YjY`v;kKoq9L=-YDuj>T#>?+wcx0u6|i*C;_gL(e|Kn8ew1*-Yx9!sYExL z#0>ILIS9Vb0@=Jr2V`wWzhh1MvtU{v{n&ueoZ@mqZr~bo(~iw=EM}FQNU%?6NL^J- zIzQpoiMzf2)(MwRwN>r>RO`Pn$*8ym&9M!#kb0)MN!EF8ZnCd98)q^dXO^a`Zj*l* z_qkwj@PA!zUgvtNa9yUNnwJD`lz~*nd!gN@fGG_no#1w9GaolTkvWmzPN}hzU6t3! si3E2`jeH(?jhskuuhhuLk=MwH1c#)NrLY=#u8>Dw&jl3!HJoS2uwmQ$ROnO4G_mtVq^U&K}f;Z@`p0gXfkVB?ut txf!?_WlWerHb6M~CJ;M;GHm~$K-Pqb8LmLugoy>tF)(3bg>!()7yt$89e)4- literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Block.mv b/release/v13/bytecode_modules/Block.mv new file mode 100644 index 0000000000000000000000000000000000000000..cb1b4ec752d3cd9d1f24a667772c1a9525885305 GIT binary patch literal 2705 zcmZWrTaVku6`nIUk~1Tb)Jocm*XzA{9lLhZ*l}3LNn`JBVk3wXc!N9zCAbp3BCM4J zlJdqyffjx3Oa4ND{(%02B7N#pf&Py6u|QsXhLk0x=EIqD&Ya6PXNEK9hs}R$NeIzE zy0p8?qW=K@3*8t0pg)20H~uHb{ZR+%hn3gcl|cfU-=l>eXr{xy}Q~%&E3`- zI^9Dj`M&27xWC~N_`s5A;|hUaTke4+A8u?C^>EAje{^jdJwMvsLHhBojr*Hj)YDH8 zCw+v7-N)`e5bp?;{8(NGDNY=h@K0|5$iNGORTO@$33h`$Z{Ir% z-Z{8+z#Nw{MF~ikT85&mC>W3i1Ta8ebEH%nMIB27W2{!8P|dnvZE!^{P)AGTke9Uz zP;wZck5#xJF`%q$Xgx5H9`PAq4m7f#QyE&S5Q37+2a(*-(y~xh_lcX5PFDGR-9`Wbd=-m4{yGV;NxtPdr(q1{v8&%XV(lY5MWulG- zY47D^oQ+DoV2j4H^s=(6a`5^J49D@ZL zBli6DlA?&SQC7Cj(=zT&^Bkw+WLgf!`P#DT%$6h`O)t*U+_w{xq%s}gvV(DkuYWFBGq;yal3rH6mSul`{d+zJP4l|gG0LWzNa`~iR>HVCm9<~EY+gl@$z+m_`l`+xUrbA0 zTqYC#A{!3<&rY75oIX8`9~~b*KRG?^CioxZWqh8F(gIgCOVjSzRwA(rT`qA^FFP}bp@ZhmM(NEH(pXP+hEp|=OZL!04tE*)XuL8UqC_7-+6+NtU zcm>|5?v8iZO}uc#7TXrL*c%U$Yb1?S67$_b>I5uu4HfTthHA<` zLF_ZFXYfkLdEVAen__V^U&Jt6FGa*!REw73+95@J>)(UpgzLs{!W>GtVZ0`2FT7$D zjw;+V+8E??c-81?+?tIW|2JL(6Eu7ckI~O@TWqe(P1+n$=3)R%XX=@zTQzaQ;WY zdg(@Fd}f-ec_(uD?{!lLQ3J#uDyB(w1GKZqW2?F(NpWnCi>(~9eGT0-;j%S^t|8&U zO?z5MNGJ!6MnFS6q<9$ij3VK6hekdg0qmsai<~npdK({7z~%=;cyNmZvQ4o!nv1x% z*s07#w@tClnTuYVDog{-@Pv ztM7HR<7+K6)!3eB*F)iR-Hq*F2jav@ND!BZ!$@2(wncJ5AvPc(q|tb{ZI7}$W6jLk zajuaN2gExdB!oD?ITA-6fw$lhxKJ~*yCf3yp}V?%zWTbltAE(~%Su9s1+qamw%7+b z{}I;2D|iX&cls^Yf5^W4Q$94`sQd0W^*8JMVh#EOp@b1m1d&7$O#)(wB@UrFoRF?2 zT5}*Er6T+-4iZQYV@RI@QJa9#TMUS(b^HdCAobe;0H^POA?&8LL~lFXi(6ocz1`^o z(L239@Zb*MZ0?2uaM&K83%@r6gn!qJ2;4WQ&<_BOLP#BG%bo7%uI}l+80ev<(lH`& z;=)kN069tr8bA}U0s_**c;JnNF|k;c2BlkfUWcGMARvHI)rieRl?g~=kgc6#GEQrZ zfS_ZIj!|Ggp626cPyJ<5Ow{gpoX@kWvzHfscQPq_S^82Q6h&T?;^4w(m1{ls^6Vr% zWrs(5!BIN%WtGg%#ZmsuXZon{NjWdBHkZPeX>~R!lFR)he^TV}IZN<;#e(p`0rB#|t(-(epUgTq>6(85M*F@X}*0`Zj50^Zb>kfYjk#Hk3GU_&eZbwf2kC!1vMbdRUL)(pL zcNp>i0Q(M1#||SUz6V@tPTcmavVrXkNTi!m{(F2h!!>JHigjnj6D+Fuxh{ucVR)1O difa^Du=qzsW&loGJgC+C_z-~N?c+~H$v>IZ^}qlC literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/ChainId.mv b/release/v13/bytecode_modules/ChainId.mv new file mode 100644 index 0000000000000000000000000000000000000000..fb643fe958323bd51f56698c3d8bf90eb0721d75 GIT binary patch literal 439 zcmY*V!AiqG5S^K1H_0ZgO%YFCau&~?OIxHD1>-%eWN80O1J^hd4vAz!h$v7d!E~il^Xd zewI`BRZ9O&{=n>)()k}XR3Q)ukQ)y`8I(YjAjcYzkAwt6Mk=-`X|^^ojJtF|ycld| zxeUk70Tmf1X_6}hF|`D^$0$BvBOi`6rydnU%B0@<+>jZ0G}358nrSHr)G46CO@Iy= z;w?z~WQ(N0J~OmOftH=b5p!^3i2;S0Ep1_THf1T;*X?o{X0d5k`nc=buGeqZo9LwZ zunL`i$H}%E{imI981!k&?S9LV&c3qv;voo>2 zh(#CTMYpDLX^|F~)eXL_h!d2|*S@gT^t9BJ^J)d`>@2hq( z?!w25hJ)%Bv-7a-!i-Djrs=oK$VIbU^7GyQP?&HV3$wWMraKN%&bKyFNSO0g4i{^{ zur@#`2S?!Wl_6FGqRK6lAf-wYD9nL{7jTFrzt>YF;&w_pcm^er7y{woIglLs6b=e! z@rd@GNTV`-+5`)K;P4QR4Y4Meov?fkSR{y}DYrpS9&;>(%pARhQaXHNb}OriqhYqg gQVn`VoOsJ4N|uJ>f1yk~an875E$)tBko5-t0K_AA4*&oF literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Collection2.mv b/release/v13/bytecode_modules/Collection2.mv new file mode 100644 index 0000000000000000000000000000000000000000..ab314639e15c5fc1a7e499593dba7915fa0d0cbf GIT binary patch literal 1860 zcmZ`)$#Nq_5UtEwdZ|`RB}?8HnPtp&;$ZhIEWwwP(iPz=Z=p zz===b2e|M7L~tiK5F9yhDNiSoiA*~6ZPr?Ye6?;xvGuzhVPSS#Owd|&CaMqGGG`)@k?$_SdyPmnR=H+JS z^;?0*+rp8OZ-_+Do9(txZ@E4R6|Q4%dK(J9vxz+UXbVgD9k&hnuGgsdcD?@nZ4f!$ zM38E8-*Y|~Kx5px+i;QF>TmaV`k~wH@45Z{L0>s?UB_ zd{LFf^(|HFMwMUAtLrF#IayST;i!rxkj>`Pe0E-4M9nZP&cb;yA3hz8pGEVl#YK(e z{HhA@t3xaE%i?+N%DlQNXScRe)#zESCslsA(8UYnAB;z{p)dpo2v;X!=)}-OlIfPyeej`$?W-PIyoIKDik3=Iy1No@|RUP z8dqvjT-HiIhA`IYCpX3LRCP9)PH`D;e@KRB%ef5CSLkAeCM)#y3gt_L1Gs~eva9!K zpALvv?lcE$K!-$5IJ^Tyz5Q6YUP3Y57Xy`85k{HNDbAFo2O{B^PegB^c0$X?qObSh zqQ2SGiNy)^l-4o0fpGmJD~{PxMj12Xrc?WM3})%=IJhTR@R?)fBiT5KDU(X+$UD?- z^C7nDq zllFFEff{XCvFuGN z_PJv`?|8Y;YBV@WWD5n&T2^K$cmBuHt}Xt#uYLY^M|kOQ*RMQ4Q}3ayl*ojwL|QnC zzTv1}5ASD_6&?Ex9k2N%hseSo*<~<{ns?E4&QdG=*<@@hsQI(Q%g;_a<+L+S{0piv B?~VWf literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Compare.mv b/release/v13/bytecode_modules/Compare.mv new file mode 100644 index 0000000000000000000000000000000000000000..e3e7ef4a6ae9a2ad703c9dd09d6d19fe9d1ae49a GIT binary patch literal 623 zcmZXS&rTFU5XQTztGlMFTKSXB;=vflG4a3&LWnV3zyoqnA7QhQiJE}o&T`;ExRP+- z%8U6DRyQncLe1psucnjg-#0Tium5Ru&M`Rj_$Ivlz=z+OD_D)Ukn$Z|d)oxN92W6t zLSPR=k!XTZ$_`KWFFDS^whX?0j;3GE9yy=lzgsR~#32vAfg! z8YcbUi|Of#nIE%$I`3zb`OoR^Z2f6J47D++qB$k}D z-qR?o2tV~1!#HJBq$7>dBG%f-QF*CjaS{(;l#_sPF(OH%r7d=u!k#9Tjy^JGA3iZ; zuRfDf4idK9JNlvk>Ocbqd9Y0(cJXWF<;vR#OJlt0k=Q+^9BhXUlagHHBY$W@N_G^sn7-)%Ys1NJv6gqloLouw{ ZP_Z@6Pyi_!fJ6tYRj?)#OAi!k zWHuh${5j#i&GE4(9iaFzmOhP6dI4MUTWMb8a8Ua7*_kj-w zQXU_QOCM{8nje`V0w0Z(*iR-T_VHkf;B01xJhl_oMwuzkc#o|SZQ2p`024%v9*~Kv zU^C@=NPrm34Y zdHLE`o&M^kE9**sU0znc8E-RQTou)&kMRdz*30r@v%`y<;=Ejy-RAKB;aBx)>6>A( zSk&vP%Zuf*@ol@mh`hOfQ?^}xzPZDXmcH$pdXryAj(nH4c*kEK=mvf zV@!5Nc9qH+zgK^rqiG#VOG$QFBs17Uw8tTQ5%=lr{!j|uA z;WN(2(h1E|HA(j62DTbW6!xU7eAI%<*?|ouL#l{PlfF#gRxh1F#ugnP^PWh8q_5Z-^1J4+r(EiY0m11TKaje#J50JVlK1PKrqQMwcab+xT-r| z)SGSJx%|_xd&@fiKU?Cq_2On<%%bkAPGe%|KJ-MFRoRury8PW`LzZL72L)uCvih90 zmAf5Q7~8vF%Wu1;=-lcq8IvBAeH*+@zs5$soPBrk;^OlA%lzr{=RaLsUPePES9f_a z9!FH*ku+Vta+Pb#cK%;=@=CY;)w*nN@_iCmMqE}ev4~}kP473@DZI{ygK|HebOsss zxfZ}9u6W859&nFaHr!bufW*Wyyo)2Imaz#l%lL%RUrbn7CMPT{Q;4NX0z)GTB=MLx z7(tU*SfFRP0kdaG%={@vSr!bKC&@WsdVpziq)B1{pD=Kcpn!n@4}1tf10>-&W%#6QX%gTj1!a!FGZuW4L0}AM69Pa4Ge{wZ j1dhN$1_r{EuxKhZuxvJAjmIZK`!Ly literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/ConsensusStrategy.mv b/release/v13/bytecode_modules/ConsensusStrategy.mv new file mode 100644 index 0000000000000000000000000000000000000000..911f9d5d7692f703c2fef37fb6df0a788cf301ec GIT binary patch literal 435 zcmY+By-ve06ov1#lQ@4ZO@%svgxC--(1oE&E5rZ;VK-^xrk2vAic_jE^CG+qkHEst z!b@=5s{DBIy~m%AuZ~|&z5)jTd<2)dKJQ;zSB@Q@ipNiM-&oIoXLk6(E;=uq5r)8k z0|>ytLIGfr0ydp6v8`RpM!`J-nNO}53Ks=-Tp*P@TyQ|foRA?YHhO?mJ0a}>QWwQl zX;f*}CTZ%lQF-f-GS_)0u4*;PvRWCVjQ60I$~5V6#dFp8y3~zM3;nF@r?gnBqwC4t zB)LiCXgt23BuSSbIc;USzu!&Cqi$rbN@cVe{BIA`;I_*2yxl(^r>k_T3*EHmtM#H#tz7OL4%9C|;rv~cC^~E#BNq`HLI_>x!7)Qpz>6#& PB0GQp`!K{I+y22f=4E0{ literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/CoreAddresses.mv b/release/v13/bytecode_modules/CoreAddresses.mv new file mode 100644 index 0000000000000000000000000000000000000000..8977cc4410a0e4bae6aba3fe5ac7f8d596fe3961 GIT binary patch literal 349 zcmZXQPfElv6vp3sY0}zOY!QZ8h#&}VTzLY^Gz?uhg=S{9VPN9W%@h;8g9|U=Ej)sE z@e(G?6h_SA%X_~s{K?DI% zObD1T=3j6WIkNNFU`@5%TH~B?LRvdmCse=N8#}F(YG+NgY}$qH+IFd{y6&V>7jwCg zs!?Npxqi}~%Wf^}kxe%KL;I?CW^Y{Y^yW|_J>GhFF06TZ>wV$T^L?KlWJz|+d2wo_ ot9<&Gco+YXu!S%(5*`8~KYbvKSP0S#%BaMfNbs{5N`6Q13n2|Rp#T5? literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Dao.mv b/release/v13/bytecode_modules/Dao.mv new file mode 100644 index 0000000000000000000000000000000000000000..6f6bedf1cb24d29785b0f41e7dac0545d8b08309 GIT binary patch literal 4845 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 pT>gMER|$EXJTLg0KM)G9{>OV literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/DummyToken.mv b/release/v13/bytecode_modules/DummyToken.mv new file mode 100644 index 0000000000000000000000000000000000000000..27c9e6f5a249bebeab991d21662926b3e40f900d GIT binary patch literal 731 zcmZ8fJ&)8d5SN*HESAqd}rT&__99?kqOhlaoDkr)&8G`~wOk z_%ZwvYI?@mMYl&JKY3=}ycxys+r!^R0f0eJq#lXKujNoCH*eEl_=EHxQK>Jo$iK=5 z_NTllz9*8o2n3J<2n`@D5J?0iYaqS%3@HkfpkrHx2~e3LN;=9SR+KX?$S^KZ zkd%0@D1cVw5oef=GEqvUN~_EoWfdBMJQI~gBxNNtG>|e9GvHDN#8(Ywm$rm+1v%!D zh75R!nj;ydGRR+U`~K?v=93%Ls}MF}Oy*$q?z|1Id%g|Bi}s>D^=m&}?UQf(Fx@8Q zDRXi^_{q0xf9*;?HeD2Lrl=}=W*76dX}d1CaWuQ~NAK31_|RUIcc+wh^;c29`Ru3j zhPnGq%HYoYIJvMJazD6!bLpCyddvEkjw>8A7rf!v_HNf(`Qefm@0vE8ZF@INtC{}a zKz_Z$4~2I7m{0&=&hLR{{`nLy@d4NZh^Q9wDOO;hW*YlJFLU-pjXBh084WJ+Bu2uL v0YghVA(r57swIhNDJ*k*RvjNM0PsX6iB4gWAM*gJ&|sZJAI83DJa*_`%eI8d literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/DummyTokenScripts.mv b/release/v13/bytecode_modules/DummyTokenScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..cc64f15f0b07c3160db754b475552d46149c72b6 GIT binary patch literal 292 zcmY*UJ5Izf5S!yUg1A`~G%uHFdVh^)KOcrQEIFy?VThMGn_ovB z!rSauvBmflirJ6j>Qn0CaTik84})KFm#=4bWBj+P(JwKDT&nyi4G+9jl zkSFD{TR!S&HY+FNGb*oQE?xzNznBM$|R3 zv4@r%xFXjE827a~(2!1A_3lM>A!sCbUHhC$J3vHtwRVsVV{hWY+0`^<&3%f9~x1zjl6S-G4lv;t?2d5FkN;0~$KybbEy3pg_DMKx+paM<5_R z7XUupfG#o=&_hmZA2~qKI6}H1Ad(cZWtV}n_IBeP+Lhg>+u{H<;30GXAGoyph$zd4 zoS~y1VW0SXOo)0f2tn@#wA-g0e;h?1Z5BsodZ_&v$HYKj?=3sJqkM?e6*e-FyC_kBZ6>D4FtwRK9eX%dEkq=2C<2W3xr2 zIe8I@vd3tpR7#^3_N(aUGUQC7&wWqQu~w)RQ(6gZY$lsOXOdLcr%B};&t}Ccue&Ej zX^zvhG*x9PH7U!YtVX9MH&s?mvw3dHlVq8Eoh`EZ+WV@^X6C$1W(%X%hw`HM#^n0q zdTGw`%c4urUz!%sTFv<+ughyay*O#C;jA=CZQ^-S#h1p!$vS=C+C>8%Q$RYJn>tRD zI*F@dRnBhWwyghyyOH%(vt*Iw^Y}8E)kPU)c~-Z0YXsN2G79?MM5UQ$Rc*=!skTM* zZ(M5<-PMw^n+-(pF00?BW%8~~-O#;7pU;wI@S$S;WG!=Bqjy!LtA&a4xQ&2O}VYFYPvMqh?<&(nOoYM%&pk#sMuB!6VvUA z1WQ(RVdKoQjvEPt)!nJ7nQ?L1Kb^dqOwXqA@ynO5C(~(=<=>KaX`Gbv)s@L>a*)Ee zn7f-!+RN#Gk=0tv=*>pO_Yc*c`L3p>*A2BsV4}Bq;C60AZ+UMH_UL(~9-IHYbUdA& zpPU_EoSnalU!R{}v;{b+Sr%1R)5N*`L9V0LW^5#PG)E?O<(|v-U3OP8hWBWY060Sr zLND}v*^^<{zLz}=d%oxi9riuuVFW(!Nsk`^Lp!UGk710A(S*a^i!t+g7(KJsc(~=V z00xI*K>Gphad7B^9Ma_TXgHB`o1BcCC?9lu^iVvKPwBmPARIpSSilF2Qwl&ykPwIg zqv;69#+=!yhr**NJQhqfJUT8}#E^R;bf^emj^(t~7NpwK2&p&~-g$x|vj5MCxbox? z(qsV|!wsq=30RMf73;iDH-wzKwKJJh>6iVZYG)4Fq Di*-ux literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/EasyGasScript.mv b/release/v13/bytecode_modules/EasyGasScript.mv new file mode 100644 index 0000000000000000000000000000000000000000..16d8f1836f89c4825f53cfd9e12fe71cc0890084 GIT binary patch literal 430 zcmZ8dK~BRk5L~Y}cG|e4fP^^k3Qk-(pq>%jEvwlUOQ?x#m#WX<5j=q#Kj9O^X=o9a zJUcTh%}Vor^Ia(b&;pcH_q3Q6kJs9NiSh&I<`WnFP5^=gAqZ%|0y9?w*BM1AB;cgT zbgD8|I-?o*ETbY#B~55bXb8}tD8vM$DF~IxA7>9P?iVgTEraip9##Du+$OF#9PFqY z?%L?n+;4ocjZ4nPb{m#l244G^IH+yc+kCb2>7@y7XV)&;6|?0{3j517r=#PVCUA^( z#~f^G?J(bNFNW+kxaBL4>Gf~AJ=n9ukx|Y6-|9>I`vmlTNqt@ztf0b5+`&+xpfl)& RKJrCsDIwyvpbjMpyhJljh~a{efnA0YMgtd6=wTzWw2_ZxM*)p3n%HG*mt7786ASHW zPS`P6*a;sH{;m*&-r+++PXkKm-4N(|c6r|}_v~^QM#Q;4+M&dG5GRz#4|W0mjK|>r zxn=m!E)TIdA0?LfF+efh=hSh3!8vh%3A^;nGCc|@5ud07>gV+ z71Hsz>k)4GxkWGp)q--jLx3|d2)jWYBVCVDAVWcgm84b}+=2^1CG|M7ViXHy)PWu! zskQp>_K6Ed%DGh!e&JfB7}R6T)e;OoVb;6_<@sebdl@{b$~rIWbq(M}aWQyOt@2Oj z^HpBgdF`C9R@JJO=dbdz5x>itm(K4mo1!ZHFN$SeH`(&iZ`C}_nr!e{e$^r^x5?&z zTGvgQTPxuPxyb5tQ7nrlc)qA+U#43;>hK0y(d!@Qht*vj?tdA^zyWm>J$c|Kd^S>4mDin3^mY*BojJ00r?v8}F+bR^Z0 ztc!kAHQB;?=B&%vBCn(M9hvpFVy1`T4VFVNt$9cIGK6vtGhyg#x9s zwqb6}D?nYTdLgz!MO{9+0B6;@Y;HcciSP0KC>00o?*GZhUc33flH$Vix?1LDj+R_i zuUo`jt{3UNcqPiJ%#$Tb-|6kOSYnmEMU8t-Z2MDK{ZZ$vEx@KpRo8R2+lD_*Wmr~M z>9SZXiaJN4=JmLzw(mnr?j@x4r>m}2o4#x-ilenZDEIOW&b^&2G~Yu1!g*XJn`j6GBC*y3 znP@unqQvgdL=ExciGoN^3pT zCW0Mom^gBDV5Fy|4PQIjH6t@nBR$e8^y2A6@#(~6)BUlDw66y$(m1-KKu65_?<5*O zNX-=u2Qlc#@=%@;G1BskY8ng@8EZ-zm?_~hitZ6GGW-^|D36(ds`0NBiIS;twSYr}BL@mMjfj+A#x+|%4CH=^2!yfbdJ zd<Lw@Rw2%H|d;eH`sNZl~={7Dzgt%-c9m6}-O8F<^iS`Yu$832y zOa?ox5s?-j z8!mUy(_C}rBLTyc=mb957N-jLrOk-m-GW0JC75?GPcg@syOO`uL*7h+ zjwSds-ZHF7pc8o)IW)0mg?T&uXrvIL1c4b|71y%7d57u~*76I^mM{1UVU>qKj*KJcC^-00QF2tgXTf(h zN5ioU12V)+$Xn+|H*J)4r1ZYs&0A}xd(yI-CqMSJrk$fsdD4{`Jh?&HwHcn2HM&*q zZtiLDtKY)p!^R_PdgEJq?uaz$yjKsj8b<&3?zN-G**Kb7rFEF5<3piSJGC{|`2Ffo zbE75x>VFp?NQ7^M2BAhM5kjRxC=d`KN65G}n3v&yH@q4F5tx7xSwa?(C*%=DLJ=Vo kWCXVr%SK!_a8aF~Aa^(%6)NGVMM4!(CoCeGggQd}0Qcxk1ONa4 literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Event.mv b/release/v13/bytecode_modules/Event.mv new file mode 100644 index 0000000000000000000000000000000000000000..a4b3a1b812a0c7d157ee28c1881bc0b6d464e54f GIT binary patch literal 695 zcmYjPy>8S%5T2R+vv=(~JMmFb&_y88!V!rE6hVt3AyHXQyh$t__G#@)bPqvAL7gVz zQFs<;C~1%wI|tloHGlifcs<|TKK$V{0Hg?(tQEye`7Tl)j?HKMj?r(*^e18M7cqBt zf|9S|8>T;HH2Wnb7aa6uQ_sJbBUvJJ<&3OB_PjM5P!Iwj~!}Z+ToAYkd4nD}SiLB~6L<~6F4!+mbdhOfV zj!ED5Wp|Ob-B9lO`Z}*x!B_S6e};#@FDQ8SJ0VKNjHff&xf&T^qLhPUriOXpAh+-w z3RYM+T*BlqfA{jh!82SCaTF~qWVFPD*oq}3IND+#Iv0x+9W8}J63AbOGY5IZNPLXa zC~F{(kH!U?#NiXn=>-t)0K|v(AM}xoRLXoa+#WgDD>%TXNQxJ2`j7GbhEab2y+UoH literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/EventUtil.mv b/release/v13/bytecode_modules/EventUtil.mv new file mode 100644 index 0000000000000000000000000000000000000000..bbbc6f34f8bdffe7b17c298d653db8fa2d8c2986 GIT binary patch literal 490 zcmYjO%Sr<=6utN6Imt|IrArsx`2!-=imnP>xe;+$1}4>kIxU&8>aVzSD~f;MR{R!! z!erWF6F52dxd*|KxR1srb+>2(L@~`R4$azf?gc!157Dhl6Y0p4Uj9|c}uoh53PaYbuFvJtMfDm^4 ai9H*dQZzUMu7pt-nk=5fDGVuomViI+@={0u literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/FixedPoint32.mv b/release/v13/bytecode_modules/FixedPoint32.mv new file mode 100644 index 0000000000000000000000000000000000000000..2ecc1abb826e4f91bc83f633ac7e73b8f52ffd05 GIT binary patch literal 595 zcmZuuU2YRG5cd3dy?EU;RH+125ot@62P%cM39s}4c;*JHRo6`|ZIWu)lyU~{PzksV zN8kz^qKw0`0;%&b{yg)2pU3vs{a;z4l(L{0nJGQeF9+t$7f63VKlur7?Hy|O9q(c5 z8>0|GDWep|l~59sR5eIS1VM_D9!WwXNEHxLsu-AA0lW9%)|VevVcDFWChzKcReu~@ z)V^qZep#;;d0jMNwJfUL|BIjUo1$8KTZWrZ`h5L*x;6KWu-k@Ptg9wmSD#}`Z@B%i zlr@xjQP0;4zifI{ScE3`w-?@*zLcB%8$hXV_mp0C=&D2W4uuwR|Gtg3Ag=<3;=}Nn zRkO+Y*y#*rli}F0<Qya%-snejIn3R9f` literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/FlexiDagConfig.mv b/release/v13/bytecode_modules/FlexiDagConfig.mv new file mode 100644 index 0000000000000000000000000000000000000000..50363aad2d38813b79e3db9110a7ffe10a62642e GIT binary patch literal 326 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 SgZt*8jb@B2LvP`a(0>479(l$9 literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/GenesisNFT.mv b/release/v13/bytecode_modules/GenesisNFT.mv new file mode 100644 index 0000000000000000000000000000000000000000..803cfbad5736fb932c885e0ad731821ddbb67af5 GIT binary patch literal 1242 zcmY*Z&2Aev5T4=BlDnk-6-SPp#7%A~QlLHwy#=uw_}~<%b6;#MN+GKK!HQO@zCxd( zy%*>U^a%>|+6U;dKp&y#aAm`(1k7?~zWF#GcZWY6|7{WgFbI~}FZfp*@e2;+Z}Fm?!<5V@O8{rY&kmVoO5hPi#c_WC{PAeal;XWRdiD$=;BkuVV!llLzdy~Pz(2R!T;ba1+5hWUdMxtgSu^HnT zLypK3%QNyii{!}YGR-vH;#1%zp(?F3Qc?V)RuO@+BTC6df{;$lnB-h(u9YDGk??3V z>cpxJA}N(ZinIw5Brf?rlh|9I#d>6S6}V4hib8hHWp7;NHh%N=>vz4^b?aU&7OmTC z+@^Q2a8>Y2?^?=DFJ1fH+R^IFZ$j(e--Np5!K;%`?U|d;cCBoUM)lJsZbGRB+x6j4`jab!53@)gG>D;FR9!uM0{k?xYg|W{Z%>o0YyEO(7B^+N%Sq09VaiTS-qv-np$^45-`q6KdMACgaNqOm zqUry?&%vAXx93+ESNW^6vv1F@u54`Yu4f%3E{aeb6m)QH$nQiI`?H)>?qgmOCjaQe zhuoLN%IVgv=pbF2xv~knF5T+{br|YElAoVVd8TD>Y$E_>tt;?_L zvMKhbX7{4=h9oX&BtHFN#wO#dP_);zukK$=#tvuiKDd+3ZRX@w#R3&hVi7kZBwdL5%e0IAyc~`oLih1ft=bWi*Tm3|BZZR`zk4u`${tqwB&jlNdQi zD-0Mh<}W$pv7D%gfH6VD{K0J0w-k91M+!1NfRWBI~ac;e$x_)O4__y2ju2k8UHs3RimsDwYrzI5R2|4ou=7YmJddwi!{sng_gp~ zjXJ+m_BwZGec@vCuen$!ch({KW{g#H>zvD6=xTW*8|yg#Eu=j9nF%^TU;F_4gd9N( n2_;C~x)(y?bue+y`yTh(5nuobJB-|)_23vBc~=g)Q+x0UqnKxU literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Hash.mv b/release/v13/bytecode_modules/Hash.mv new file mode 100644 index 0000000000000000000000000000000000000000..67a4a8bf036cc600fbb84c246f8188e4c3b8fad8 GIT binary patch literal 129 zcmZ1|^O~EDfq{XIk%5VsNrY95nO#zc!&QJMQ~)T-2*eCbAc7f0umCY57ZZy|VsQpn zc4~5RVs^ZdsTpTcWPv10xdyBM>tIF*6V|002-4 B5HtV) literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/IdentifierNFT.mv b/release/v13/bytecode_modules/IdentifierNFT.mv new file mode 100644 index 0000000000000000000000000000000000000000..44d5f27272aecd2f94a15d3e82260ffe92ab259a GIT binary patch literal 1493 zcmY*ZOLE&r5bf?6V1OAAACaO&N{*F}EuTP!E$35CB~@M|StMDrAQ6;NrT`WQ+0iAm zNRMiyD+2-#$lZ7MwgNIG0h_jLDr{icbTcgKGj7XStbn)I3Y;unfMOe=1G|C?NJ@gD)_8(J5`4$C#weze5OgJjt|aoc4JM`q>;cVqaJ`P>2;#kH7>%NFgAa?q0EUP0NyqM=@Q!I+S{`Tu1+^_1os@KB0->sUWD&6mkt1_?s=M`t(*m!n% znXj6lGcyL)xB8;Z&dNm-?%dh+O%wmPnrBV^Wwy#Lie=GkORJk^FwfUbUER*|>s50* z{NJwQRow4Ixu}Axys_l7f;ZteMcM2KovS)48?RkwP30HsStm`gSG_6M(k`aXo140v zU1XQ9!sqPm2;4ezjtjc^)R?Td6bFnPeFY~!&U02t+%71F= z?6R?YTa{$XI?v{}yUJj5Ae(l(v3T|%_7Ku?$VIVSZp&HpcOgM<_NDfHiH3^8A6z=4J&O5sFm11Ua%&%p@{-$X*`dzSyiMo9Dxe^Y!X` z*_@qL8&hu!%Jlbt!jmykk;sw4OLR22D~8LCu)=$$sI-u5Knm4!!=2YTTO?*KwW9N6 zVP>9{HML5uvF5f>vD7vumRqB)*)dT1A#UCiCqoy5rL#)qawiXEkvwAh8_)9Cw~%9H zqju>Omcz3BtLt1+F`~-!TY+pJ>%V(*+-UV4#0sR?TTcOA`xW+;<5-SC|AonKM{tX>7|UHM=JRtQp^*8AVC3v1_Ra#BZw3lKB5qW z5)^YBF%BF`VZf{IKOrrRGSD*?je&mTIGK7r5`#ntFvFe`phv?#;7%Na+~uU&8%dyK zcS)t*HOExiAF`*3Z7_XIDUElM{a%V%Y7!2Sq!6e*hzO+B!Fc3|q?Hjw!Z{RPU>A}O zTwWxs6iW!26$ccN>~JWg&=H_<5%5nC>nM~;E1{I66`XN8NX>Zdu+wAZ2#HTS+m)%3 zPOY?;#!`pQwUaX3w&jV#!AVhnb5VTx`PcW#rmf4hkHdE}AB*&h+F_(^fOvoaaZ`;m0@iN^(>ev+8lN zH0tcv#qo^2zJ#>D$yGwyKdz$R*AXCYIox&%(helTov>jCjM2jw#)5Y-#xV~8^1um* zt%uv-MZg;##}bh#TYFCECu{D0kpAzhy`#WFx4_H0+kp;w=>M@ieiW3afl~)wy~D2q zI}DCIq)~_*-iF|K$zX4IJC<*&9*w-?3GH4D_g*5CD23n?Lbed^Po-lY%L5M+pV zUXGRLd+==I^_Wm`4SOH*Kt5SlvLDFN)zz-Y>nic2H>HjO-Pzt09d!3;Sgv55b#z_5 zMLV%R++;WVy=`w_ld!bKCFoBe7{|TvYOHxTp8_}8ATjIU|9W_ndB^|RLq`Lzu6Y_F fy9#(C@q)Xj5={8v21?kHTSQ%pu>15tDpL3h!jzgA literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/MerkleProof.mv b/release/v13/bytecode_modules/MerkleProof.mv new file mode 100644 index 0000000000000000000000000000000000000000..27c43e894adba8f2d675b862c1928bf000847399 GIT binary patch literal 322 zcmYk1u};H442Er=&zIgE6_F4Ff&s$7R0$A>6%9;VqRZpUx@P=r8WfHi|914e`q&}9}VLxq;S zI(jnVJ;~7M0Fm<}&|oEsXoEDuU20$7(tTUkb9Y-Wo3c$jExUz0rmC-7sp?f#_VS+E zm-$-Crb(;kQMGJlPwPH)S+^+9XJ;3es_eh1Ismp?5bz2DkSYT=2^7udy}=@TxW;Hb ydt2~{jUGJTV3e`(lABX1_#l`dJ2~VWjV-hc=C27X!v$Tm8`-)5I5q(f34Q_oMI(>^ literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/MintDaoProposal.mv b/release/v13/bytecode_modules/MintDaoProposal.mv new file mode 100644 index 0000000000000000000000000000000000000000..2f4e07a5c960309a401f7ee55925e2980999340c GIT binary patch literal 681 zcmY*XOODhq5Unbg?Id=((=*e}h7D{u0%0*i{B|HAfy6Qji5Vigli*Gd!yd8c0!ZA0 zlW+t^>^J~UCWs*m>(#4zugWQZyLo980Hg?(>_*&v$hDRIQ~e#kQuIS)>ZeGO-y$=g znCxeE=_S+R7gNw65C~w9pfrGv5Ku1ccuEc@M1ZIvCPaor1WZd%q_xa2LYAvILB=B! z(tJ!2h?6u0xuyj&ZI&1cg=8(Y(y>k?Ndc%VD=S$DmPTL<6pu|}3=kzLLjf>erRIu> zlPGWkLfII_@>$akkIU}4@A__EZuNtz>JIH70;isM-}$|I(VVr;%a`3d*T!T0gx0To z+4rs+u?uw3&#tQ99?qI}c@@vep^Ln$TyyTcDtA-Us_Ym4 z``vICgD_4&;-R_ z;l{gNcRmkvO*#)6HhcX;5q-g#ATrW25~kDN4BHKRM$QZv%;9)^LL$dgxC@4IvTTIm wT!aSzVAnZXN?@f8-Qq~527-JQ-AN#4i=)FmxDQ037WEh!IszkdIWijl0EgXzIRF3v literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/MintScripts.mv b/release/v13/bytecode_modules/MintScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..e0d82f1a77b9f7b80c56e9f5fa91c080efa95085 GIT binary patch literal 49 scmZ1|^O~EDfq{XUk%5VwiHCzvfPsPAH#4s!IJqdZprjZmg$x)O0K)SIhX4Qo literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/ModifyDaoConfigProposal.mv b/release/v13/bytecode_modules/ModifyDaoConfigProposal.mv new file mode 100644 index 0000000000000000000000000000000000000000..390caae299f5035c47e016690518a9c920348d45 GIT binary patch literal 850 zcmYjQ&2G~`5T4oDAKSZ0leQ#OaDYmvXD-M{NE`~{goFf~I9N;UMk^Ap>)2KM82mi| zufh``9)b%u?g%!qUGQOdXTJHq@pwOfx&2d102m<{W@dE!j5{ORH|iVyV$oMVk>B}Y z@`KOyZ_dmg{s~7PB^!U1ERYZw5O5G6BUA`V0UC}9*hp>T2rvXO+pY72-5dukItmGvOfXcF;7X{-#6}Ay2v8bnh!_#4u(22-#2^&| z3ZXPZP2s#N2%<3z8G+P67&4()c3XrbO^h^u?sIo`^~Cy9U!J+;i`rLyV^^{ZDFE_m zUHf_?U%F*k)Z&$YSCmKBgpPk|EBn^1TywQ|jl8aM+Z3v}EEa83$ZFLtU8$;FgMt>e zn)TdW<9`bAwSu|ujVqT~UaaiZs1K^5c0S+lqx06+?K-PNr^(utnO!u_mmOnXTsCz` zWL;0Y>d{fN9U-%MUKg9qbiMlmS#Eu{*u6^9Bbh&&)Wv!0LfKG#XVC0f9U}|V4D;K? z!nb8J5GJm?uq&5mwqCaDqHKbL{(q37_t+&U`p};sT<36s$oQD{Xu_rh!D$?UPc>*v z;Q)hqh2e%$d;||bljd4zma^bIfaEwuLkUb}LU(y2M!^>frs^btlnfiQl>(K3ia&;+!C~(pq5JtgE<~honw;ohqHULbG;$1DYLSZVFQMQs9fGGz literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/ModuleUpgradeScripts.mv b/release/v13/bytecode_modules/ModuleUpgradeScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..f2d215e295f47705bf56c11f22c759c52fc43203 GIT binary patch literal 901 zcmaJ<&2G~`5Z>88J6^}JlhQ(k5Qqa8PCfY!94jgXxURPG*0qS&mVeUr33vi7+>m$# zj)><$;w2cz2`UA#vSw$#@0)L|)qH;VQ%OR|1V~KdfE}0o14QB@EWID_jrm_hEWe5% z{4PEL%79S92q%I_;^85Tc?0evLnai!BLN$t+U6lgcq%YN5(xKEE7b&f83Y*lOd%RW zNJQdI3CyQ6@VrGF5jaSYXZK)^g6RUs9>y_YM?TiRKk>nzMzbi67eg}(1(Tr&C}Y4w zynu$3;RiB=38BdTrsb9g3Igz-0T`9xgn$ARq6x)>9h_EKzqW7dyfK+wu9~9mTKS@K z7ey{#HBHsD@^#%6l}pad>b=SBn`?J!943ui7P+&{{ay3u^wLykO;uN|S$pqn(_-gh zW!%cHbw3W#_1d_n_S&xc&gybI{|`>rTLb%Gci+`)PLA9DyezuA#9+MGQMZRZ>g&w> zJ*({+MDv^H|EKj;(Ov4YaJnl>d-xB3y*W9|ZKwB!y1S}$eQ8=7m@I2-+v@7#XtjM* zZLf>A)8{vOM=58o^k#gidEK9{i}q3v*r?~OayBm9#;l7>npI?6rNv#meSrDd zz6MT!MI`ZXH8JH16io@GL*YkcC>2v&i4<^k5EN<)rj+ublzUAQP%!}W021|tPth|> j+2bL>Egw%3rF_t*B1xzm)X}IG!uLore>R$>5^3@aR2#wG literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/NFT.mv b/release/v13/bytecode_modules/NFT.mv new file mode 100644 index 0000000000000000000000000000000000000000..cf97fbd3cd94c264447836e29d3e4e945ae000c7 GIT binary patch literal 4087 zcma(U%XSmVwdz*&tEyUW8ygHZ<{|O64d`JUJPddkGJzyxhP+Q7VYN*sNOGjM8E2bS zzF}5b=OeP3bNGs^ak&BP2Lu+B1&f*_&Kg?Jg|sg59Ag*q1;&{#%M5X#>?Q^wz>-C$>_2%`}>T+$Zwo<)SyHf?%XvPD^2$6^o)Cjq& zT?kl!#shR~d0xiykcDz%0lQB|GKRIttvNn2<_qo`juYe}=5WEaXMLa_&J{@4_`*6H zn{XV@s*kv!@K4Z!z%>C!BigsoVHiXxvNlqY!XYg*nT2b~4>KUvI4NJCjgcxE85s>I zLQbToLj-6XU>uT-Gk{>^Cg9_U#Ta^{z<>+^*A8m?ndnr;#_Otp2}%ZiSV3-`iBTiQ z333A_OOLc%Ve`*a?3Q@(*-P)y-d_Kxmxhn~gZNRWGl+-7c6xc- zFCHet-Q=Jb4<5G<+pm+iNqXXr81AchFYOO!O<( z-W+k7e%;56-$k$cos)$bJn9~$(YqvlL$Z?0ht@~NI@5`V>7ak|vF8c@Bkzlu z{HX|3+&xTBqAnJz@NuO}@z?2~y_ZHq+X9LuJc!fib$b|F4NcVEAZ}wLT*8x%Zvj@) zN~Ty=E2)xRk|yo9$sb~!45LAOkPOp!5YFInr$A9e80y|2IZTs&PgzFNZ6Cz>DH>5% z155YX-B?nto=y08BeXCpQ{e+DI^OVm@jDw&IYUNOwk{UFgJ*peX`{EFMmC)UldGKK zpz*m6L?S!i@nGRQxu?bBuOqTt`cRy*^s{Q|3_em6Q^ zkJ3KosXIsA?n$(t#BV#0bOfCT>bhfFrtE5)q-W;F8_#4gnbcr1iIUEmH*Suk#3a>S z+w#P8@eH-S9zJjPI&Wib&)tZx@C?&M74`SagZTGH2@*4hIsbI$#m?@t-RRMiCtvRD z?&8r((#WdLxAA%#q|w3XN{hyZd>ns!{t8L&7!OA$Y7Y*Mx)?)&2F$8PZ)_YTI#-$c z=seQvW#-3)|7J`IKbc^^onZSDES_KoV~hcR!a49A0l+`=jR5&n!RHE|Dfl6N@o3ut zxg)-Ce&mbic(H@?g|j0@#EXD?vztE1AB&&(;->-sGQ0Zm^Ma%Tr|HTkg`y`yCv&fi7GWf8#ne8yTkI&pI%5f6nrZQtJOW(Av}kjAQCR!x9zH z)$F_GKy&Q>c@mh~mz_#R3#Dp*TYTE?Q?3pI|n z27`TXdd8vux$F;HC$!TFU34g3=DHLmM&kp;6GuSsgRdxjds2R^SSfetoIfGD6uwXkz7a7~Xae zv^Y*43uRN|mfXh3f)?9G$3Y9W0j^?Un#)aCk$t6Fw!t11hi)DI5a0$i z5Ks7~3pcG~d2*;o(%`^*R#&_h9#sVunbHB}a0#a_~ z;10S_EuVT~thstP2W!amH&?JRfjo~%1)G6!jWmvdQRR#4=-0s`WE*ch?0~l|ag{B# zt(;{nFSvLOxZpCEy8?e)fM7oU6QQ`m|2=%XZ&{63p(bjw=G4@hUNhCOs%p7fzE-HR F{{T>1nu7oU literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/NFTGallery.mv b/release/v13/bytecode_modules/NFTGallery.mv new file mode 100644 index 0000000000000000000000000000000000000000..bda70d9e15f10338f3b469feef051e14342bf596 GIT binary patch literal 2178 zcmZuz&2rpC5T2etNi!qukF5RkCb1Lem%!0XND2a#giu8Vs-WPga=fy=RrboYtHkk< z2jBrXaNrR*<;0OU;K~J#TzLR`M$+08sA{LDd%o_kd!{wopQe9lNeGF7Bs6)CJ^B^+ zcXU_0rGL=i2k|!xzmK}|$7nZQPd0VfSefNwOD$Q1fer_BIQI+V`NVHI(8yu zi4z;F<3v^m8`QyuUGF~Xc`@$$C=-$*QfyY-i$#>CGvCgOxM2oz)jdS+S#4*$RLkE5LDwQw=_h1!p* z7Qm!og5eJXBd87y8fps11Dbj_=|_SiXClxNw3`PF6lCig5$aaamBcQu2JC`dWOy-a z12E>nO%&m(!DMAE0xxKwBEl$k2&z8+wKEzVPn|Zai(_p{tWCDv6+vBqy4FUh7tg-_ zbnp1MSf0zL%VoJ-iKnlNMa9rAzc{Vt3+qXBJ09J z?}Gb<)T?S)o;QI_t2!*+GM67<;X$LbaJ@+BrkFCI?279m*TvV`cG_zDi8i2&Y|>4< z;K)X*NUvwf7Vj!z0e|#y+HyT02HzbG9}&^VcZdRT0xThxQ3?d`g+n~LN_SiOhidYO zyiYz(Df55;0Zb!<2FodTw((Svhj?j-rg5yn;0~I?;%I9&5x#Dn#|=M;aa#9A5a_X*d|7b&ucQN zr3rLET^iT#Dwh;f>{3!1H_~>fW*5wcD*RM@l3Jl)n@`0MA(~oEl@H_d+vYosBfab> zI{57YxN*HX2;221;5e~Lz$!%|u%2lwupZ19tsI$pwvY91X$H3I%BG<|uH;`wQ=g>< zho_MP?A&R19>>kLk(v)K49E@sF!;J^ERZX@!*|5Mt+`r_h?y3)_axRA1r0DK>=bw5 zDLfaz&UuIgj`?Qh4<75n-U)>Ay`$NO5)V~4tK%_#l_0Jw!c zjHrQO39~~U3LOA8pk{W2JA)T3c4*?AM1nv(ficC8B?b}RQQHaaIz3D@u^l@xfPHl- Q5ZDoZqY+O?1{uxBKcMIgkN^Mx literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/NFTGalleryScripts.mv b/release/v13/bytecode_modules/NFTGalleryScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..e9736e40d3098473a75e9cd4f6390736cb29f34c GIT binary patch literal 271 zcmZurI|{-u82%qg+L|B=PU7m~;N;-wq??QGrIaW_TT2W=j^i;rf@kp(K7#1rzkF}_ zFQdCw0FWRE785a5a%Pf6NUzv4Hyl4B1OlW)07nq?QYhaFRfObiG7FZB2H3Eq3^MGm zm)liQRn~<~=?<+wb-s=&%F?!e;B0+7+uYWz5BWZ}Q}2rAw6o5{Qf?dX!th@;M%~XK b%ID+1hkyc*HOztVLy_o3r3Q_f=0xxSXZih2;igWy5$Ax=7L*i15XdRCvqqu@aw z!n61s;tTi^)`)_A_|f%!d{yv$KKsQM02Tey+`nJMQoaix0H2U+BbtCC}f8 z!guwvcX^pBvclSI?8B+5?Q`4yDlbvIt@eI=6)LQ+GiTu+_drr6|I#`pc4=eo%@#Wu#B&&^d7UpBfwjIHXXRA$*x57YLF$LU=?$L%z> z^Qs@Oo1t&(CS4wOamy@52)y5{DGSL*X$~oO^r>4mepF{ECQKR vwv6jQO!}5Nb5OYp*6hyp+T3vz7pFz(!~`_Acl*Kd6}tDCB>T9@}Dt3KLY@5I{HcP4Ob+(;&JIlG!ba6DD<<(~1xDUN&@su3q|l5rvzcl4@{U04~Za==Lv|C2Nh!mkNLY~c!G~0ri=&~i*9F_Py`Dd(*qf( el*eRXVID@1iDOJ~AWxCa{B`sojt5u{I)K0L+JTP% literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/OnChainConfigScripts.mv b/release/v13/bytecode_modules/OnChainConfigScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..8d847cdf257fe6e822b0a9ca4710a4573aa7c13a GIT binary patch literal 1254 zcmah|&2G~`5T4mxd)MCeUz(%I7e|8#PLB7yg_^j{*%Em_@3{pKqYEV z?W?{zQcsAYKpYw!oQI*e|Ix?u%MZKt7I(&Pr z@A9*3+QR5vR!kS!RA1?;&dVa+%5j#J>Z88Rs&VV47ni5*MLsQb)xWH=qRvK*3Hq@3 zbe-3;^SK2Nh0FX#my4zi7FX}v!->ArqeY|BvPeg^;B>UAIGtDJysWe97ymP)%h%6Z zvrZTDab|Lv6m6U9WUqGgiETR_XVX+qCfby})agv;(^>O!$9Yp4>3ThublJ{juw$xL zQ(52jd`E2Vige!2BrR7%dCbwY!&&F(@8nqCtOY+Ck1Ji*X*uERxpWJCYt^lW!|eon z*0XBb_S_Db8ZNQ?R`pLU)7-z!oznl2x9bjU^rl$zJ3m|q$N-%X5>Mg~%!h0slVAW6 zVu0*Oltfa=q$6F)rI4QVrA(v>LXd$}Lqe!AMnYm@{yRfbNrsd#Lv}0~Zb(KPLv}40 xZAgc>hU}U9B}rn%Oadn9&?Vf^ht`{HyqpL_9(NzFNh%p69Tk}jkqn1|z+VX77Wx1H literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Option.mv b/release/v13/bytecode_modules/Option.mv new file mode 100644 index 0000000000000000000000000000000000000000..340a58f50f415907a26ff143f03e2cab343beaba GIT binary patch literal 1051 zcmZuw&2H2%5S|%3wqqx|*`MAxaO2iv2|Xd8T)A;wE!(t2+D*zPZ7C85Bm~dFLm`0> z4}f?EBxbzZZ7bDM#@~!TkH4`e-yZx81^{vdL&m7=o&M;PulT`!q95pfs>1wHQ~yud z@L5y#MSoZMFH3{pmUtHeTZ@boAWxbU+e8aCI$>*#EIZ@arl~^$PlAJ&corNg$U&Hc zXouD?E}YnrXC_Xv3}`xF3YnqUJvTuJu5csg-PoZCfGMEi&u*YinH!-55hD~5Ma1)l zxT7&k5p#`~L~KY52Pg#zSqW{IH&7zx)mdM+jX7Gc+jVDNSBt(~n>Q`Hmwq$NR_Fa> z3oq;b?d-TZnV&Cvw`iMwUN>EKTy_1ry_z*`Q|+9tT~*WTmD~Gl^}b)v7rj2Im&@X` z>SuRW>n`T8JWC2KNp(cs<@`)tREwf+F6PVncs5_3p0BE=cg(F;XZ=;$)y?U$>f45& z^Y%dHu3aThw;6HV6L!JF9nC literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Oracle.mv b/release/v13/bytecode_modules/Oracle.mv new file mode 100644 index 0000000000000000000000000000000000000000..348476de27b193dfe2f939586be8033b3bb5aa6e GIT binary patch literal 1893 zcmZWqOLN>r5bo}o(MTHYL$cO(oDfI?I6w%mDzA+V#>6Is160LuRw=tEz=!RN)P zt?K;rEZooQ{GlDq%5g&;&gSLFhHapatQ{}N2h*cj+;YD-8|Src!t`7EssBMf9%u7L zAsbyp?LV7FV!y5#N}W|reoi$xwskgZ@MR4;TlOxo3Xb0|rbV4`@I0&9G##VJC&jmR zt*9}omZXHeGJaohTAq1wBD@ae(fgTriZfB)gZ;bCVw ztFyEDqe)Sn*l~Y4dz_sX6TWe6rsJwVwU4tVwd|xxs%gvKUv&`e|$k5T~PLkHi_%v`2b!JNaBXLDQ@w*Z$BC&!k2t42w!f#8cB3h ztOqi)8|-7~lXCk*I`67+@Si-0R{H(i_rO9d@80?ynm#xC?{`NT^vS zHmrAtmWYD^N>p*OgF{S7T)I+9(p{JC#>qBHsRHLu#7pZ=I}&jkQONUhu?!m8qAjs2 zToRECAr$PAhhn=z*n};)D>)gt1-s8kmyOuK0V#)qXOcU3YHag>Onxj}78sPqMX=z(=6OBgp9ny}96jxjr+VQx!YUrn-+z=bV zz+gkjfe{T64jSoGV4>RZnYUq#8b+y+Ly>OjO~KIk2Z8*nawXu`!H>iJwi4n8C6$V0 O?8Q1!%2R$4B=8?dKsvzy literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/PackageTxnManager.mv b/release/v13/bytecode_modules/PackageTxnManager.mv new file mode 100644 index 0000000000000000000000000000000000000000..75e05951e072b1421ecada9f86bcb4d9297a2f65 GIT binary patch literal 3179 zcmZ`*&2k&Z5uX3q-B|#;0Qmn4NfafKjAh!gkwms5%S!oRRa9j~7dy2D0Sj;=a2EkU zQcP7&@l)iKT=NWhf#jB3o*}8qDG!iuW&s+cWgG@Q-P2$9bbqrmf7$$xQG^gfNuAX{ z;$QxYia)bW`8W1os{bnf;d}q9MC!Y0Klpbw3IAUEr&syY>N*@KVT2PwBvC{YkN6=W zfd?Q>NQnOmP^*w@&_|j`sVSTe1;t`d6Y.(uon5SSCv02*lu3`-Kjvcj;UF|0D6 ztWiko9Jm|QCuEaj*s{a69d_)nO9Mh$)DUtj#Nyi(40oy+_G%dJMi};EPShht3IE9R zi2S&@1hH+!pYml&2)aJllhj{_-{!t~E9qn~k;g&Gnr|YwOm|#`>MDJ@4+${?5HEsysy{RUu(A zU|eEgp`=i9%Bb$t%olHBYBmF8JPhePjUi8j}>90qFai^DlJso$Z>EN>V@}hWg(wWTl zOE>0a*!YI_)p0n(aiPs@@?zM@mlouwol)m?Hq54%l?Cmq<65WNEza_3(kXY+=yvjM zI!w;W+>#M+Hs7I3F0$!K((R1m?n&BxlZ?tLCDXTg^9P#b{P?h2~N@_2S9}fn7J2t!+L@I^)+F4CBkjHFbZSroT^DuIcjhVupDgVtP>|Bir7{ zE?=y#!(3FLUd@GqCg~^}7K5|&nsPKQoN{GxUlHawtY70p#VQt z7H?h>g@)o32ul!y&RSmE7A=F@S^u&m>jLZM`%CQsF^;QWcJkgZtzPd*ZN8luA;b9` zr908HKruLwou^5sKTXH3pBWim*DHB$MJat;`KL zmD5z@MV_kH1rG2BwSDoA9czYwbDIE;=aco zxKH-0uP_$8$NBe0y=WASKa}qW?3hc&@&5ro=8Dl+Y9?mW52?L=xiBOmO&g5k z&fwCJc;!IF4Dj}nukSc}NCO%NI&6tRRxNP7#q0ZRYFLdf z;exX6E1v`;4nh$K?YD#{A434hLqv%}Ughv@$YnUL?qk9nAZr@h61#HGLNXhQMZ6hr z?TJJAo~BSZ7}FAue^ zE|2XBlzBF1cuBc7HWX!eXECB^&35top7}DI_3ThFJfkSzycLjz{%yHFGI+3>4rt^x z-40kuM`OTX!(xxsORKV00}{rZ zHAzbo1 z=kZ_^*nztB9gd47pY}qWD9B+e1?Vjc0xS2(bH96oGQY^urJjNxvPMuw8+Li$B1^8$1lc3M>IE g6=zX!HR@2siYbEgLNt{`QhaxqW*iT1j=GZn1OAObxc~qF literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/PriceOracle.mv b/release/v13/bytecode_modules/PriceOracle.mv new file mode 100644 index 0000000000000000000000000000000000000000..b8584e7754d63d0f975320ee01be7b17fc125d7a GIT binary patch literal 825 zcmZ8gOODe(5Unb=+wM>N%Ljxw28--r!vcYjSX;*FWGqE-WP3Ck_AEIBpjmJR4!{xE za04zuwVfzoEUT*Cd-ds-%U_@WH4*?cf+U#*t1l?NK=Ch;>E9x>f5Z=* zeU`+z2n0a{q#|USS&R?_AcK&Atqi=4M94N4p4URMHBrpgDzDD8x5=2Fj`_J^hUUyg z5rr8~V9!lFjK#=mG55$s3wF3z@zdlV z?W%h3#G7ikkyD&r@vjftw%EC$?CWaZ9Cqcls)x4AnnN>`n`)@azP;^gw|Y#J?l5%s z&zk-^tMpk7H~Qo@qI1v~#eKXvrC-trwZpykkCjZ|m^%tFn@JY9AaBS~*jjkX5l34H#0a&>P z3khVfAY=@}fWb8qp(w7{YKF!)Tr#6o3tmiqe^B_OR@rQmi{j*^4y<4VXjLVI_ zN)6}V^l@aN-t5ZixJ@~>%>Vn`WgO$T)U5L&Eqer- z2#>FVaOC7$`A!{|dR|O1*r3o`C*I4`(s*@=p7f#MB#^2qGZm-ugZgM-qRuKa(E=U- Dle|=Q literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/PriceOracleScripts.mv b/release/v13/bytecode_modules/PriceOracleScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..9fc3054e32464ca19f39e147e1cd114bdb85369c GIT binary patch literal 274 zcmZ8bOA5j;5S^K%shWTy=*p#_E7!e+f(HmC1_?-8(sbd{qj(ID;90zcX$x99i^sel zyyxa41puT7obfH+i{vm%vj zC-00s`rO>?*?3olS`MUzD_qc*Jmk7A8*l8~+pDXC^}6gjqN$>5*W;YFMez64DBY{7 Z@AM=NA07h6WIQ#$r literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/RewardConfig.mv b/release/v13/bytecode_modules/RewardConfig.mv new file mode 100644 index 0000000000000000000000000000000000000000..9114706079514d6ee2998922b28c22c6316ba53d GIT binary patch literal 419 zcmY*Vu};G<5WPDmwv)J}t`IEz18b!YsA?<3!q6brC?%#?YSStSs>+A3voN!;^FJ(n z0(L_s>c#ioy}M_>w~OzD13-cxNd`<^2E!n{Iv4j}C|{|^-zkniC{&*`?EDZpDFOil z5CDOzA@m$)t`d$W>Dedk(P0dnO~1Zrlsc~y+p<)dBj z_Ueq+l^GR9W$N10(VbnHy2)1?y)aEy?e*Eiejv7`ZEU`@FGiPUd)!oi(!wnB-O2Uz zcADO#*=RDEP1CgNcg=TM-r96?XH_-X!jz`A_1Q5zsQR1d`O?-;nfGd6;6D2QAd~$A qCKrT{378HBK literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Ring.mv b/release/v13/bytecode_modules/Ring.mv new file mode 100644 index 0000000000000000000000000000000000000000..870e433ee9fc90ba055fbebda1186a8e2267f49c GIT binary patch literal 1292 zcmZ`($!-%t5UsARo~66pwiCx85LUAtAQBv$VO3bKNc?~`B$F^A8C&**gabdog%cNU zNPGc8`~WBJ`~^Qj^^D^K_vTKtn))ft3qy==~}6NqiCE5Bx2n z57Y`ilh$9!nQw&lJAG7*pK;)R#r~K81Rw!`7_tNjf)$};sYtO5RKPL}d^n0?mN99T z+E@X?DFxVU@)lcy-PpE{<$`Upl%m6O(fMeniY|4%zuWaWE_T`(XI;ZN6|1Iexwdl- z0|O!kDFP!{V>mU#%4DyP3Mp!>Iiq$3?Bx_G#PmpQA0tUV$FMbyL|x%YHPx~*J)C4} zK2_Oua{E{*mluW2hS(`H^wvatsrR7oy7EVFTu z?$%~2FW#oR`PLvE@9ghoMM=f5$UMwsxR==}{z=1UkPrK`%Gl1Ca&nN4xbyQ%$S6Cq zQJT6$RyHI!o)~C6(2#&74eQX+>QS`28}_I)R`@4WEsGj8^r)@khDgLyYj9SUE`L6m0yhInQzIZBXL8_G~3pE`ApHT^?sjd(u0 ztWoHn^Wyb6_^OSv2EL>;cTQ-0Y!ju$MLNs#Zje76I$a}|lYsko;+qs#jB}E(ayKJ? zoYS$x2=(t|X-z}l4+M66J+)j*B5E6cTS=SSB`Ip*+ykL(I#;1cg) TE@Yq&ONP+@zIY^^aOmJK&@O@( literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/SIP_2.mv b/release/v13/bytecode_modules/SIP_2.mv new file mode 100644 index 0000000000000000000000000000000000000000..b495fd3d331ac91db7311762cd6f6e490a210008 GIT binary patch literal 43 mcmZ1|^O~EDfq{XUk%5VwiH(CpfPsNE*fSvB2q=gQ7#RR;UITIf literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/SIP_3.mv b/release/v13/bytecode_modules/SIP_3.mv new file mode 100644 index 0000000000000000000000000000000000000000..3885df5848da07fab902933f588e46c6a38fb005 GIT binary patch literal 43 mcmZ1|^O~EDfq{XUk%5VwiH(CpfPsNE*fSvB7$}Gg7#RR;a07Dy literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/STC.mv b/release/v13/bytecode_modules/STC.mv new file mode 100644 index 0000000000000000000000000000000000000000..213831b4eadcf00d73097aba35795e5f129f2575 GIT binary patch literal 1371 zcmZWpO^@S55Up;v?Y6t^d`vQ#*`3WU?8gOhSWZ50fvmWVcEkpdxL7^oo=j^JJ8C;K z6E58N2}m3f2M+Lu5I=#xfCSZch6xbK&(-~^-mA3S_2bDOA^-qEU`nSSdtZOcej~5^ zzsRp7{Kfm7@$Yy)_?~<54?LAW^FK-QQ%o_R00j>i_z*w{93qH8fP@56zzyh0h$2RS z$e~1xjva=NCB$(EX&M3{SjIyTB82EY$1;X>eN=`4ML6&nz=-&S!I)r+harRLQA7xf zPK3iJG9k>HQdIJ%5;1%#Q%I&gBm>-_VHiCN4+)cl$r0wiFOLzQAG_KY#HWl!C`=fA ziSE%W@&wCx$T^RA%q36y$sidf2gxYqJ>KU7o;(^pKHy_c1SK5652WW&F9;-aZz4S0 zB?Ogm2SXYNMk2uE2q=aexT7cuBxxDat`U$49E1+IgUCV5+N#!#`<;BJ7RdJPEF&O7 zI0r0{2+qs3*QGP>-F()YRb{QqdQ)R?X%@+>vig&vu)3~w?Y&V|`q@(7nKx?DB}`7M z!dz~V=+pX*y?i!Q^TSJ%2cnp;)Y z>Y_1KdA2!Un)>SP+Aa2pxmoFI({y!wZndg6c6;>2dSO+ev7gOSqv3rg{L9lWb@c8^ zSzUa(vE@vy)wx-kX3NfT8Jp5HMlH=Zdia%Tt_rJeA5xMBHoy5OFm+xx7fIv#%~f|a z<4tFtU)pMw-@MM73R6X~S*^DDrP0g6yHM-&-_|2%o!_Egj^wVN@$PS&E!AF^snrWp zH`<~w+8$cHs%~`N3Ov*X>*Z!)%BT9Sv3Q1gy*Xc*Ccp1(jgroZtxVaZrwFruZ0{8v zwb#w0&~;<0ZT_GA#2tcK>0LVtKMvdE3tj3OncbnpD`l^BD~D5H|3}*IoJSJ&+!2U+A=WIAZXNn<3XAi5;S$M9yzX6a;3(f!l literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/STCUSDOracle.mv b/release/v13/bytecode_modules/STCUSDOracle.mv new file mode 100644 index 0000000000000000000000000000000000000000..2a49c599094b25a3e50eb303845ba33ca8a26f7e GIT binary patch literal 322 zcmYk2K~BRk5JhLk_KdMD(F0UH0YYNeMR#NmqOgwA#Gpv6D!J{V$Kg~Qfdw3bNkgQ1 z@%{cEOV*#y`A=j3xItjzU}krAVY)^F&4l( zWzA4XK~+=L;2Fh=6BZG4XfdJ+2Zv##1n7Y{QChz~zOAdL(zM&m;}xGv-{${loZFI{ zE>z92dCBd*baC)?xp2DTgD?4`KOA$3-D$Tw*YADacDGYl?=Syot?Q!|Q5P{ZGZB{R RCPbnMiOhgD!UHc2!5^eoGq(T$ literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Secp256k1.mv b/release/v13/bytecode_modules/Secp256k1.mv new file mode 100644 index 0000000000000000000000000000000000000000..5f0dd612f4273ea6dccb1faa22d56d430200a532 GIT binary patch literal 604 zcmZ`%J&)5s5S`gCf9%E=gM|=+0vbxh=`KpgMIoY~0FfVHImr@PN$hCtB#LzP755`f zqM_igT}ws9*ufGYSglqw@4a~|&CHjl_gVpfMo>&eJb5L?LcV+B-Qaihf3Uu~n_ECV1(=#$)N4XoFTs4fcV_0UHQ8Tx?A z2Oct}2+$4CB<;mULogsi&RdQuFn~rEKrprQ?fKq~!bo41Z zeB8~}`TV^-MlCYUmqk|ZoPA;Eiz-W9c1X9aBwg8K`q`D6ba0W*j~9$A43uv25vnUhK1VzDP5-+-+=8i>lmMQIv(H z?*4v|Q+G~>`&S*qP*b1Ux0y*`A{d1pJ{L*`9>nUUh6g~6BuZ%LL&6xv=Aoty(5#P1 k%#AccOL3+}3_~zn#zQn*bH-`z;(w;dWM_&AZ2~1f0Yy)2RR910 literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/SharedEd25519PublicKey.mv b/release/v13/bytecode_modules/SharedEd25519PublicKey.mv new file mode 100644 index 0000000000000000000000000000000000000000..aa92ddbcab19b8289c18c5d75dd714715d8e0637 GIT binary patch literal 615 zcmZWn!EV$r5S!rq_iL*BrZs(APz;U5XTDj)C-~?5V?uzMl8wVIM9Af4}1XJ zIC14~_zA|#qE^BOYv#?Hc{BEWee~NZ05Aw8m0Ik-%FdqT<9E_GqEg?)j`=By@|XCu z_#q|p5C{ZF$N)58$&g|Ua)v<*c8heGOad-)4cSf(Aa@BtR7C+)69MiSj%J8xh*W6^ zh?$0v3#t+|q9CO?c>jFqg6~edm&eCPuiwrWtG+$+*ZE1?j`I)~Cv#l-A@;3{V^F6d zjA1Iy`^&+_Ie3*U9}0ifPjPBo6dyQuovKVr6UOMGZy2(-W>aqLejJ+Ctq)l1U81r7 z#;x5&zv|=lV}BKcYhy}n?$Wn$RX==vz5B%TGo6m05cS(-bIj!o44br%9Ie+8{ z9{wY`+lf*W%st$8_kX1M(#K`$b1TfBbN8Uoe(Uqo0ubeftj6?PQdl?y!sN)z!gHu# zpAt)zIU1<5J>G@|S*)c6OD}-LhN~>p>KP=Q(l*F@2J2kPtgwJN)cUD`3K=VEW6{Dc J9PnPS${*!1fMfsw literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Signature.mv b/release/v13/bytecode_modules/Signature.mv new file mode 100644 index 0000000000000000000000000000000000000000..e37f2baf06e884792c42fdb4bf03bae888c3fe3f GIT binary patch literal 430 zcmYjNJ5Iwu5S^J_+xx>xXlQ6SLLwy!1qB5X4FZIe)(ZB3tPnf0ogg2A3(!$<1P;X| zn7D}8)sEi0H*chUU+2F*1^|O#$T)R6*S98mxJo|o6U{e`!Vf))jzFM@5)_CDfEETK zQUI}*l86jOkg`U}tcx82da^*l3#1e05uzlv##&2GE_y(NC;-)=cSHl@2#_##c94Y< zU_luf9(4OuzE-Pl*RZ=;-dz_(!)+ViZ@aRt;w9%@-B`{W&g(rlXIxBYv&m()U%i#Z zs^e_CdtP&&9(iucmwqG*%ROgD->Bt$JDttflT5bAgelvMH`}h)Rb8>F_+7X4hC{(^ z*VKJ>Xe6fpM*@(DMjkwlRZyu~fOZQE6s2B`lLZCxB)=yhc}f!0VhE|19L5kLu_ZzK LXfc>meL?UCh08)- literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/SignedInteger64.mv b/release/v13/bytecode_modules/SignedInteger64.mv new file mode 100644 index 0000000000000000000000000000000000000000..e3b62651c1b9513b4d5267c90b85fc7f8a58080c GIT binary patch literal 463 zcmZXQOHRWu5Qb;`iW{e;DuE)X*nlF~SKV;{)*K)T#6&@9Kxq=hak}CN?6?d|F2OiS z5f!#&&x}8N{+aFK+b94SAuz@SR~Pa+^lqN?J5K!%^ny?P!ts_1V!#7HnncpZoh6V1 zNTgfkT#q)!HK3*gkrvaS0S@l+thDKES=-E3tEHEuY22)qM-P=vY8yXR&+E8KUgI_? z8tbQdo2S+Rqs-QQ(BzxAv{_Q;tqs;qQRgqkn?t-!bMH>sy>&AG3|E!rvQsUuCOCyq zocllqhLJcly)_@rAYk&W3mceg=NcAp84bj-Be>xVsY)db7@YNOQ2v0NcE3}UcgO@N n1rs|PLPjb;`9qGA9jz$3Q#RhqCZk`Wi+!P&|Adk<*MIl{YMM33 literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Signer.mv b/release/v13/bytecode_modules/Signer.mv new file mode 100644 index 0000000000000000000000000000000000000000..a84a73d58a7f95cf8408216d8d7c5266707fc6d5 GIT binary patch literal 114 zcmZ1|^O~EDfq{XIk%5VsiHntolU-Di!%Tq3O#mp$2!sqwK*-3(!^q0W#>&7JoSB}N tTEvx@l2VjfTpXXD#+Q^|RFq#H4;2CGLIz+Hm|3_P1Q|t`7#W!u7yzFL55xcf literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/SimpleMap.mv b/release/v13/bytecode_modules/SimpleMap.mv new file mode 100644 index 0000000000000000000000000000000000000000..0effeda9fd8a7551e7aa7b6084c83a3ce1d4c1ae GIT binary patch literal 1160 zcmY*Y&5qPY5bmn3?zX!<_Uy1b%OXS+A;bY`#R<&j!rzh;;t(mBs05R#zShtin40(S zH@MIE36i%owjXHM|4Vz}Gg0=1zUt9GiOoMIVh0M9R^*V+yatKrfEA+viIhbx!jTb? zpcRpV6X9J?37CkMrC!8{f{0vYEO3%rP;kk6g}ZXZy`2f~)5#w1`@p-tyw8XY-e-Q~ zb6@yzkx%l2Vp1Gv7XVWZC!a#Q(QK-~rhwa9(On9>HUtO=8n$%My$@tCRk8uH#fBmn z1T`>p54xVnxMo@pq1NJZK!l^wdDe_}eq*aOC%}pRwpgxCyA(3GS;20=5zbJVa6*zh}rV2%TAiQs}}Wo_E$W&CvB{{IGV?G*EZ*~xLkGT z^v9x}+tXOT=>D{ATsAMGJzK3~+i5m2FRRnDNb{vmcHG_-!tZHAJNo2WL zH_Pba>#nU%IueD18rH9>)ogIukHf_VI+2l(rIXFDD1}(0YRu0@*x8mr1uiCYNBdso zkmh+@t%;&06X^(hZ+2-;uo`H-!9dc^+A~oZUx7X>m$vt_~H$k$? xIlEh&f~Rfi`DB9qwFq=v9I4EeF1RwmVE&V~F=-%f>P5rKwDi&hd75|%>N|W)c2WQU literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/StarcoinVerifier.mv b/release/v13/bytecode_modules/StarcoinVerifier.mv new file mode 100644 index 0000000000000000000000000000000000000000..684d44fe5845cdaffafd90109c0a8e06a708ef5c GIT binary patch literal 1910 zcmY*aO>Y}T7@qGP&y1a2XPvL6&4+0#4j|GN6mBGKq##mS)d-2xYVB+qQ`>9pZc@sT zWB&yguDu~~&)#8P6IS>wBX@e9@RJ^es~ zKiI!q|E5CqyLwN}pTWoO@8B=h{Ll&!KnWw92qFVQ6y5-@4hZJ~g|z`Y06Bn#B*ej$ zG`(9(HwanrV(5p+K-ad8kkw|3kXS+2S%J%12#6gW5wW|;9gI;#sTrRP1U$49yx_D93X>r#xe^rE>~nwsxMsuxPux}D{P%l|WTxSE22#>AH%k**b=<_dBKQD^>t*-K!6VAc%L(x8S8SN#GM|mGTLb%T6TCOi{ zX8!#6$FR+fd~)8ETs8ckcCG9=+W z?Aghy{_-& z!7N{rxD=M*(!e#eUqkNBA@7TOYBBeQb+^P1*w}F}v98#bag!gAXB|tIaH(9eoPj+M z4~1V@@l|JzOm1gw%5Y_pc+Jq8TDBbbw`ctTa#7+Y60pSb<4$bZ zEfR*tdm_e)Mi#qtXlO{{mV&N3-!MiSzz#`EMa;LygI)1t$rJ>ZV!NfB%&|@ZyJTMg z?u#G(Z?GZ?&}uZKu?_ack4rHNObgPMj8IU#$C{{M>E&cI)UXlsnh8q2}zcEu;N2oy%bAe88D|EnBoajL}*xszz_z=GX+ SLWe_6sqZF^_GJ`*asL6IU=6YW literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/StdlibUpgradeScripts.mv b/release/v13/bytecode_modules/StdlibUpgradeScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..86dbbec48c8d76bb2d444b2814bf40508a906a82 GIT binary patch literal 2199 zcmaJ?OK%%h6h8OP`(el9N1W!-ByH1oQ<^mCP@Zm*woxAmvHOycMicwm8Dh^^Gvg-i z3b6qsHoy-+h#fzG9SbCc#EKnag8&Kf5E5d;f&~)idhC)W&}-c@XTI~e=bU@S=fm;e z3>g440<(1Xq;U5yB7Q|jrC;f1MEO|!MpfTPW#so#JLcQz?qT zs02kCP?f5Lr~=m$h#?Y{A}is!35N)>2D+l0Y9NZDAgDb>Lrw$;2%@1R1|sQk1cm5b z?mYw|qZ7GjFDNKSH@(BShMBzcU?d@5j%!VC^G>@Fx;0j=hF&|4lv1@Cbo^Ml(hREG z`clwrvTE!FzPuFpb+3_H3PM(@)j}3UEK*k7sC&(g(pQ^o*IRZQiIRa(xw^$_ohH+- zF`q?Vbo*+h*k{XL!)M`=+jcj-rWbdIZn}P><2Kk`7DjlKc*~8q1T>J=>U9=o*8HU{ z*YgwK%WfdAg>JRUgmPuc#C@l{oB&$IYq2PHTWzTlY%^c2gv^aPVRvl6-1FkCTIlYe zll3rY2a($xtp!deDS=ZDgO>B~!UZP|@G(3{p9wc z{RH-*{Wvo|+i@Ch-2M=|x)(KcL!cO1a(aG(3N7kP2R(Uyq%*+h*v#j+Z%?+23?o zwi{y`#ZJ`gMqa^e4Z9}{x_h9Jo4rC0`eskhUR$}nQeG`PrRC*~m2z1QS&gyQVT|}G zmt!UFc%RKC8BTbkJZa`XGwKmQ2-9mR5`w4u}KsR!O4zx?pQo8F1w6Zx8BzeesAe?alvcXqs!;dztSqNS07gIH)`?q>)zc;spN)_Dy*})y>NftyVq^4 zmx3Et>fXlH*Vb=6z%c<*S_dm-r4=xV4mwfrXAo=104qZYDi9eJEGyds_&6inB8NMV zyMTMx0ENm8K7es4f>oq^rV-HqnGajOERphwM>L$X#2T@2-r59Rj^PvlNbBfkoCkoy z34{+@lT;=mWQNjUP1)2WX%yK)8f?*)2rjCim>^)`&=|0UYRHb9LNvz>tQk|Yj@vkb z(n3Ex09&zDQ#KV-G*v^eHS3Hir8EPFNYTKdU?|0+t(z3>HQPW+t>gdNnp7VgMybJB NG5tiA=0Ge__y^B6{>T6T literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/String.mv b/release/v13/bytecode_modules/String.mv new file mode 100644 index 0000000000000000000000000000000000000000..4b51f4373525345475828b2193f430dc1ee0f914 GIT binary patch literal 927 zcmYjPJ#W-N5S{(>dS~tPUM`3r8iWD`QY5;gOhHY7M0>j2If+H^oopY<75o@}5j_n( zR0vVf@z#MPBYAfA&D+_xp85Rv2U{XyK~6farYpU3=F@fdTYMGni>mB5HS@oe4S&>6 zS$ww=WI>V?QASc`0(%XFjD)jF12?GXQYP1q$miIyM-(^^6$(+QfK7^$s0tIJ7)nw) z3PECOEve$b;f{mD2kw7qFNJj^td|mN3Y7wk>Ox4MW5P?N5GW&52WHf>*b!$H#yb=NMh7OTs8^?qc=TkJpi=nm;Y zTy~4I&8}T9yZznyes{L$M@6pb7xjnju(wxrdof)4d#Rz@k9X)Ksc71d%d2LMbIYOD z{pLfh+f7@eefLc$mpYtGp$GpAzuL>xWRWpVs1y~=<|NTC5{5B6v4|Lkv{g(M;m;wo zDP(Y?l^VeGl?MawadG6^X`rtiz5%ftK($QE) z4!K8R_Q3{o!iFs%SL7@s!MjMDGaX8UIkosOsA#REJgL%2)m%t_yE&~S#-C;{Qzlq% zPb-L&oE_^4w94b8@J8N4Z%4`6Jj#P+t)Bppc!M!d^I+KMXXXXln+LFkMj73dWI+81 ghCCYWn5HxbV*FeM%%Uuk5Y(z?_yg)_B2xeW literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Table.mv b/release/v13/bytecode_modules/Table.mv new file mode 100644 index 0000000000000000000000000000000000000000..297bb011c407ad2b2ebe612110e13206bca96db8 GIT binary patch literal 1107 zcmY*YOK#La5Ur~I_|yK+C#$?!Y3-iXB4iI0i@H z3~Ufv4nTE#GLu+pSJkUmRbAcH-=6<98USJhNiq?|7nDEnQ2oR^^nTGj`M+hR|H&8O zy^76OC8O`^55=E-ncVr30}&`emK-jSEdfZvS}0h65{v_Ap`7Vy&q-hV77l;~K^Qoa z5upVm5jsw6T&5%%Go@yfS>#xG6kBqEhJ=I(CdAdIIa@Snr#<7>;V3MU?9}RFJv?|= zJ=l0yt*+<8tZLfxdc7DX8~icmpY`2P&%0IhpxE4T)2@bPe_OQ|m&0xT#IpXPS@xIJ zx;vY-XP;WPLFK4=(RLq)ndsW9CRP~`$rEO;aVlMoCK$_bPZ!ZDADn^+Fs zH*f@d#6t}H15}2IB_7+!Bapn*4yGd>2sS5K2q8w|jS;1IDI;qcDy556sbQ{|qY`1DU R_8UnH@RwygjldZDi3wtb=5||0v3c7n zTyM=_oOQ|$cD7AtFO0J8n$3stOWofJ(Vn;p+;e8GXAZ4DHLm6Z`Pj|wylrMvZ@ck* z(=E&Coq%@N_h0Le)^zR44xf3))_Z4jaQ8rU^Z#D!=jH3NdRf&cXJ>E9s>-iT&9vS1 zd{1B4TMb2=T|p72H#2iH`^9Bl8X?z~aE1I({450pB9svp(IFu-VWOajHEtj!4VsRC z$P0rad4dl~EVi&noCu>MHc!b110UQJMmHSGJZ^bcD~csc+8 literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Token.mv b/release/v13/bytecode_modules/Token.mv new file mode 100644 index 0000000000000000000000000000000000000000..4217dbb830bb72ceef02b0cf1811442146c4015b GIT binary patch literal 2435 zcmZWrO>-MX5S{6n{m{%xmSkBT}V|!z1*Q{1? z3`g!)BU<UYqvcmW-!6O9m(RI!E zV`T88y@u|O$r#Ru-Q{jK48yB3TnrmwC2WQp-HqidA-Dl9s4zxEBB8Hqzt%qHp8Z(h z*37lQIZ{d?xLwA_PRX%_!nG!eE}%$fi!r!_sn@~n2kzQP=s+5br%LX7XtyfHnMs)A zX&*lda2?Lz;OPpED~t6|Ps`H^4eg}*C+TaGJWmJaS(=rfo72V@X=dW$oTWyd zb8Bg6*H&!KCwXGVjC9P$NfN!l=+WLRo3#ya)j6A_IW0T!BrOlmdA!6N=fkw@BxYC^ z`RT=IGkf0(jY`xW9huXa{X(W-8s{5Rs8`|)0x7tZh)x4dfWig0%dGaRb%Xb-o}EAa%O zD(6+)9~qxCCq;ZBsarZ34F;#!2GdX6c#w~>(kb&Y?)xT7Y~x+ZZ4xysB;iVkhYT0gb1U+)={m;~?d z^FJ>9{mEGP^D}lhWAzz(Ib+Qk8_d|jjP++Mow1`CGZO}UodLhiIl#N}rtbm39r>OR zAn(Y#@_lhnNOC(9w+sB1^gw*zY%17N;DhYRb-9iAgzwxZ~H zF~`{ebI}9j;}yjks}IrNV<7N#@t2l*Ja7ULNF^Tt-e!D91TJP`E#-C;Y_bInn|M`f zsfBi$UX%9#FEhq;VCRBjThP+b)@&0Nz?mf7!Iul4ExhS8+mYZ+%~&=HW?Z3J+?}*! z_UTI3sd%Dsbp!Bz=l*Jl>SO?cPy*HALqfXfaU)%PQz(Y2Kugr+^f1-705!>aAFvo| zM^E;gE-of99&cRRsGd=L(HVED)DUb9%u!3Y)AJru1E7vglhdZ*d)M=!VP^>B6=-5h z>Ev+eDQHooDmFu+z%7TsZE3dUwO|2V*KRBB1#8lAuyXEI8rL^mHK|+kdyTaKdLEXE z+oMHScAO=erW@-UidDAxE~gLMWs1GgG>u!()0*{yZP*29qe6QK8mk{N=n$tPfg=u= ztom_%ehV(6Fy-0mtGM+{11wS*vWNd3AS5b!s_DU!m{hrJ-B=d1;0p1M-G0T_rRUJI z?6JlTl#G7GJN8Iuj+?S#W4$3AJwEe=%X|<_aDfjX9cLZ_9%dOjc&I%*+SsT60YCMV A5C8xG literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/TransactionFee.mv b/release/v13/bytecode_modules/TransactionFee.mv new file mode 100644 index 0000000000000000000000000000000000000000..f209ddeb58683e9556d9604d30f086f9323857a7 GIT binary patch literal 567 zcmY+C&2H2%5XWac<9yiJ?d}02C`X=v0|cpns&+wKIFLPXi(F#BqD@w@OQBp4FM@a* z-h=}WzzM-594J;i8vo|68G9yQZ~d?t08|J@nHAl9$S;gOd60j>Z&-X+EAvy8_7kb< zGkskABDMTYO7sW{2pFJ1KxP)JR1Tm4ks$*mHWw8XN&p)afEFcO3FSqW3tdW(X%7Xg z%p{|n3WCxQW+JnQCCJCKqjNhSP-FHt!YZE~#zJb(?rfIZ(e=^2OkwCBd%rjuMt|6K zqmR)?YPLt^Hk|pG+}TcVhqu08yRK`~`@VhUeVZn---VdQaB`jm{L3~8q6vLS!JURn zpYPmrn&B<=9t>ozV|W2Rtinm(C^&oxi2n4dee>W zV)?%+@BD6vAxWFBE@?TI^8=;xvQS&7;XXVPF6{^2U+YR)SZ7upKt+b`L5&p~zH>Fr t`FEN)O(=z?Kez=7Ax%rCg?8!;!%QzUinVdn*p`vx zCV35BfZ+x%x#foYz5tKF6&E}LoRuxtw6HT-pFQX7Ip6o~M*HL9pTa;0Sr~0=+ZFxp zADH~0Ez{q$-!c21{KU*(Ma6h6e#Z7+_Ae?EBMs?@Ac_pckclkBkw7*oAqSOF1-ZyW zRa6s#VT39bf)Os27(y3dC#q{06Le8m^Bht0C939m17>5v#E33p3t3B?BX`-fF)6Q< zFw$2YjLb&4g2W2i@;|F{WC_i4ys}sEh)2D7Z(gieYu;sVO{|M`kK0_+Dg5c0 zE)eD#;x^S`Xk4RMfURP0uT;=7iXb6oVH2Vefw8G!!^Rrcl?7`HX@;#c1DdJgc_RuQ z7$7ki1R#v}S%|2iq_-)Y1I>RG7)n%W3#kgK4}n_P;FdzI!G4W`C(rN>l37pD-*Wc>BOT!R@xn9$8wNGogj-7`b979oQQmWE>D9bWP8U!Ghf!{b z!th`1m_@XloelgqfgAa{2tr~#0E$WGcjZ8)QR)X{)_PZFm1yuP=tZF)B;8RTWLpTM zG)tnxQ6~NDjmZ9yl&Lowh5`7yz4$Qb`57RtLz@mL=#TOCWfnk6U$ zoFqR618}5Sr`!!vKTd*9Px^@rLJu(cX$K$;y8aOyaGcbJW99u>mVCm&kB`a^_rKn6 zKWh8C_wPU7Z?`Ln{B9J%u@*d+q1Bk=EFpzHKQb4>{Wu%}f}q!nPi1&Sn>=`8-&WLidue`{ZRH~7bt|K;%=e`ssP8yb9t_(q*$zN~KGW)sD7C0ytlS_Q3bn8VcU?_a%?_ZM=T;lUpcd2J z+UA(BL*1OPf^lgIW9gl)?>PP!h5}&-!@WSR(d(=PVscXo4XmieirU2lgWw%Q7F{~VT))1N>D4@_|W2!VPnyW-9ZM&NQ2imXX&8~3V zAPaPv832=RDIY|)8l*|La-ZT`{C}u>#(=hEn;@vOL2lDKV}9m;Ab!EMTg zFlQ=@0b{sx;p;Bc>%sNi>-}Zx!n;?y5vcRNyK>F!y!ZBOv+*_r8`R4C-Un5=rn5f2 za9bOOdb>+p=LT1|?xQVTFx!5!Z>_1@w!gNUkqK+>cEiLx=C$Fg}KbXdLHn@<~hdNDvb@FWWa#g*k%-M4JW>r;%x9|6knlMMre6k!% zS>LppH+C?WA0`Ej|NnzL`bk3{50B=DfTACNxg$l~!zpAeLE1KLO)g52Kq*W0NNAa* tfSQ;3af&G`dB#&n`6zaJ52%$|3Bs9b|kl+gYkFqvQ(bfbdDV&2Na0-sVVYmbd(gYIz zu>I`kXZwBqC29bu5gKaFt93iOd&A}f7xEMDa|3|^0WYzl4D0M@Rx(25NJMb94cbNB zC+pqTj>b=^dN}(2FfS-3Jw7l0Qy#s0vioZr)r&sbL8V_2l}>ZQ`BxQ9@7)lWdy`Z@ zg$0vUV*don;N literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/TransactionTimeoutConfig.mv b/release/v13/bytecode_modules/TransactionTimeoutConfig.mv new file mode 100644 index 0000000000000000000000000000000000000000..f54deb348e9e1c1ab4a66540e50e0aa4a049fea5 GIT binary patch literal 447 zcmaJ-OHRWu6nyVFalS20g@6U>71&nl0#$8<*svfKTPtl$vD7A2>BixPv2_YTQ8>BU2Eo-TjKKe_)Rm0tW zxl#H~xWBptwvyk+c8MNyH4@J-g+2`6kkE2qnKuR^2g8iVkOc`On6WVu``RZkbk)Nr DnyF-U literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/TransferScripts.mv b/release/v13/bytecode_modules/TransferScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..5a5eaf79403d771db081c5d3d6720bcae3726783 GIT binary patch literal 719 zcmZ`%v2GMG5cQ15Ua#%jBS%O91c4}0geujw7YQ2ZprBisU7vDAawo3|(DEk{;uH81 z_zQl5@g9dRikRYg=Izs)(azjF{_V67!hq0HzoIu@y?xvPq^#YtNsh=?7q-g{+(?S?yYC}dFXUJP+Em{(?WJF$B zWMm3SdPQm^xZvC()PhJ#1&VDzY9>Kac`Q!frEoPYV|v@A)g}+sqU+Wlud;rb(mD;Z z4_A=(sha8Uo|A`yb@$+iP zLmTp=F2#^z8@3a-qelY0yEdO!U;KDtlTDb~O%6W|8$&yvi=~T@cuyk$@y|((GdP>Ju z&!OQpp1VUY8{ss2q9a`nr^JybH9_2ODN&YER&ZcXsHA)@#Y|gZvoaUX5qZ-B^ma@~ Ob3$DRe@Ds<6^cJ#q9=8vYR-|!X99&IKYWiaa1WQZKA@Kj3g(7 z2jCI70tc?V09AYEM)4Y4_7UhANzPJ9WnJY~Pxsfq)0)w5>;EcA2x(H%g4P~;^bh4f z!BG4Pe^cuwsJ48i9y+hp1NDn5-QV4xW%Ez3)%we8p&=ze7~w<^Ni6hayA)-_ z(1xLoBvNve!aJNwN)(}#6BjgXQiim}HNPY@ZA(o%j3f1^g>>0&Anh8uVrzWQ(7q#) zAJ`hRYUof2j)6TDVyCtAQklm-UOO$^2=UyO0ift!_moJB!C&o1TjEK9RoJU@?; zf`1(pXY!l)G>NjtaXgLkBACv^ar#}9xL-uGG>;1d9DEfgQILHb7iVD>TznqPf|Ga> z7nk03QL`2q%grDR{fV*mFDi5Y#lpU?)i=nklVB1gFCr@}v)BnSw=BK9#noC3xxt+Z z(?yg<^h2B%xgQjFPov@%hyEt zqs)$~HM7qa-06ag7u?H=BS7zP3VfGu^1E!00kEby820hxu=zbr2?P2r_rou-qIImpJ4T*yi@bI#B%tMLvZ?GN!;Zc%?T6&V;mBXShEmPr-#2 zDqZTp0iLNI88Zb3c*TtI$kL%KMV{b&Ln(+V@)P9oo}#e2?~rTpcDWF?#XB4O7)XiM zRUqmRhw4o3@`2dEGtvS?IrIP=;_})9*aa%O;zO-m(dtYG&V+;TG5x5Nd$(}*uhyq^Sc+@-OP;?bJl-&`u zu1S_q(ik|p@bXvINlXPdG@&WlrU{)Lj6|;i6n6QDKpVFNFG+>Deny~!E4)L^ih`%N zYx9Y7-B^cqbWys?SWd$gn7r&dv}cMa`-^(hUtN|%`wlq}E0_&O2-kJ8ZqMQUo3rDJ z9bpd@-fFOnA1F9GQm6G4M`Y|k7n`xQ*V!?y`q*piHu~G+EBLIM*mtSeEtl}vs2_Lk znD(MZ;UJ=03RD=kSOfHQy%d`@R?ye{sN<0PV;4sgMS4TAL`8dw9LN>S3otEw8yFg4 R6Y*0A-xTI?PvD0G`40haz*qnP literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/TreasuryScripts.mv b/release/v13/bytecode_modules/TreasuryScripts.mv new file mode 100644 index 0000000000000000000000000000000000000000..23b7501a57b223bcba74253c5b6edff659f4d604 GIT binary patch literal 892 zcmaJ9HS=-r7oa9p60RnOK)NT=!NFWi3(lYi&SomVg-f*O&Io^Y}py3gC z5?+F_o#a4Baq)TP``I6RzCZeHv=AZ$VWqX|a*frBzQP>@ck+h{f70CkqHn+!5K<_C zf^cF%fKtdPv;YW1AbSiI0E!41No!^(2pG{s6F{`a0>X64D$ZsxV?62W`J7QM7Ja?E zSTPcjrhr0MpCU+!vScyi0EnTG||x`B>a5*C$K1Ez+*3N}pE#KA30C^OME* zCm6J}Dz`3c|M6uXN>1-DUk}ppSTD2YAUti|P5s%OiC!J{|9|bcaC|d9o3GQ(RhwsJ zm%5wA@6W7uUAWG-^*PJqtSHW`pmY8q-aR>efWA2T`O6$G#>4yf!()pAXeJC8nFtWab6n<}h9nUz8)6zDyRCIxmH~*5o=#%~~ee#}t#6JIo6Zso|(BL~C zh@X5f{KJRpvmpA5xW?$KB>iuacp3r$3Jf?1kP;vW5Kx5L-#KS(JZxj=0ipy&5E*FN z#u4Ml$a>HtQnHOu0llX+@J&?6#8!XJ-?s-IPDU7`r1yQ3>PP*Go?OtJPsdJq8NzJw?=a_pM2BQc5{s1<3!$h>F| zDOt344xKes#Vb?1bwycJW)>Y3&b~}jXRFFq)OW;d=L%PeciA+zjvp4M zHV>8x(Ndx-kB*!vOPel>2c|T~*(|HCM)uN9n%X883(KTj7!L1(MLBDxSw6Ud+;T=M z@=4*6<5@8|O`N?jE)ATW*zDXoVdh1X*P^s8D^fZ!<@TE_x5nLd*|L|lGn0CClEf!j zk%#7H`lL7+ID6J){#7K4T2!~wFSCbPRW&x5bq2SSdDF$zd!F{6wmxeL*UXdiqPEo_ z%g@a$OB3U!&D`d-T#UbI{FiWbGPSv_vei+xS1+Rtl3P>1(EnaYgOf#01G|c*OAMiX zzQzU=3C7*_VB}ZbFV&7hMaHlWnrj+D%=ek%0|kEVWAS*5&*3R3s`!{_ra-YV^*;uH z8jewu7O%)Y3wYEr&@(&+pTP?t#G~SkG1ELGia%nK>lQ;|)nOD-blB=~LfeC2&x?7L Nn0Jmi7Og-8e*rXK)=>Ze literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/TypeInfo.mv b/release/v13/bytecode_modules/TypeInfo.mv new file mode 100644 index 0000000000000000000000000000000000000000..1be6ae92597c093fa4c307d0bb65bc4cc57f14f5 GIT binary patch literal 312 zcmYjNyG{c!5ZqmRZO0A}p(`U=Y6_&3JSys>ptFuUM~X1?hM&N9 zQlxA(GdsJQ-LLtdQvhHQ6e%g}wY-shd!?7p<{M}B2i^1+@6JAHa3K(Y1`q{-90&`E z64a=(LO>&^xHL}?SSyXn05V!aH32Mhg%&`9Em<E_oGSLw8X(P3*hu z>$cs8l-w@1{Wkcn-UXL7AHm19f3LSL<$d4eQP;VwDZ0tgzZ`N%CF*IFKtiyzq$~}| lSvr_OMR>$mQArJ?94ugp=Xh^O9Gg^;9I#m6<#6Ztg@1jSDjEO) literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/U256.mv b/release/v13/bytecode_modules/U256.mv new file mode 100644 index 0000000000000000000000000000000000000000..5114e77f7fa3bb190418c315f2b2e2fa6f316645 GIT binary patch literal 1125 zcmaJ=%Wl(95S{z*ecEZ9K0;|1ybBUiX_Qn&Vo?x$0&F9fn95ROSB_Iuwx}P%k_{X7 zY}oKGtXY>C$L@m#quk>&Gskl$bFaT_|Mm(1JOjm*6z)uZW;{4&&-D-Xhner9tA2_X z?n0>WTz-|&H^WiR08s-7WFWZ!2#6_(paTR$%qj$@5jV*w(94#5gRmmntSS(L1j zZjE4_V8dZ=eN3=Tt%2W;I!L#WZfI`605iaq0sJw}9Oue$#v~J5*Fj*I5o8V*v%s7M z`F1ecS8vL)DCg>3`o1bkkxVA~eK9*p%2Z6U)0GcpF&iIc$Ky1gWJ&Ip{#ljIdo`VA zRW(hUtgS6Ts-oD?71XqnDhI$s=#B2NWo1%?Is zx+=!Bjr^3Bg*?itc{j^XlW8^?C*|>Cmgbe6XZi6ot%^KqQ}ZgRQarNjhSLIJCQV3~ zUk&4o;{b&r7sn5>+azj_IA;>qEmt4B4I=2U*m?}1-0x~V45gEFp=x^|p9IEBx(2oN zF$-OA@|9i-xnnIAjyrKrKK6{^P4V1|`|^>NTniqEWe|@an}%jfhg%AAqYk_j>P}Pt zp;Up@EMDK~fQco?UV(1oe`FSA)L*#iU~th`Qx3L=q42PG_-q(rPX`dP2)lc&BX;>0 z|8YF)0jC>prH4_hxFNorlgFklcI0p&g%DSStAlHWWMY7L!>~a2sz8Wu#aC{GZtu$N zpu0-$Q<|~DZ?ZNV^<}enr43NVG>`i`wTeDwvYV=Yuzf>?Rck}lXzy^>Q~f4HZ;rP3 P8f`2FZLob}|49D=@Lhsr literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/UpgradeModuleDaoProposal.mv b/release/v13/bytecode_modules/UpgradeModuleDaoProposal.mv new file mode 100644 index 0000000000000000000000000000000000000000..083a94d1c5a49560b7ae39faff5498708e8fd823 GIT binary patch literal 846 zcmZ8g&2G~`5T4mz+q-G%lr}A@f_mz`7s3Hm;^$Z?5``PGwvL-vO>N_!QeJ@z6!8Ka zIP(ZR2~WTiATEp(r%-(GelzpU?6=x)zwG}s3IKWtme~Ox9gEjW#!vKDe9ygaVpDw= zqu__wH@^h4zr|DAhm`R&aNhz1fGEH)L=BeHUk*^95L-$B zyQhh@?Gf4`gu?)t*0{?pEqsr(aOwHJ&y@8zC}m~9I7cQqO7sDhMUKkj%m-^sr^+V0}X!exJ1s#r9$G}|kdDw61ODJyDL zBBQIL`&Dyxnb!Xo3YxOfk==A!CRJsNmFj5js=2;O$|}t>9=pOzvh%!*lWDJRUdEEhZr+JuM*QJZ=XcfCfL;-F6pi{m+ODj2g zo7VG)X3)vVF8_YWy-&DGaPQ_8ee4i0-jf>v>(i~{Cfzg>T^u4xvKffMm>e5GC=5Fg zp6nSwjiEd=VDJ$f138Z@h&y9=3=bhx0p8Le)JvLSh8sCxMvRfMmTpFE`5(0z}7t1r#GqL2cBe$I; z99H`h-1f3Z9)K$^fW!gq8*t#jfmfi~Zcl=fIz-w?5iR+rzpAeK`s?a(&&zv%3y%;o zpd?_ykWU{wUo!WrBmXD*vlIO44#VHw_vLf%)fAj4VT2RMC&Y!zgNwlB0}g{t5U`Ta z+=Sy2BEf?m07~zf+kInyBP4`95QO?67z489$&iJNpEnu?6#6uvQQs19ms1KhN5pnRg;8ZauhJrqwe{Z4lPWz`o4(A|)3}YGtH^Xt*Cra!I#^}J zEXm@vS{LP6e4@&Dc2+5{>gr9z_Owi`$NoCaivd zOiWL@(Vz|}n6Kg`a4*W;g<2+cR>jGDUetLNn^D^r)rEnfl?h&@iPH)0r#gn%l?Ts- zIvv2{ILR_~wwJ*2mQ}n`xzd0p?TU|2>RFcRW4^<8 z`5nH;C!8`i<@=m5K7jHInI90&=v}C9Q|0fCJjXTrrD+oOfd{bd2qGPid_OZ=fk+On z!$4AZJn|(K)R_d5x%(ry3+6l!+=H#qw5jBtW8b|&_wrp62DaJeC9o#Jh2st1ZhJtc zb=(l~9>NARZA=(7>~=yj8VDk&U}mUrg(rLwh=B-&5K=@V_c37%T=`$@5H@bxB#Fp* z&~BO|=TjH(XC1p9-gP$vt^fZOw=$dy^_u6K*}~}SiRH!c+or!Q(M!5v{4pGx*LD4| zI5&;oG|zYKX71O|9R!~s_-|H-ew+yL$8@{t`QCJVY+j$)#C?4*J{bNMqUSb(Zy`9g zE(eJJHwZpM@DJ^0qCel<915ZJ@kcFu3I7wpKe7V#kuON)W!tj4+@9TwC`5}_^ zV+5aAIs0sWLHse*FqLnWn(%eMi_9xQeg({*1JnBYylUY~_y-7%<^2PxszW3WhCfIA zZLwYAxjB_}+unZNuZwply}mwJobII8_kRcBzl-44&5QBD;=C@NPZ0hXpIe2)uTR6r cF-Pn%WiAv8-MRX#Jti`0PU6v+jX5L#0&`?Gj{pDw literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/Vector.mv b/release/v13/bytecode_modules/Vector.mv new file mode 100644 index 0000000000000000000000000000000000000000..fca0c13f9fa22089f35b632ccb13ea8f3c0c1427 GIT binary patch literal 1256 zcmZ`&&2G~`5Z;;n@p^ZiCT*IuP$8u$R9t$_v8{?YaN@!VDM}N!jc9Dkc2jys9C-)c zhIc^X1$yR)#H<~h2&pT3cJ`auZ#+N#e(-1&V@v}>j$c501uefp8vKD@pnvkVdgR9a z=07Ak0RvzRk(1;?k`yW+DYeHH5D5!ZNKzY*hsKgL)h#O==`Qk~QRMYj%j;Ve-mdVD z^9S>yklX+4^ zv$!bp^kEz?vhqPzQqPlF{CS*S>3LD(>NZZU%bO^fl=Edgu37(`@_3OhsJyPcP!xSwR! zi*Zdst=(L}b#tV;gRsoPi0TMP0;$^6q=BEBYB@CQ%sFn*@S%7vjbR4Qoq>VqSq2tB zqeVrRs?~ESWsQd@h)&Y$t=q#VC=WI%`zuO|Pmwk(=w}cp)|qRt0cr|IBS2$`%+l-V z9MRh%XWKUHgmOUx7GDWRu>y8nr4P8}*|=pRq@kn{4^G`GCE|#{vI}PcJ4Crn=ADzO zD$;<#o)bnG`BFI9t|<*RUvwmP<^BqV1|5h)E36ziE{{UTEf=pX{SE$8ERHztP>Al; zY11gDeK-TpoN72+V3dJ9Zy1VxW%uX43)U`3T~kAGDqn156Rz#jPzFOWlE*%gJtKRL zN17oLl74ty7UGv+eh%URJfD}ag9z59sMk$* zy%uj50dNG(TB|tMGd6Q)SL=A6M@^Chliru(C$Vf1U;!Rn2_Pe8naPl%7&Mac&iA3| z+GyLg$EH@bzqr=lit87fb9w6eOlWa<6lGQQJ_I@ZFH*7pWhSkLZ)_blNGYQnQzju= JIZUJq@Bw@68Sel9 literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/YieldFarming.mv b/release/v13/bytecode_modules/YieldFarming.mv new file mode 100644 index 0000000000000000000000000000000000000000..50950090851a88625a12d6ba75faf63dc102e95d GIT binary patch literal 1610 zcmZ`(%Z}tU6!j}{5~r$?dQ8tW1H;S!4TuHI3W*g$!wv}vHmoAkaaWs8QibF6V^;G6 zNW&+vV!;xL6>RtcR_xjH6I?s#6r-uCQu!XAdwj2bRQ6Bz{}mxZNMIC_@O}E>4>oDnFN|*3CM6YRty8!PlD$)zGKcTRtSx zA%5Dn%HI1@8d)o=%om$dpWS>WxAI$EX?qiVW#xrBI+fLFS4pdib7?MBYYW|!>iY2k zzPM6)eQt|q%4{AT)M$HNNZ)=ZxdO5@@~V*arfY0e>dT`0=*h=3b*)?5_WDBF_;zlO z2GqKZLZ*;qX;j-%1&1AWo9IScEi3&@Wjojx%W8k*VtZ>rRCkr{dFT61nVVw0xh$-+ zZ`hOQY2PpJvE5i%6`l$F7+KRbr{EXwnx3d-V|ClgsWnQr9n|$T=iUIou0ZeF44us7*L_J~q~A7i*!Z^ig+_6|E?WQA93 z<=%soJQ)iNfZzkXdo%Xw=>a`+`aHp}ba==($NBOkL3>h@S2!ZzX*?$Gtx2gspCA(6 zLQMEABm|x-lyZT%$R`5lY>r6mvmE8ClVk_sp@mAGO?S{a$rpR~#G{l1V&6$pA_$x9 k-|}5Db=CJcJUhT=2l#xq%egybI7Jy+a&b%+y9^}$1C#U(mjD0& literal 0 HcmV?d00001 diff --git a/release/v13/bytecode_modules/YieldFarmingV2.mv b/release/v13/bytecode_modules/YieldFarmingV2.mv new file mode 100644 index 0000000000000000000000000000000000000000..e0e4f01ae5c0088a7710dfd4eb8c9cce6f995249 GIT binary patch literal 3429 zcmZ`+TW=f36`t$P?#wK;EAt|WvMI}!?WCz%+lfRus*RvX5fm_5z(IjL5gTzOZ_Qhl zOJDNZ0{tC*Y5Q29KnoP;Tl?6z{(wF=f1=;al5_$(1T^RDxzD-GjDElWjR^=LF(sDS z2mJB>sQ44xmVameX6kqHA3^v}lLY@Uf2R7k@k8^sxMBYl|G~!J?Cvyvvv&whN*Lip z5J>_>h_Vb6O2Q?KmQXLD@sLO4@9q+Dmh2Mx2pIhsi#)$|n+o=mBT3}rL{brU zw+>|Q*5T1%)ZIPMz3T@&u!2(~SVSVqLJ|@h5(Gho6oNZ1SXf|~7w`lsDTNwRX95~g zE=6FtV>1?5Pa>driwr`{B^h=kR3f(K(6>60Ma=6lxg=6f16zAU01OeTmALc6U9iyM zLK*7CR2?8BL4rL93E^!bLZ%!>>Uas`_^sr*T%!V5tqEuKb`_T^L6?V^!|H}daIiV= ztMNsVkA^?X%5gEd`qhKr)3ThFbMZ8*o(Ip0t4Ur)pBLkNUS;E%{CxT%pYTs#&(u=E zF5xHhd0wTTW#vmq{xq9qUlyaHdb9h>tjxxFm6uPa!{YMITaJ8IWiRq58x9AV(^U@3 zU(Z4Z7xy3ZI~UpLVlm39eDJ(BJ18c@{PnHxp$}f=#ntm_@O55J55HHYsGisUcHfG; z0&!SouLjw8x|mequz2Ys*velQ^J-qp53(v+eOH|&hNQg6!5JXvGM~>mHlXo07#3xI zQKfHDx3z3CRLiX-t1UU-gNtmYi%C%x*{JwB569W0D(3Sn8T*_KW~&^A=OPCzG1XQ`1OkXX1&XW}6qda`E{N~|`$-~i_Hd|xG8q3$%S8Hs%#xB>`)f#)g#wKfQy2gIJ#6%J; zu@w*rA;UlZ<*)yZR}{kNb)0te{rV_l!4Jd-;)ncL{D}XUaz^hIA{APPH*1TO!FfV%S0J`Ir|-} zj49UB;GB`gI-rY23>4A&{S-qBREBX7W~Fhe^K<3>WoITmT`gmIG*d0UfH(%kTW zB(8x$n^;&A+ajmDnF`C~;fjo#_}e^g8BXm0{*y!#O>tXd1Kfqo++I67sZF~KZv&E~ z@7VB7p%ii3-AwdN5pTrjZSJwq`9pC&CM;T^jOi81AqD|uh}uf88Ja5O-#QX>fV$>M zkU+=9XM^IBVqD(P23>G2POhB< z9~<6hR%xa6scd2inrUDoAgXDiwl&(g^gl}TDjprJ>bELW8GEfx5VJH$Iv412( z%M*)808C3u7tn#m&1}W75q-x+Waz?^sKu_qs6mTu6c&AeN25e?Hd(I4#MTDg_reZq z;t9&+-F+Vs>WjJrh|4#=WygjgguvA#sB41viK~fdvzFV{y#y-6QcX|eCKm1%g5Jjz zur?&5>y&eT+Gw(lQ}CZ|c-W5nY#EJ=xpu*3@zz5A4 zw8|cu#pS9c_dzy_s-Qk}H0WDsp(Al5KUlItu(V^CW(U2bPLp@d?k~WwO=B?cA>zOZ zvXL|so&`^W4YF3gNB~Jo7Osn}JT?+79o2?(w4vh+`A7_Jdqoq~X0%bR3xhMk_Iwk$ zp6al!!vo(?YHN?}FQ=}BP}3Waamctd_Ct2P9=Z3Q8v01s_&b9aKMo!RR@u;EN>OEv zw!=RczRH-k$b?#8?u=2!wCl++ZgLu^e$v$9jyRSNF@8$9ggTlL9n4OGG6JA~{Xl(Y zB21EQ$)CGX<)(qdo8hKm49{31nWPd&IK!nvyR6G`pJ3Q}su%X6uEwpxd!nbis%v_* GNB$2!=DQC7 literal 0 HcmV?d00001 diff --git a/release/v13/docs/ACL.md b/release/v13/docs/ACL.md new file mode 100644 index 00000000..acad22c6 --- /dev/null +++ b/release/v13/docs/ACL.md @@ -0,0 +1,205 @@ + + + +# Module `0x1::ACL` + +Access control list (acl) module. An acl is a list of account addresses who +have the access permission to a certain object. +This module uses a vector to represent the list, but can be refactored to +use a "set" instead when it's available in the language in the future. + + +- [Struct `ACL`](#0x1_ACL_ACL) +- [Constants](#@Constants_0) +- [Function `empty`](#0x1_ACL_empty) +- [Function `add`](#0x1_ACL_add) +- [Function `remove`](#0x1_ACL_remove) +- [Function `contains`](#0x1_ACL_contains) +- [Function `assert_contains`](#0x1_ACL_assert_contains) + + +

use 0x1::Errors;
+use 0x1::Vector;
+
+ + + + + +## Struct `ACL` + + + +
struct ACL has copy, drop, store
+
+ + + +
+Fields + + +
+
+list: vector<address> +
+
+ +
+
+ + +
+ + + +## Constants + + + + +The ACL already contains the address. + + +
const ECONTAIN: u64 = 0;
+
+ + + + + +The ACL does not contain the address. + + +
const ENOT_CONTAIN: u64 = 1;
+
+ + + + + +## Function `empty` + +Return an empty ACL. + + +
public fun empty(): ACL::ACL
+
+ + + +
+Implementation + + +
public fun empty(): ACL {
+    ACL{ list: Vector::empty<address>() }
+}
+
+ + + +
+ + + +## Function `add` + +Add the address to the ACL. + + +
public fun add(acl: &mut ACL::ACL, addr: address)
+
+ + + +
+Implementation + + +
public fun add(acl: &mut ACL, addr: address) {
+    assert!(!Vector::contains(&mut acl.list, &addr), Errors::invalid_argument(ECONTAIN));
+    Vector::push_back(&mut acl.list, addr);
+}
+
+ + + +
+ + + +## Function `remove` + +Remove the address from the ACL. + + +
public fun remove(acl: &mut ACL::ACL, addr: address)
+
+ + + +
+Implementation + + +
public fun remove(acl: &mut ACL, addr: address) {
+    let (found, index) = Vector::index_of(&mut acl.list, &addr);
+    assert!(found, Errors::invalid_argument(ENOT_CONTAIN));
+    Vector::remove(&mut acl.list, index);
+}
+
+ + + +
+ + + +## Function `contains` + +Return true iff the ACL contains the address. + + +
public fun contains(acl: &ACL::ACL, addr: address): bool
+
+ + + +
+Implementation + + +
public fun contains(acl: &ACL, addr: address): bool {
+    Vector::contains(&acl.list, &addr)
+}
+
+ + + +
+ + + +## Function `assert_contains` + +assert! that the ACL has the address. + + +
public fun assert_contains(acl: &ACL::ACL, addr: address)
+
+ + + +
+Implementation + + +
public fun assert_contains(acl: &ACL, addr: address) {
+    assert!(contains(acl, addr), Errors::invalid_argument(ENOT_CONTAIN));
+}
+
+ + + +
diff --git a/release/v13/docs/Account.md b/release/v13/docs/Account.md new file mode 100644 index 00000000..cd98d41a --- /dev/null +++ b/release/v13/docs/Account.md @@ -0,0 +1,3676 @@ + + + +# Module `0x1::Account` + +The module for the account resource that governs every account + + +- [Resource `Account`](#0x1_Account_Account) +- [Resource `Balance`](#0x1_Account_Balance) +- [Struct `WithdrawCapability`](#0x1_Account_WithdrawCapability) +- [Struct `KeyRotationCapability`](#0x1_Account_KeyRotationCapability) +- [Struct `WithdrawEvent`](#0x1_Account_WithdrawEvent) +- [Struct `DepositEvent`](#0x1_Account_DepositEvent) +- [Struct `AcceptTokenEvent`](#0x1_Account_AcceptTokenEvent) +- [Resource `SignerDelegated`](#0x1_Account_SignerDelegated) +- [Struct `SignerCapability`](#0x1_Account_SignerCapability) +- [Resource `AutoAcceptToken`](#0x1_Account_AutoAcceptToken) +- [Struct `RotateAuthKeyEvent`](#0x1_Account_RotateAuthKeyEvent) +- [Struct `ExtractWithdrawCapEvent`](#0x1_Account_ExtractWithdrawCapEvent) +- [Struct `SignerDelegateEvent`](#0x1_Account_SignerDelegateEvent) +- [Resource `EventStore`](#0x1_Account_EventStore) +- [Constants](#@Constants_0) +- [Function `remove_signer_capability`](#0x1_Account_remove_signer_capability) +- [Function `create_signer_with_cap`](#0x1_Account_create_signer_with_cap) +- [Function `destroy_signer_cap`](#0x1_Account_destroy_signer_cap) +- [Function `signer_address`](#0x1_Account_signer_address) +- [Function `is_signer_delegated`](#0x1_Account_is_signer_delegated) +- [Function `create_genesis_account`](#0x1_Account_create_genesis_account) +- [Function `release_genesis_signer`](#0x1_Account_release_genesis_signer) +- [Function `create_account`](#0x1_Account_create_account) +- [Function `create_account_with_address`](#0x1_Account_create_account_with_address) +- [Function `make_account`](#0x1_Account_make_account) +- [Function `create_signer`](#0x1_Account_create_signer) +- [Function `create_account_with_initial_amount`](#0x1_Account_create_account_with_initial_amount) +- [Function `create_account_with_initial_amount_v2`](#0x1_Account_create_account_with_initial_amount_v2) +- [Function `create_account_with_initial_amount_entry`](#0x1_Account_create_account_with_initial_amount_entry) +- [Function `create_delegate_account`](#0x1_Account_create_delegate_account) +- [Function `deposit_to_self`](#0x1_Account_deposit_to_self) +- [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) +- [Function `withdraw_with_capability`](#0x1_Account_withdraw_with_capability) +- [Function `withdraw_with_capability_and_metadata`](#0x1_Account_withdraw_with_capability_and_metadata) +- [Function `extract_withdraw_capability`](#0x1_Account_extract_withdraw_capability) +- [Function `restore_withdraw_capability`](#0x1_Account_restore_withdraw_capability) +- [Function `emit_account_withdraw_event`](#0x1_Account_emit_account_withdraw_event) +- [Function `emit_account_deposit_event`](#0x1_Account_emit_account_deposit_event) +- [Function `pay_from_capability`](#0x1_Account_pay_from_capability) +- [Function `pay_from_with_metadata`](#0x1_Account_pay_from_with_metadata) +- [Function `pay_from`](#0x1_Account_pay_from) +- [Function `rotate_authentication_key_with_capability`](#0x1_Account_rotate_authentication_key_with_capability) +- [Function `extract_key_rotation_capability`](#0x1_Account_extract_key_rotation_capability) +- [Function `restore_key_rotation_capability`](#0x1_Account_restore_key_rotation_capability) +- [Function `destroy_key_rotation_capability`](#0x1_Account_destroy_key_rotation_capability) +- [Function `rotate_authentication_key`](#0x1_Account_rotate_authentication_key) +- [Function `rotate_authentication_key_entry`](#0x1_Account_rotate_authentication_key_entry) +- [Function `do_rotate_authentication_key`](#0x1_Account_do_rotate_authentication_key) +- [Function `balance_for`](#0x1_Account_balance_for) +- [Function `balance`](#0x1_Account_balance) +- [Function `do_accept_token`](#0x1_Account_do_accept_token) +- [Function `accept_token`](#0x1_Account_accept_token) +- [Function `accept_token_entry`](#0x1_Account_accept_token_entry) +- [Function `is_accepts_token`](#0x1_Account_is_accepts_token) +- [Function `is_accept_token`](#0x1_Account_is_accept_token) +- [Function `can_auto_accept_token`](#0x1_Account_can_auto_accept_token) +- [Function `set_auto_accept_token_entry`](#0x1_Account_set_auto_accept_token_entry) +- [Function `set_auto_accept_token`](#0x1_Account_set_auto_accept_token) +- [Function `try_accept_token`](#0x1_Account_try_accept_token) +- [Function `sequence_number_for_account`](#0x1_Account_sequence_number_for_account) +- [Function `sequence_number`](#0x1_Account_sequence_number) +- [Function `authentication_key`](#0x1_Account_authentication_key) +- [Function `delegated_key_rotation_capability`](#0x1_Account_delegated_key_rotation_capability) +- [Function `delegated_withdraw_capability`](#0x1_Account_delegated_withdraw_capability) +- [Function `withdraw_capability_address`](#0x1_Account_withdraw_capability_address) +- [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) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Authenticator;
+use 0x1::BCS;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Hash;
+use 0x1::Math;
+use 0x1::Option;
+use 0x1::STC;
+use 0x1::Signer;
+use 0x1::Timestamp;
+use 0x1::Token;
+use 0x1::TransactionFee;
+use 0x1::Vector;
+
+ + + + + +## Resource `Account` + +Every account has a Account::Account resource + + +
struct Account has key
+
+ + + +
+Fields + + +
+
+authentication_key: vector<u8> +
+
+ The current authentication key. + This can be different than the key used to create the account +
+
+withdrawal_capability: Option::Option<Account::WithdrawCapability> +
+
+ A withdrawal_capability allows whoever holds this capability + to withdraw from the account. At the time of account creation + this capability is stored in this option. It can later be + "extracted" from this field via extract_withdraw_capability, + and can also be restored via restore_withdraw_capability. +
+
+key_rotation_capability: Option::Option<Account::KeyRotationCapability> +
+
+ A key_rotation_capability allows whoever holds this capability + the ability to rotate the authentication key for the account. At + the time of account creation this capability is stored in this + option. It can later be "extracted" from this field via + extract_key_rotation_capability, and can also be restored via + restore_key_rotation_capability. +
+
+withdraw_events: Event::EventHandle<Account::WithdrawEvent> +
+
+ event handle for account balance withdraw event +
+
+deposit_events: Event::EventHandle<Account::DepositEvent> +
+
+ event handle for account balance deposit event +
+
+accept_token_events: Event::EventHandle<Account::AcceptTokenEvent> +
+
+ Event handle for accept_token event +
+
+sequence_number: u64 +
+
+ The current sequence number. + Incremented by one each time a transaction is submitted +
+
+ + +
+ + + +## Resource `Balance` + +A resource that holds the tokens stored in this account + + +
struct Balance<TokenType> has key
+
+ + + +
+Fields + + +
+
+token: Token::Token<TokenType> +
+
+ +
+
+ + +
+ + + +## Struct `WithdrawCapability` + +The holder of WithdrawCapability for account_address can withdraw Token from +account_address/Account::Account/balance. +There is at most one WithdrawCapability in existence for a given address. + + +
struct WithdrawCapability has store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+ + +
+ + + +## Struct `KeyRotationCapability` + +The holder of KeyRotationCapability for account_address can rotate the authentication key for +account_address (i.e., write to account_address/Account::Account/authentication_key). +There is at most one KeyRotationCapability in existence for a given address. + + +
struct KeyRotationCapability has store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+ + +
+ + + +## Struct `WithdrawEvent` + +Message for balance withdraw event. + + +
struct WithdrawEvent has drop, store
+
+ + + +
+Fields + + +
+
+amount: u128 +
+
+ The amount of Token sent +
+
+token_code: Token::TokenCode +
+
+ The code symbol for the token that was sent +
+
+metadata: vector<u8> +
+
+ Metadata associated with the withdraw +
+
+ + +
+ + + +## Struct `DepositEvent` + +Message for balance deposit event. + + +
struct DepositEvent has drop, store
+
+ + + +
+Fields + + +
+
+amount: u128 +
+
+ The amount of Token sent +
+
+token_code: Token::TokenCode +
+
+ The code symbol for the token that was sent +
+
+metadata: vector<u8> +
+
+ Metadata associated with the deposit +
+
+ + +
+ + + +## Struct `AcceptTokenEvent` + +Message for accept token events + + +
struct AcceptTokenEvent has drop, store
+
+ + + +
+Fields + + +
+
+token_code: Token::TokenCode +
+
+ +
+
+ + +
+ + + +## Resource `SignerDelegated` + + + +
struct SignerDelegated has key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Struct `SignerCapability` + + + +
struct SignerCapability has store
+
+ + + +
+Fields + + +
+
+addr: address +
+
+ +
+
+ + +
+ + + +## Resource `AutoAcceptToken` + + + +
struct AutoAcceptToken has key
+
+ + + +
+Fields + + +
+
+enable: bool +
+
+ +
+
+ + +
+ + + +## Struct `RotateAuthKeyEvent` + +Message for rotate_authentication_key events + + +
struct RotateAuthKeyEvent has drop, store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+new_auth_key: vector<u8> +
+
+ +
+
+ + +
+ + + +## Struct `ExtractWithdrawCapEvent` + +Message for extract_withdraw_capability events + + +
struct ExtractWithdrawCapEvent has drop, store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+ + +
+ + + +## Struct `SignerDelegateEvent` + +Message for SignerDelegate events + + +
struct SignerDelegateEvent has drop, store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+ + +
+ + + +## Resource `EventStore` + + + +
struct EventStore has key
+
+ + + +
+Fields + + +
+
+rotate_auth_key_events: Event::EventHandle<Account::RotateAuthKeyEvent> +
+
+ Event handle for rotate_authentication_key event +
+
+extract_withdraw_cap_events: Event::EventHandle<Account::ExtractWithdrawCapEvent> +
+
+ Event handle for extract_withdraw_capability event +
+
+signer_delegate_events: Event::EventHandle<Account::SignerDelegateEvent> +
+
+ Event handle for signer delegated event +
+
+ + +
+ + + +## Constants + + + + + + +
const MAX_U64: u128 = 18446744073709551615;
+
+ + + + + + + +
const EDEPRECATED_FUNCTION: u64 = 19;
+
+ + + + + + + +
const EPROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0;
+
+ + + + + +The address bytes length + + +
const ADDRESS_LENGTH: u64 = 16;
+
+ + + + + + + +
const CONTRACT_ACCOUNT_AUTH_KEY_PLACEHOLDER: vector<u8> = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
+
+ + + + + + + +
const DUMMY_AUTH_KEY: vector<u8> = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+
+ + + + + + + +
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;
+
+ + + + + +## Function `remove_signer_capability` + +A one-way action, once SignerCapability is removed from signer, the address cannot send txns anymore. +This function can only called once by signer. + + +
public fun remove_signer_capability(signer: &signer): Account::SignerCapability
+
+ + + +
+Implementation + + +
public fun remove_signer_capability(signer: &signer): SignerCapability
+acquires Account, EventStore {
+    let signer_addr = Signer::address_of(signer);
+    assert!(!is_signer_delegated(signer_addr), Errors::invalid_state(ERR_SIGNER_ALREADY_DELEGATED));
+
+    // set to account auth key to noop.
+    {
+        let key_rotation_capability = extract_key_rotation_capability(signer);
+        rotate_authentication_key_with_capability(&key_rotation_capability, CONTRACT_ACCOUNT_AUTH_KEY_PLACEHOLDER);
+        destroy_key_rotation_capability(key_rotation_capability);
+        move_to(signer, SignerDelegated {});
+
+        make_event_store_if_not_exist(signer);
+        let event_store = borrow_global_mut<EventStore>(signer_addr);
+        Event::emit_event<SignerDelegateEvent>(
+            &mut event_store.signer_delegate_events,
+            SignerDelegateEvent {
+                account_address: signer_addr
+            }
+        );
+    };
+
+    let signer_cap = SignerCapability {addr: signer_addr };
+    signer_cap
+}
+
+ + + +
+ + + +## Function `create_signer_with_cap` + + + +
public fun create_signer_with_cap(cap: &Account::SignerCapability): signer
+
+ + + +
+Implementation + + +
public fun create_signer_with_cap(cap: &SignerCapability): signer {
+    create_signer(cap.addr)
+}
+
+ + + +
+ + + +## Function `destroy_signer_cap` + + + +
public fun destroy_signer_cap(cap: Account::SignerCapability)
+
+ + + +
+Implementation + + +
public fun destroy_signer_cap(cap: SignerCapability) {
+    let SignerCapability {addr: _} = cap;
+}
+
+ + + +
+ + + +## Function `signer_address` + + + +
public fun signer_address(cap: &Account::SignerCapability): address
+
+ + + +
+Implementation + + +
public fun signer_address(cap: &SignerCapability): address {
+    cap.addr
+}
+
+ + + +
+ + + +## Function `is_signer_delegated` + + + +
public fun is_signer_delegated(addr: address): bool
+
+ + + +
+Implementation + + +
public fun is_signer_delegated(addr: address): bool {
+    exists<SignerDelegated>(addr)
+}
+
+ + + +
+ + + +## Function `create_genesis_account` + +Create an genesis account at new_account_address and return signer. +Genesis authentication_key is zero bytes. + + +
public fun create_genesis_account(new_account_address: address): signer
+
+ + + +
+Implementation + + +
public fun create_genesis_account(
+    new_account_address: address,
+) :signer {
+    Timestamp::assert_genesis();
+    let new_account = create_signer(new_account_address);
+    make_account(&new_account, DUMMY_AUTH_KEY);
+    new_account
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if len(DUMMY_AUTH_KEY) != 32;
+aborts_if exists<Account>(new_account_address);
+
+ + + +
+ + + +## Function `release_genesis_signer` + +Release genesis account signer + + +
public fun release_genesis_signer(_genesis_account: signer)
+
+ + + +
+Implementation + + +
public fun release_genesis_signer(_genesis_account: signer){
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `create_account` + +Deprecated since @v5 + + +
public fun create_account<TokenType: store>(_authentication_key: vector<u8>): address
+
+ + + +
+Implementation + + +
public fun create_account<TokenType: store>(_authentication_key: vector<u8>): address {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if true;
+
+ + + +
+ + + +## Function `create_account_with_address` + +Creates a new account at fresh_address with a balance of zero and empty auth key, the address as init auth key for check transaction. +Creating an account at address StarcoinFramework will cause runtime failure as it is a +reserved address for the MoveVM. + + +
public fun create_account_with_address<TokenType: store>(fresh_address: address)
+
+ + + +
+Implementation + + +
public fun create_account_with_address<TokenType: store>(fresh_address: address) acquires Account {
+    let new_account = create_signer(fresh_address);
+    make_account(&new_account, DUMMY_AUTH_KEY);
+    // Make sure all account accept STC.
+    if (!STC::is_stc<TokenType>()){
+        do_accept_token<STC>(&new_account);
+    };
+    do_accept_token<TokenType>(&new_account);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if exists<Account>(fresh_address);
+aborts_if Token::spec_token_code<TokenType>() != Token::spec_token_code<STC>() && exists<Balance<STC>>(fresh_address);
+aborts_if exists<Balance<TokenType>>(fresh_address);
+ensures exists_at(fresh_address);
+ensures exists<Balance<TokenType>>(fresh_address);
+
+ + + +
+ + + +## Function `make_account` + + + +
fun make_account(new_account: &signer, authentication_key: vector<u8>)
+
+ + + +
+Implementation + + +
fun make_account(
+    new_account: &signer,
+    authentication_key: vector<u8>,
+) {
+    assert!(Vector::length(&authentication_key) == 32, Errors::invalid_argument(EMALFORMED_AUTHENTICATION_KEY));
+    let new_account_addr = Signer::address_of(new_account);
+    Event::publish_generator(new_account);
+    move_to(new_account, Account {
+          authentication_key,
+          withdrawal_capability: Option::some(
+              WithdrawCapability {
+                  account_address: new_account_addr
+          }),
+          key_rotation_capability: Option::some(
+              KeyRotationCapability {
+                  account_address: new_account_addr
+          }),
+          withdraw_events: Event::new_event_handle<WithdrawEvent>(new_account),
+          deposit_events: Event::new_event_handle<DepositEvent>(new_account),
+          accept_token_events: Event::new_event_handle<AcceptTokenEvent>(new_account),
+          sequence_number: 0,
+    });
+    move_to(new_account, AutoAcceptToken{enable: true});
+    move_to(new_account, EventStore {
+          rotate_auth_key_events: Event::new_event_handle<RotateAuthKeyEvent>(new_account),
+          extract_withdraw_cap_events: Event::new_event_handle<ExtractWithdrawCapEvent>(new_account),
+          signer_delegate_events: Event::new_event_handle<SignerDelegateEvent>(new_account),
+    });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if len(authentication_key) != 32;
+aborts_if exists<Account>(Signer::address_of(new_account));
+aborts_if exists<AutoAcceptToken>(Signer::address_of(new_account));
+ensures exists_at(Signer::address_of(new_account));
+
+ + + +
+ + + +## Function `create_signer` + + + +
fun create_signer(addr: address): signer
+
+ + + +
+Implementation + + +
native fun create_signer(addr: address): signer;
+
+ + + +
+ + + +## Function `create_account_with_initial_amount` + + + +
public entry fun create_account_with_initial_amount<TokenType: store>(account: signer, fresh_address: address, _auth_key: vector<u8>, initial_amount: u128)
+
+ + + +
+Implementation + + +
public entry fun create_account_with_initial_amount<TokenType: store>(account: signer, fresh_address: address, _auth_key: vector<u8>, initial_amount: u128)
+acquires Account, Balance, AutoAcceptToken {
+    create_account_with_initial_amount_entry<TokenType>(account, fresh_address, initial_amount);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `create_account_with_initial_amount_v2` + + + +
public entry fun create_account_with_initial_amount_v2<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
+
+ + + +
+Implementation + + +
public entry fun create_account_with_initial_amount_v2<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
+acquires Account, Balance, AutoAcceptToken {
+    create_account_with_initial_amount_entry<TokenType>(account, fresh_address, initial_amount);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `create_account_with_initial_amount_entry` + + + +
public entry fun create_account_with_initial_amount_entry<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
+
+ + + +
+Implementation + + +
public entry fun create_account_with_initial_amount_entry<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
+acquires Account, Balance, AutoAcceptToken {
+    create_account_with_address<TokenType>(fresh_address);
+    if (initial_amount > 0) {
+        pay_from<TokenType>(&account, fresh_address, initial_amount);
+    };
+}
+
+ + + +
+ + + +## Function `create_delegate_account` + +Generate an new address and create a new account, then delegate the account and return the new account address and SignerCapability + + +
public fun create_delegate_account(sender: &signer): (address, Account::SignerCapability)
+
+ + + +
+Implementation + + +
public fun create_delegate_account(sender: &signer) : (address, SignerCapability) acquires Balance, Account, EventStore {
+    let sender_address = Signer::address_of(sender);
+    let sequence_number = Self::sequence_number(sender_address);
+    // use stc balance as part of seed, just for new address more random.
+    let stc_balance = Self::balance<STC>(sender_address);
+
+    let seed_bytes = BCS::to_bytes(&sender_address);
+    Vector::append(&mut seed_bytes, BCS::to_bytes(&sequence_number));
+    Vector::append(&mut seed_bytes, BCS::to_bytes(&stc_balance));
+
+    let seed_hash = Hash::sha3_256(seed_bytes);
+    let i = 0;
+    let address_bytes = Vector::empty();
+    while (i < ADDRESS_LENGTH) {
+        Vector::push_back(&mut address_bytes, *Vector::borrow(&seed_hash,i));
+        i = i + 1;
+    };
+    let new_address = BCS::to_address(address_bytes);
+    Self::create_account_with_address<STC>(new_address);
+    let new_signer = Self::create_signer(new_address);
+    (new_address, Self::remove_signer_capability(&new_signer))
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deposit_to_self` + +Deposits the to_deposit token into the self's account balance + + +
public fun deposit_to_self<TokenType: store>(account: &signer, to_deposit: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun deposit_to_self<TokenType: store>(account: &signer, to_deposit: Token<TokenType>)
+acquires Account, Balance, AutoAcceptToken {
+    let account_address = Signer::address_of(account);
+    if (!is_accepts_token<TokenType>(account_address)){
+        do_accept_token<TokenType>(account);
+    };
+    deposit(account_address, to_deposit);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if to_deposit.value == 0;
+let is_accepts_token = exists<Balance<TokenType>>(Signer::address_of(account));
+aborts_if is_accepts_token && global<Balance<TokenType>>(Signer::address_of(account)).token.value + to_deposit.value > max_u128();
+aborts_if !exists<Account>(Signer::address_of(account));
+ensures exists<Balance<TokenType>>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `deposit` + +Deposits the to_deposit token into the receiver's account balance with the no metadata +It's a reverse operation of withdraw. + + +
public fun deposit<TokenType: store>(receiver: address, to_deposit: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun deposit<TokenType: store>(
+    receiver: address,
+    to_deposit: Token<TokenType>,
+) acquires Account, Balance, AutoAcceptToken {
+    deposit_with_metadata<TokenType>(receiver, to_deposit, x"")
+}
+
+ + + +
+ +
+Specification + + + +
include DepositWithMetadataAbortsIf<TokenType>;
+
+ + + +
+ + + +## Function `deposit_with_metadata` + +Deposits the to_deposit token into the receiver's account balance with the attached metadata +It's a reverse operation of withdraw_with_metadata. + + +
public fun deposit_with_metadata<TokenType: store>(receiver: address, to_deposit: Token::Token<TokenType>, metadata: vector<u8>)
+
+ + + +
+Implementation + + +
public fun deposit_with_metadata<TokenType: store>(
+    receiver: address,
+    to_deposit: Token<TokenType>,
+    metadata: vector<u8>,
+) acquires Account, Balance, AutoAcceptToken {
+
+    if (!exists_at(receiver)) {
+        create_account_with_address<TokenType>(receiver);
+    };
+
+    try_accept_token<TokenType>(receiver);
+
+    let deposit_value = Token::value(&to_deposit);
+    if (deposit_value > 0u128) {
+        // Deposit the `to_deposit` token
+        deposit_to_balance<TokenType>(borrow_global_mut<Balance<TokenType>>(receiver), to_deposit);
+
+        // emit deposit event
+        emit_account_deposit_event<TokenType>(receiver, deposit_value, metadata);
+    } else {
+        Token::destroy_zero(to_deposit);
+    };
+}
+
+ + + +
+ +
+Specification + + + +
include DepositWithMetadataAbortsIf<TokenType>;
+ensures exists<Balance<TokenType>>(receiver);
+ensures old(global<Balance<TokenType>>(receiver)).token.value + to_deposit.value == global<Balance<TokenType>>(receiver).token.value;
+
+ + + + + + + +
schema DepositWithMetadataAbortsIf<TokenType> {
+    receiver: address;
+    to_deposit: Token<TokenType>;
+    aborts_if to_deposit.value == 0;
+    aborts_if !exists<Account>(receiver);
+    aborts_if !exists<Balance<TokenType>>(receiver);
+    aborts_if global<Balance<TokenType>>(receiver).token.value + to_deposit.value > max_u128();
+}
+
+ + + +
+ + + +## Function `deposit_to_balance` + +Helper to deposit amount to the given account balance + + +
fun deposit_to_balance<TokenType: store>(balance: &mut Account::Balance<TokenType>, token: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
fun deposit_to_balance<TokenType: store>(balance: &mut Balance<TokenType>, token: Token::Token<TokenType>) {
+    Token::deposit(&mut balance.token, token)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if balance.token.value + token.value > MAX_U128;
+
+ + + +
+ + + +## Function `withdraw_from_balance_v2` + + + +
public(friend) fun withdraw_from_balance_v2<TokenType: store>(sender: address, amount: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public(friend) fun withdraw_from_balance_v2<TokenType: store>(sender:address, amount: u128): Token<TokenType> acquires Balance {
+    let balance = borrow_global_mut<Balance<TokenType>>(sender);
+    Token::withdraw(&mut balance.token, amount)
+}
+
+ + + +
+ + + +## Function `set_sequence_number` + + + +
public(friend) fun set_sequence_number(sender: address, sequence_number: u64)
+
+ + + +
+Implementation + + +
public (friend) fun set_sequence_number(sender: address, sequence_number: u64) acquires Account {
+    let account = borrow_global_mut<Account>(sender);
+    account.sequence_number = sequence_number;
+}
+
+ + + +
+ + + +## Function `set_authentication_key` + + + +
public(friend) fun set_authentication_key(sender: address, auth_key: vector<u8>)
+
+ + + +
+Implementation + + +
public (friend) fun set_authentication_key(sender:address,auth_key:vector<u8>) acquires Account{
+    let account = borrow_global_mut<Account>(sender);
+    account.authentication_key = auth_key;
+}
+
+ + + +
+ + + +## Function `withdraw_from_balance` + +Helper to withdraw amount from the given account balance and return the withdrawn Token + + +
public fun withdraw_from_balance<TokenType: store>(balance: &mut Account::Balance<TokenType>, amount: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun withdraw_from_balance<TokenType: store>(balance: &mut Balance<TokenType>, amount: u128): Token<TokenType>{
+    Token::withdraw(&mut balance.token, amount)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if balance.token.value < amount;
+
+ + + +
+ + + +## Function `withdraw` + +Withdraw amount Token from the account balance + + +
public fun withdraw<TokenType: store>(account: &signer, amount: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun withdraw<TokenType: store>(account: &signer, amount: u128): Token<TokenType>
+acquires Account, Balance {
+    withdraw_with_metadata<TokenType>(account, amount, x"")
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
+aborts_if !exists<Account>(Signer::address_of(account));
+aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
+aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
+
+ + + +
+ + + +## Function `withdraw_with_metadata` + +Withdraw amount tokens from signer with given metadata. + + +
public fun withdraw_with_metadata<TokenType: store>(account: &signer, amount: u128, metadata: vector<u8>): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun withdraw_with_metadata<TokenType: store>(account: &signer, amount: u128, metadata: vector<u8>): Token<TokenType>
+acquires Account, Balance {
+    let sender_addr = Signer::address_of(account);
+    let sender_balance = borrow_global_mut<Balance<TokenType>>(sender_addr);
+    // The sender_addr has delegated the privilege to withdraw from her account elsewhere--abort.
+    assert!(!delegated_withdraw_capability(sender_addr), Errors::invalid_state(EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED));
+    if (amount == 0){
+        return Token::zero()
+    };
+    emit_account_withdraw_event<TokenType>(sender_addr, amount, metadata);
+    // The sender_addr has retained her withdrawal privileges--proceed.
+    withdraw_from_balance<TokenType>(sender_balance, amount)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
+aborts_if !exists<Account>(Signer::address_of(account));
+aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
+aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
+
+ + + + + + + +
fun spec_withdraw<TokenType>(account: signer, amount: u128): Token<TokenType> {
+   Token<TokenType> { value: amount }
+}
+
+ + + +
+ + + +## Function `withdraw_with_capability` + +Withdraw amount Token from the account under cap.account_address with no metadata + + +
public fun withdraw_with_capability<TokenType: store>(cap: &Account::WithdrawCapability, amount: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun withdraw_with_capability<TokenType: store>(
+    cap: &WithdrawCapability, amount: u128
+): Token<TokenType> acquires Balance, Account {
+    withdraw_with_capability_and_metadata<TokenType>(cap, amount, x"")
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Balance<TokenType>>(cap.account_address);
+aborts_if !exists<Account>(cap.account_address);
+aborts_if global<Balance<TokenType>>(cap.account_address).token.value < amount;
+
+ + + +
+ + + +## Function `withdraw_with_capability_and_metadata` + +Withdraw amount Token from the account under cap.account_address with metadata + + +
public fun withdraw_with_capability_and_metadata<TokenType: store>(cap: &Account::WithdrawCapability, amount: u128, metadata: vector<u8>): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun withdraw_with_capability_and_metadata<TokenType: store>(
+    cap: &WithdrawCapability, amount: u128, metadata: vector<u8>
+): Token<TokenType> acquires Balance, Account {
+    let balance = borrow_global_mut<Balance<TokenType>>(cap.account_address);
+    emit_account_withdraw_event<TokenType>(cap.account_address, amount, metadata);
+    withdraw_from_balance<TokenType>(balance , amount)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Balance<TokenType>>(cap.account_address);
+aborts_if !exists<Account>(cap.account_address);
+aborts_if global<Balance<TokenType>>(cap.account_address).token.value < amount;
+
+ + + +
+ + + +## Function `extract_withdraw_capability` + +Return a unique capability granting permission to withdraw from the sender's account balance. + + +
public fun extract_withdraw_capability(sender: &signer): Account::WithdrawCapability
+
+ + + +
+Implementation + + +
public fun extract_withdraw_capability(
+    sender: &signer
+): WithdrawCapability acquires Account, EventStore {
+    let sender_addr = Signer::address_of(sender);
+    // Abort if we already extracted the unique withdraw capability for this account.
+    assert!(!delegated_withdraw_capability(sender_addr), Errors::invalid_state(EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED));
+
+    make_event_store_if_not_exist(sender);
+    let event_store = borrow_global_mut<EventStore>(sender_addr);
+    Event::emit_event<ExtractWithdrawCapEvent>(
+        &mut event_store.extract_withdraw_cap_events,
+        ExtractWithdrawCapEvent {
+            account_address: sender_addr,
+        }
+    );
+    let account = borrow_global_mut<Account>(sender_addr);
+    Option::extract(&mut account.withdrawal_capability)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(Signer::address_of(sender));
+aborts_if Option::is_none(global<Account>( Signer::address_of(sender)).withdrawal_capability);
+
+ + + +
+ + + +## Function `restore_withdraw_capability` + +Return the withdraw capability to the account it originally came from + + +
public fun restore_withdraw_capability(cap: Account::WithdrawCapability)
+
+ + + +
+Implementation + + +
public fun restore_withdraw_capability(cap: WithdrawCapability)
+   acquires Account {
+       let account = borrow_global_mut<Account>(cap.account_address);
+       Option::fill(&mut account.withdrawal_capability, cap)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Option::is_some(global<Account>(cap.account_address).withdrawal_capability);
+aborts_if !exists<Account>(cap.account_address);
+
+ + + +
+ + + +## Function `emit_account_withdraw_event` + + + +
fun emit_account_withdraw_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
+
+ + + +
+Implementation + + +
fun emit_account_withdraw_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
+acquires Account {
+    // emit withdraw event
+    let account = borrow_global_mut<Account>(account);
+
+    Event::emit_event<WithdrawEvent>(&mut account.withdraw_events, WithdrawEvent {
+        amount,
+        token_code: Token::token_code<TokenType>(),
+        metadata,
+    });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(account);
+
+ + + +
+ + + +## Function `emit_account_deposit_event` + + + +
fun emit_account_deposit_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
+
+ + + +
+Implementation + + +
fun emit_account_deposit_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
+acquires Account {
+    // emit withdraw event
+    let account = borrow_global_mut<Account>(account);
+
+    Event::emit_event<DepositEvent>(&mut account.deposit_events, DepositEvent {
+        amount,
+        token_code: Token::token_code<TokenType>(),
+        metadata,
+    });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(account);
+
+ + + +
+ + + +## Function `pay_from_capability` + +Withdraws amount Token using the passed in WithdrawCapability, and deposits it +into the payee's account balance. Creates the payee account if it doesn't exist. + + +
public fun pay_from_capability<TokenType: store>(cap: &Account::WithdrawCapability, payee: address, amount: u128, metadata: vector<u8>)
+
+ + + +
+Implementation + + +
public fun pay_from_capability<TokenType: store>(
+    cap: &WithdrawCapability,
+    payee: address,
+    amount: u128,
+    metadata: vector<u8>,
+) acquires Account, Balance, AutoAcceptToken {
+    let tokens = withdraw_with_capability_and_metadata<TokenType>(cap, amount, *&metadata);
+    deposit_with_metadata<TokenType>(
+        payee,
+        tokens,
+        metadata,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Balance<TokenType>>(cap.account_address);
+aborts_if !exists<Account>(cap.account_address);
+aborts_if global<Balance<TokenType>>(cap.account_address).token.value < amount;
+aborts_if amount == 0;
+aborts_if !exists<Account>(payee);
+aborts_if !exists<Balance<TokenType>>(payee);
+aborts_if cap.account_address != payee && global<Balance<TokenType>>(payee).token.value + amount > MAX_U128;
+
+ + + +
+ + + +## Function `pay_from_with_metadata` + +Withdraw amount Token from the transaction sender's +account balance and send the token to the payee address with the +attached metadata Creates the payee account if it does not exist + + +
public fun pay_from_with_metadata<TokenType: store>(account: &signer, payee: address, amount: u128, metadata: vector<u8>)
+
+ + + +
+Implementation + + +
public fun pay_from_with_metadata<TokenType: store>(
+    account: &signer,
+    payee: address,
+    amount: u128,
+    metadata: vector<u8>,
+) acquires Account, Balance, AutoAcceptToken {
+    let tokens = withdraw_with_metadata<TokenType>(account, amount, *&metadata);
+    deposit_with_metadata<TokenType>(
+        payee,
+        tokens,
+        metadata,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
+aborts_if !exists<Account>(Signer::address_of(account));
+aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
+aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
+aborts_if amount == 0;
+aborts_if !exists<Account>(payee);
+aborts_if !exists<Balance<TokenType>>(payee);
+aborts_if Signer::address_of(account) != payee && global<Balance<TokenType>>(payee).token.value + amount > max_u128();
+
+ + + + + + + +
schema DepositWithPayerAndMetadataAbortsIf<TokenType> {
+    payer: address;
+    payee: address;
+    to_deposit: Token<TokenType>;
+    aborts_if to_deposit.value == 0;
+    aborts_if !exists<Account>(payer);
+    aborts_if !exists<Account>(payee);
+    aborts_if !exists<Balance<TokenType>>(payee);
+    aborts_if global<Balance<TokenType>>(payee).token.value + to_deposit.value > max_u128();
+}
+
+ + + +
+ + + +## Function `pay_from` + +Withdraw amount Token from the transaction sender's +account balance and send the token to the payee address +Creates the payee account if it does not exist + + +
public fun pay_from<TokenType: store>(account: &signer, payee: address, amount: u128)
+
+ + + +
+Implementation + + +
public fun pay_from<TokenType: store>(
+    account: &signer,
+    payee: address,
+    amount: u128
+) acquires Account, Balance, AutoAcceptToken {
+    pay_from_with_metadata<TokenType>(account, payee, amount, x"");
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
+aborts_if !exists<Account>(Signer::address_of(account));
+aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
+aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
+aborts_if amount == 0;
+aborts_if !exists<Account>(payee);
+aborts_if !exists<Balance<TokenType>>(payee);
+aborts_if Signer::address_of(account) != payee && global<Balance<TokenType>>(payee).token.value + amount > max_u128();
+
+ + + +
+ + + +## Function `rotate_authentication_key_with_capability` + +Rotate the authentication key for the account under cap.account_address + + +
public fun rotate_authentication_key_with_capability(cap: &Account::KeyRotationCapability, new_authentication_key: vector<u8>)
+
+ + + +
+Implementation + + +
public fun rotate_authentication_key_with_capability(
+    cap: &KeyRotationCapability,
+    new_authentication_key: vector<u8>,
+) acquires Account  {
+    let sender_account_resource = borrow_global_mut<Account>(cap.account_address);
+    // Don't allow rotating to clearly invalid key
+    assert!(Vector::length(&new_authentication_key) == 32, Errors::invalid_argument(EMALFORMED_AUTHENTICATION_KEY));
+    sender_account_resource.authentication_key = new_authentication_key;
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(cap.account_address);
+aborts_if len(new_authentication_key) != 32;
+ensures global<Account>(cap.account_address).authentication_key == new_authentication_key;
+
+ + + + + + + +
fun spec_rotate_authentication_key_with_capability(addr: address, new_authentication_key: vector<u8>): bool {
+   global<Account>(addr).authentication_key == new_authentication_key
+}
+
+ + + +
+ + + +## Function `extract_key_rotation_capability` + +Return a unique capability granting permission to rotate the sender's authentication key + + +
public fun extract_key_rotation_capability(account: &signer): Account::KeyRotationCapability
+
+ + + +
+Implementation + + +
public fun extract_key_rotation_capability(account: &signer): KeyRotationCapability
+acquires Account {
+    let account_address = Signer::address_of(account);
+    // Abort if we already extracted the unique key rotation capability for this account.
+    assert!(!delegated_key_rotation_capability(account_address), Errors::invalid_state(EKEY_ROTATION_CAPABILITY_ALREADY_EXTRACTED));
+    let account = borrow_global_mut<Account>(account_address);
+    Option::extract(&mut account.key_rotation_capability)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(Signer::address_of(account));
+aborts_if Option::is_none(global<Account>(Signer::address_of(account)).key_rotation_capability);
+
+ + + +
+ + + +## Function `restore_key_rotation_capability` + +Return the key rotation capability to the account it originally came from + + +
public fun restore_key_rotation_capability(cap: Account::KeyRotationCapability)
+
+ + + +
+Implementation + + +
public fun restore_key_rotation_capability(cap: KeyRotationCapability)
+acquires Account {
+    let account = borrow_global_mut<Account>(cap.account_address);
+    Option::fill(&mut account.key_rotation_capability, cap)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Option::is_some(global<Account>(cap.account_address).key_rotation_capability);
+aborts_if !exists<Account>(cap.account_address);
+
+ + + +
+ + + +## Function `destroy_key_rotation_capability` + + + +
public fun destroy_key_rotation_capability(cap: Account::KeyRotationCapability)
+
+ + + +
+Implementation + + +
public fun destroy_key_rotation_capability(cap: KeyRotationCapability) {
+    let KeyRotationCapability {account_address: _} = cap;
+}
+
+ + + +
+ + + +## Function `rotate_authentication_key` + + + +
public entry fun rotate_authentication_key(account: signer, new_key: vector<u8>)
+
+ + + +
+Implementation + + +
public entry fun rotate_authentication_key(account: signer, new_key: vector<u8>) acquires Account, EventStore {
+    rotate_authentication_key_entry(account, new_key);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `rotate_authentication_key_entry` + + + +
public entry fun rotate_authentication_key_entry(account: signer, new_key: vector<u8>)
+
+ + + +
+Implementation + + +
public entry fun rotate_authentication_key_entry(account: signer, new_key: vector<u8>) acquires Account, EventStore {
+    do_rotate_authentication_key(&account, new_key);
+}
+
+ + + +
+ + + +## Function `do_rotate_authentication_key` + + + +
public fun do_rotate_authentication_key(account: &signer, new_key: vector<u8>)
+
+ + + +
+Implementation + + +
public fun do_rotate_authentication_key(account: &signer, new_key: vector<u8>) acquires Account, EventStore {
+    let key_rotation_capability = extract_key_rotation_capability(account);
+    rotate_authentication_key_with_capability(&key_rotation_capability, copy new_key);
+    restore_key_rotation_capability(key_rotation_capability);
+
+    make_event_store_if_not_exist(account);
+    let signer_addr = Signer::address_of(account);
+    let event_store = borrow_global_mut<EventStore>(signer_addr);
+    Event::emit_event<RotateAuthKeyEvent>(
+        &mut event_store.rotate_auth_key_events,
+        RotateAuthKeyEvent {
+            account_address: signer_addr,
+            new_auth_key: new_key,
+        }
+    );
+}
+
+ + + +
+ + + +## Function `balance_for` + +Helper to return the u128 value of the balance for account + + +
fun balance_for<TokenType: store>(balance: &Account::Balance<TokenType>): u128
+
+ + + +
+Implementation + + +
fun balance_for<TokenType: store>(balance: &Balance<TokenType>): u128 {
+    Token::value<TokenType>(&balance.token)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `balance` + +Return the current TokenType balance of the account at addr. + + +
public fun balance<TokenType: store>(addr: address): u128
+
+ + + +
+Implementation + + +
public fun balance<TokenType: store>(addr: address): u128 acquires Balance {
+    if (exists<Balance<TokenType>>(addr)) {
+        balance_for(borrow_global<Balance<TokenType>>(addr))
+    } else {
+        0u128
+    }
+}
+
+ + + +
+ + + +## Function `do_accept_token` + +Add a balance of Token type to the sending account. + + +
public fun do_accept_token<TokenType: store>(account: &signer)
+
+ + + +
+Implementation + + +
public fun do_accept_token<TokenType: store>(account: &signer) acquires Account {
+    move_to(account, Balance<TokenType>{ token: Token::zero<TokenType>() });
+    let token_code = Token::token_code<TokenType>();
+    // Load the sender's account
+    let sender_account_ref = borrow_global_mut<Account>(Signer::address_of(account));
+    // Log a sent event
+    Event::emit_event<AcceptTokenEvent>(
+        &mut sender_account_ref.accept_token_events,
+        AcceptTokenEvent {
+            token_code:  token_code,
+        },
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if exists<Balance<TokenType>>(Signer::address_of(account));
+aborts_if !exists<Account>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `accept_token` + + + +
public entry fun accept_token<TokenType: store>(account: signer)
+
+ + + +
+Implementation + + +
public entry fun accept_token<TokenType: store>(account: signer) acquires Account {
+    accept_token_entry<TokenType>(account);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `accept_token_entry` + + + +
public entry fun accept_token_entry<TokenType: store>(account: signer)
+
+ + + +
+Implementation + + +
public entry fun accept_token_entry<TokenType: store>(account: signer) acquires Account {
+    do_accept_token<TokenType>(&account);
+}
+
+ + + +
+ + + +## Function `is_accepts_token` + +This is a alias of is_accept_token + + +
public fun is_accepts_token<TokenType: store>(addr: address): bool
+
+ + + +
+Implementation + + +
public fun is_accepts_token<TokenType: store>(addr: address): bool acquires AutoAcceptToken {
+    Self::is_accept_token<TokenType>(addr)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `is_accept_token` + +Return whether the account at addr accept Token type tokens + + +
public fun is_accept_token<TokenType: store>(addr: address): bool
+
+ + + +
+Implementation + + +
public fun is_accept_token<TokenType: store>(addr: address): bool acquires AutoAcceptToken {
+    if (can_auto_accept_token(addr)) {
+        true
+    } else {
+        exists<Balance<TokenType>>(addr)
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `can_auto_accept_token` + +Check whether the address can auto accept token. + + +
public fun can_auto_accept_token(addr: address): bool
+
+ + + +
+Implementation + + +
public fun can_auto_accept_token(addr: address): bool acquires AutoAcceptToken {
+    if (exists<AutoAcceptToken>(addr)) {
+        borrow_global<AutoAcceptToken>(addr).enable
+    } else {
+        false
+    }
+}
+
+ + + +
+ + + +## Function `set_auto_accept_token_entry` + + + +
public entry fun set_auto_accept_token_entry(account: signer, enable: bool)
+
+ + + +
+Implementation + + +
public entry fun set_auto_accept_token_entry(account: signer, enable: bool) acquires AutoAcceptToken {
+    set_auto_accept_token(&account, enable);
+}
+
+ + + +
+ + + +## Function `set_auto_accept_token` + +Configure whether auto-accept tokens. + + +
public fun set_auto_accept_token(account: &signer, enable: bool)
+
+ + + +
+Implementation + + +
public fun set_auto_accept_token(account: &signer, enable: bool) acquires AutoAcceptToken {
+    let addr = Signer::address_of(account);
+    if (exists<AutoAcceptToken>(addr)) {
+        let config = borrow_global_mut<AutoAcceptToken>(addr);
+        config.enable = enable;
+    } else {
+        move_to(account, AutoAcceptToken{enable});
+    };
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `try_accept_token` + +try to accept token for addr. + + +
fun try_accept_token<TokenType: store>(addr: address)
+
+ + + +
+Implementation + + +
fun try_accept_token<TokenType: store>(addr: address) acquires AutoAcceptToken, Account {
+    if (!exists<Balance<TokenType>>(addr)) {
+        if (can_auto_accept_token(addr)) {
+            let signer = create_signer(addr);
+            do_accept_token<TokenType>(&signer);
+        }else{
+            abort Errors::not_published(ERR_TOKEN_NOT_ACCEPT)
+        }
+    };
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `sequence_number_for_account` + +Helper to return the sequence number field for given account + + +
fun sequence_number_for_account(account: &Account::Account): u64
+
+ + + +
+Implementation + + +
fun sequence_number_for_account(account: &Account): u64 {
+    account.sequence_number
+}
+
+ + + +
+ + + +## Function `sequence_number` + +Return the current sequence number at addr + + +
public fun sequence_number(addr: address): u64
+
+ + + +
+Implementation + + +
public fun sequence_number(addr: address): u64 acquires Account {
+    sequence_number_for_account(borrow_global<Account>(addr))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(addr);
+
+ + + +
+ + + +## Function `authentication_key` + +Return the authentication key for this account + + +
public fun authentication_key(addr: address): vector<u8>
+
+ + + +
+Implementation + + +
public fun authentication_key(addr: address): vector<u8> acquires Account {
+    *&borrow_global<Account>(addr).authentication_key
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(addr);
+
+ + + +
+ + + +## Function `delegated_key_rotation_capability` + +Return true if the account at addr has delegated its key rotation capability + + +
public fun delegated_key_rotation_capability(addr: address): bool
+
+ + + +
+Implementation + + +
public fun delegated_key_rotation_capability(addr: address): bool
+acquires Account {
+    Option::is_none(&borrow_global<Account>(addr).key_rotation_capability)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(addr);
+
+ + + +
+ + + +## Function `delegated_withdraw_capability` + +Return true if the account at addr has delegated its withdraw capability + + +
public fun delegated_withdraw_capability(addr: address): bool
+
+ + + +
+Implementation + + +
public fun delegated_withdraw_capability(addr: address): bool
+acquires Account {
+    Option::is_none(&borrow_global<Account>(addr).withdrawal_capability)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account>(addr);
+
+ + + +
+ + + +## Function `withdraw_capability_address` + +Return a reference to the address associated with the given withdraw capability + + +
public fun withdraw_capability_address(cap: &Account::WithdrawCapability): &address
+
+ + + +
+Implementation + + +
public fun withdraw_capability_address(cap: &WithdrawCapability): &address {
+    &cap.account_address
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `key_rotation_capability_address` + +Return a reference to the address associated with the given key rotation capability + + +
public fun key_rotation_capability_address(cap: &Account::KeyRotationCapability): &address
+
+ + + +
+Implementation + + +
public fun key_rotation_capability_address(cap: &KeyRotationCapability): &address {
+    &cap.account_address
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `exists_at` + +Checks if an account exists at check_addr + + +
public fun exists_at(check_addr: address): bool
+
+ + + +
+Implementation + + +
public fun exists_at(check_addr: address): bool {
+    exists<Account>(check_addr)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `is_dummy_auth_key` + + + +
fun is_dummy_auth_key(account: &Account::Account): bool
+
+ + + +
+Implementation + + +
fun is_dummy_auth_key(account: &Account): bool {
+    *&account.authentication_key == DUMMY_AUTH_KEY
+}
+
+ + + +
+ + + +## 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
+}
+
+ + + +
+ + + +## Function `txn_prologue` + +The prologue is invoked at the beginning of every transaction +It verifies: +- The account's auth key matches the transaction's public key +- That the account has enough balance to pay for all of the gas +- That the sequence number matches the transaction's sequence key + + +
public fun txn_prologue<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)
+
+ + + +
+Implementation + + +
public fun txn_prologue<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,
+) 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);
+
+    // 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 (is_dummy_auth_key(sender_account)){
+        // 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) == *&sender_account.authentication_key,
+            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 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));
+
+}
+
+ + + +
+ + + +## Function `txn_epilogue` + +The epilogue is invoked at the end of transactions. +It collects gas and bumps the sequence number + + +
public fun txn_epilogue<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64)
+
+ + + +
+Implementation + + +
public fun txn_epilogue<TokenType: store>(
+    account: &signer,
+    txn_sender: address,
+    txn_sequence_number: u64,
+    txn_gas_price: u64,
+    txn_max_gas_units: u64,
+    gas_units_remaining: u64,
+) acquires Account, Balance {
+    txn_epilogue_v3<TokenType>(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining,1,1)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## 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)
+}
+
+ + + +
+ + + +## Function `txn_epilogue_v2` + +The epilogue is invoked at the end of transactions. +It collects gas and bumps the sequence number + + +
public fun txn_epilogue_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, gas_units_remaining: u64)
+
+ + + +
+Implementation + + +
public fun txn_epilogue_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,
+    gas_units_remaining: u64,
+) acquires Account, Balance {
+    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)
+}
+
+ + + +
+ +
+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_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<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);
+aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
+          !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();
+
+ + + + +
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);
+    };
+}
+
+ + + +
+ + + +## Function `remove_zero_balance_entry` + + + +
public entry fun remove_zero_balance_entry<TokenType: store>(account: signer)
+
+ + + +
+Implementation + + +
public entry fun remove_zero_balance_entry<TokenType: store>(account: signer) acquires Balance {
+    remove_zero_balance<TokenType>(&account);
+}
+
+ + + +
+ + + +## Function `remove_zero_balance` + +Remove zero Balance + + +
public fun remove_zero_balance<TokenType: store>(account: &signer)
+
+ + + +
+Implementation + + +
public fun remove_zero_balance<TokenType: store>(account: &signer) acquires Balance {
+    let addr: address = Signer::address_of(account);
+    let Balance<TokenType> { token } = move_from<Balance<TokenType>>(addr);
+    Token::destroy_zero<TokenType>(token);
+}
+
+ + + +
+ +
+Specification + + + +
let addr = Signer::address_of(account);
+aborts_if !exists<Balance<TokenType>>(addr);
+ensures !exists<Balance<TokenType>>(addr);
+
+ + + +
+ + + +## Function `make_event_store_if_not_exist` + +Make a event store if it's not exist. + + +
fun make_event_store_if_not_exist(account: &signer)
+
+ + + +
+Implementation + + +
fun make_event_store_if_not_exist(account: &signer) {
+    if (!exists<EventStore>(Signer::address_of(account))) {
+        move_to(account, EventStore {
+          rotate_auth_key_events: Event::new_event_handle<RotateAuthKeyEvent>(account),
+          extract_withdraw_cap_events: Event::new_event_handle<ExtractWithdrawCapEvent>(account),
+          signer_delegate_events: Event::new_event_handle<SignerDelegateEvent>(account),
+        })
+    };
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/AccountScripts.md b/release/v13/docs/AccountScripts.md new file mode 100644 index 00000000..0b0181fa --- /dev/null +++ b/release/v13/docs/AccountScripts.md @@ -0,0 +1,93 @@ + + + +# Module `0x1::AccountScripts` + + + +- [Function `enable_auto_accept_token`](#0x1_AccountScripts_enable_auto_accept_token) +- [Function `disable_auto_accept_token`](#0x1_AccountScripts_disable_auto_accept_token) +- [Function `remove_zero_balance`](#0x1_AccountScripts_remove_zero_balance) + + +
use 0x1::Account;
+
+ + + + + +## Function `enable_auto_accept_token` + +Enable account's auto-accept-token feature. +The script function is reenterable. + + +
public entry fun enable_auto_accept_token(account: signer)
+
+ + + +
+Implementation + + +
public entry fun enable_auto_accept_token(account: signer) {
+    Account::set_auto_accept_token_entry(account, true);
+}
+
+ + + +
+ + + +## Function `disable_auto_accept_token` + +Disable account's auto-accept-token feature. +The script function is reenterable. + + +
public entry fun disable_auto_accept_token(account: signer)
+
+ + + +
+Implementation + + +
public entry fun disable_auto_accept_token(account: signer) {
+    Account::set_auto_accept_token_entry(account, false);
+}
+
+ + + +
+ + + +## Function `remove_zero_balance` + +Remove zero Balance + + +
public entry fun remove_zero_balance<TokenType: store>(account: signer)
+
+ + + +
+Implementation + + +
public entry fun remove_zero_balance<TokenType: store>(account: signer) {
+    Account::remove_zero_balance_entry<TokenType>(account);
+}
+
+ + + +
diff --git a/release/v13/docs/Authenticator.md b/release/v13/docs/Authenticator.md new file mode 100644 index 00000000..baad0a7d --- /dev/null +++ b/release/v13/docs/Authenticator.md @@ -0,0 +1,448 @@ + + + +# Module `0x1::Authenticator` + +Move representation of the authenticator types +- Ed25519 (single-sig) +- MultiEd25519 (K-of-N multisig) + + +- [Struct `MultiEd25519PublicKey`](#0x1_Authenticator_MultiEd25519PublicKey) +- [Constants](#@Constants_0) +- [Function `create_multi_ed25519`](#0x1_Authenticator_create_multi_ed25519) +- [Function `ed25519_authentication_key`](#0x1_Authenticator_ed25519_authentication_key) +- [Function `derived_address`](#0x1_Authenticator_derived_address) +- [Function `multi_ed25519_authentication_key`](#0x1_Authenticator_multi_ed25519_authentication_key) +- [Function `public_keys`](#0x1_Authenticator_public_keys) +- [Function `threshold`](#0x1_Authenticator_threshold) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::BCS;
+use 0x1::Errors;
+use 0x1::Hash;
+use 0x1::Vector;
+
+ + + + + +## Struct `MultiEd25519PublicKey` + +A multi-ed25519 public key + + +
struct MultiEd25519PublicKey has copy, drop, store
+
+ + + +
+Fields + + +
+
+public_keys: vector<vector<u8>> +
+
+ vector of ed25519 public keys +
+
+threshold: u8 +
+
+ approval threshold +
+
+ + +
+ + + +## Constants + + + + + + +
const AUTHENTICATION_KEY_LENGTH: u64 = 32;
+
+ + + + + + + +
const ED25519_SCHEME_ID: u8 = 0;
+
+ + + + + +Not enough keys were provided for the specified threshold when creating an MultiEd25519 key + + +
const ENOT_ENOUGH_KEYS_FOR_THRESHOLD: u64 = 103;
+
+ + + + + +Too many keys were provided for the specified threshold when creating an MultiEd25519 key + + +
const ENUM_KEYS_ABOVE_MAX_THRESHOLD: u64 = 104;
+
+ + + + + + + +
const EWRONG_AUTHENTICATION_KEY_LENGTH: u64 = 101;
+
+ + + + + +Threshold provided was 0 which can't be used to create a MultiEd25519 key + + +
const EZERO_THRESHOLD: u64 = 102;
+
+ + + + + +Maximum number of keys allowed in a MultiEd25519 public/private key + + +
const MAX_MULTI_ED25519_KEYS: u64 = 32;
+
+ + + + + + + +
const MULTI_ED25519_SCHEME_ID: u8 = 1;
+
+ + + + + +## Function `create_multi_ed25519` + +Create a a multisig policy from a vector of ed25519 public keys and a threshold. +Note: this does *not* check uniqueness of keys. Repeated keys are convenient to +encode weighted multisig policies. For example Alice AND 1 of Bob or Carol is +public_key: {alice_key, alice_key, bob_key, carol_key}, threshold: 3 +Aborts if threshold is zero or bigger than the length of public_keys. + + +
public fun create_multi_ed25519(public_keys: vector<vector<u8>>, threshold: u8): Authenticator::MultiEd25519PublicKey
+
+ + + +
+Implementation + + +
public fun create_multi_ed25519(
+    public_keys: vector<vector<u8>>,
+    threshold: u8
+): MultiEd25519PublicKey {
+    // check threshold requirements
+    let len = Vector::length(&public_keys);
+    assert!(threshold != 0, Errors::invalid_argument(EZERO_THRESHOLD));
+    assert!(
+        (threshold as u64) <= len,
+        Errors::invalid_argument(ENOT_ENOUGH_KEYS_FOR_THRESHOLD)
+    );
+    // the multied25519 signature scheme allows at most 32 keys
+    assert!(
+        len <= MAX_MULTI_ED25519_KEYS,
+        Errors::invalid_argument(ENUM_KEYS_ABOVE_MAX_THRESHOLD)
+    );
+
+    MultiEd25519PublicKey { public_keys, threshold }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if threshold == 0;
+aborts_if threshold > Vector::length(public_keys);
+aborts_if Vector::length(public_keys) > 32;
+
+ + + +
+ + + +## Function `ed25519_authentication_key` + +Compute an authentication key for the ed25519 public key public_key + + +
public fun ed25519_authentication_key(public_key: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun ed25519_authentication_key(public_key: vector<u8>): vector<u8> {
+    Vector::push_back(&mut public_key, ED25519_SCHEME_ID);
+    Hash::sha3_256(public_key)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures [abstract] result == spec_ed25519_authentication_key(public_key);
+
+ + +We use an uninterpreted function to represent the result of key construction. The actual value +does not matter for the verification of callers. + + + + + +
fun spec_ed25519_authentication_key(public_key: vector<u8>): vector<u8>;
+
+ + + +
+ + + +## Function `derived_address` + +convert authentication key to address + + +
public fun derived_address(authentication_key: vector<u8>): address
+
+ + + +
+Implementation + + +
public fun derived_address(authentication_key: vector<u8>): address {
+    assert!(Vector::length(&authentication_key) == AUTHENTICATION_KEY_LENGTH, Errors::invalid_argument(EWRONG_AUTHENTICATION_KEY_LENGTH));
+    let address_bytes = Vector::empty<u8>();
+
+    let i = 16;
+    while (i < 32) {
+        let b = *Vector::borrow(&authentication_key, i);
+        Vector::push_back(&mut address_bytes, b);
+        i = i + 1;
+    };
+
+    BCS::to_address(address_bytes)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if len(authentication_key) != 32;
+ensures [abstract] result == spec_derived_address(authentication_key);
+
+ + +We use an uninterpreted function to represent the result of derived address. The actual value +does not matter for the verification of callers. + + + + + +
fun spec_derived_address(authentication_key: vector<u8>): address;
+
+ + + +
+ + + +## Function `multi_ed25519_authentication_key` + +Compute a multied25519 account authentication key for the policy k + + +
public fun multi_ed25519_authentication_key(k: &Authenticator::MultiEd25519PublicKey): vector<u8>
+
+ + + +
+Implementation + + +
public fun multi_ed25519_authentication_key(k: &MultiEd25519PublicKey): vector<u8> {
+    let public_keys = &k.public_keys;
+    let len = Vector::length(public_keys);
+    let authentication_key_preimage = Vector::empty();
+    let i = 0;
+    while (i < len) {
+        let public_key = *Vector::borrow(public_keys, i);
+        Vector::append(
+            &mut authentication_key_preimage,
+            public_key
+        );
+        i = i + 1;
+    };
+    Vector::append(&mut authentication_key_preimage, BCS::to_bytes(&k.threshold));
+    Vector::push_back(&mut authentication_key_preimage, MULTI_ED25519_SCHEME_ID);
+    Hash::sha3_256(authentication_key_preimage)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `public_keys` + +Return the public keys involved in the multisig policy k + + +
public fun public_keys(k: &Authenticator::MultiEd25519PublicKey): &vector<vector<u8>>
+
+ + + +
+Implementation + + +
public fun public_keys(k: &MultiEd25519PublicKey): &vector<vector<u8>> {
+    &k.public_keys
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `threshold` + +Return the threshold for the multisig policy k + + +
public fun threshold(k: &Authenticator::MultiEd25519PublicKey): u8
+
+ + + +
+Implementation + + +
public fun threshold(k: &MultiEd25519PublicKey): u8 {
+    *&k.threshold
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/BCS.md b/release/v13/docs/BCS.md new file mode 100644 index 00000000..9e684aac --- /dev/null +++ b/release/v13/docs/BCS.md @@ -0,0 +1,1599 @@ + + + +# Module `0x1::BCS` + +Utility for converting a Move value to its binary representation in BCS (Diem Canonical +Serialization). BCS is the binary encoding for Move resources and other non-module values +published on-chain. + + +- [Constants](#@Constants_0) +- [Function `to_bytes`](#0x1_BCS_to_bytes) +- [Function `to_address`](#0x1_BCS_to_address) +- [Function `deserialize_option_bytes_vector`](#0x1_BCS_deserialize_option_bytes_vector) +- [Function `deserialize_bytes_vector`](#0x1_BCS_deserialize_bytes_vector) +- [Function `deserialize_u64_vector`](#0x1_BCS_deserialize_u64_vector) +- [Function `deserialize_u128_vector`](#0x1_BCS_deserialize_u128_vector) +- [Function `deserialize_option_bytes`](#0x1_BCS_deserialize_option_bytes) +- [Function `deserialize_address`](#0x1_BCS_deserialize_address) +- [Function `deserialize_16_bytes`](#0x1_BCS_deserialize_16_bytes) +- [Function `deserialize_bytes`](#0x1_BCS_deserialize_bytes) +- [Function `deserialize_u128`](#0x1_BCS_deserialize_u128) +- [Function `deserialize_u64`](#0x1_BCS_deserialize_u64) +- [Function `deserialize_u32`](#0x1_BCS_deserialize_u32) +- [Function `deserialize_u16`](#0x1_BCS_deserialize_u16) +- [Function `deserialize_u8`](#0x1_BCS_deserialize_u8) +- [Function `deserialize_option_tag`](#0x1_BCS_deserialize_option_tag) +- [Function `deserialize_len`](#0x1_BCS_deserialize_len) +- [Function `deserialize_bool`](#0x1_BCS_deserialize_bool) +- [Function `get_byte`](#0x1_BCS_get_byte) +- [Function `get_n_bytes`](#0x1_BCS_get_n_bytes) +- [Function `get_n_bytes_as_u128`](#0x1_BCS_get_n_bytes_as_u128) +- [Function `deserialize_uleb128_as_u32`](#0x1_BCS_deserialize_uleb128_as_u32) +- [Function `serialize_u32_as_uleb128`](#0x1_BCS_serialize_u32_as_uleb128) +- [Function `skip_option_bytes_vector`](#0x1_BCS_skip_option_bytes_vector) +- [Function `skip_option_bytes`](#0x1_BCS_skip_option_bytes) +- [Function `skip_bytes_vector`](#0x1_BCS_skip_bytes_vector) +- [Function `skip_bytes`](#0x1_BCS_skip_bytes) +- [Function `skip_n_bytes`](#0x1_BCS_skip_n_bytes) +- [Function `skip_u64_vector`](#0x1_BCS_skip_u64_vector) +- [Function `skip_u128_vector`](#0x1_BCS_skip_u128_vector) +- [Function `skip_u256`](#0x1_BCS_skip_u256) +- [Function `skip_u128`](#0x1_BCS_skip_u128) +- [Function `skip_u64`](#0x1_BCS_skip_u64) +- [Function `skip_u32`](#0x1_BCS_skip_u32) +- [Function `skip_u16`](#0x1_BCS_skip_u16) +- [Function `skip_address`](#0x1_BCS_skip_address) +- [Function `skip_bool`](#0x1_BCS_skip_bool) +- [Function `can_skip`](#0x1_BCS_can_skip) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Option;
+
+ + + + + +## Constants + + + + + + +
const ERR_INPUT_NOT_LARGE_ENOUGH: u64 = 201;
+
+ + + + + + + +
const ERR_INVALID_ULEB128_NUMBER_UNEXPECTED_ZERO_DIGIT: u64 = 207;
+
+ + + + + + + +
const ERR_OVERFLOW_PARSING_ULEB128_ENCODED_UINT32: u64 = 206;
+
+ + + + + + + +
const ERR_UNEXPECTED_BOOL_VALUE: u64 = 205;
+
+ + + + + + + +
const INTEGER32_MAX_VALUE: u64 = 2147483647;
+
+ + + + + +## Function `to_bytes` + +Return the binary representation of v in BCS (Starcoin Canonical Serialization) format + + +
public fun to_bytes<MoveValue>(v: &MoveValue): vector<u8>
+
+ + + +
+Implementation + + +
native public fun to_bytes<MoveValue>(v: &MoveValue): vector<u8>;
+
+ + + +
+ + + +## Function `to_address` + +Return the address of key bytes + + +
public fun to_address(key_bytes: vector<u8>): address
+
+ + + +
+Implementation + + +
native public fun to_address(key_bytes: vector<u8>): address;
+
+ + + +
+ + + +## Function `deserialize_option_bytes_vector` + + + +
public fun deserialize_option_bytes_vector(input: &vector<u8>, offset: u64): (vector<Option::Option<vector<u8>>>, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_option_bytes_vector(input: &vector<u8>, offset: u64): (vector<Option::Option<vector<u8>>>, u64) {
+    let (len, new_offset) = deserialize_len(input, offset);
+    let i = 0;
+    let vec = Vector::empty<Option::Option<vector<u8>>>();
+    while (i < len) {
+        let (opt_bs, o) = deserialize_option_bytes(input, new_offset);
+        Vector::push_back(&mut vec, opt_bs);
+        new_offset = o;
+        i = i + 1;
+    };
+    (vec, new_offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_bytes_vector` + + + +
public fun deserialize_bytes_vector(input: &vector<u8>, offset: u64): (vector<vector<u8>>, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_bytes_vector(input: &vector<u8>, offset: u64): (vector<vector<u8>>, u64) {
+    let (len, new_offset) = deserialize_len(input, offset);
+    let i = 0;
+    let vec = Vector::empty<vector<u8>>();
+    while (i < len) {
+        let (opt_bs, o) = deserialize_bytes(input, new_offset);
+        Vector::push_back(&mut vec, opt_bs);
+        new_offset = o;
+        i = i + 1;
+    };
+    (vec, new_offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_u64_vector` + + + +
public fun deserialize_u64_vector(input: &vector<u8>, offset: u64): (vector<u64>, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_u64_vector(input: &vector<u8>, offset: u64): (vector<u64>, u64) {
+    let (len, new_offset) = deserialize_len(input, offset);
+    let i = 0;
+    let vec = Vector::empty<u64>();
+    while (i < len) {
+        let (opt_bs, o) = deserialize_u64(input, new_offset);
+        Vector::push_back(&mut vec, opt_bs);
+        new_offset = o;
+        i = i + 1;
+    };
+    (vec, new_offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_u128_vector` + + + +
public fun deserialize_u128_vector(input: &vector<u8>, offset: u64): (vector<u128>, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_u128_vector(input: &vector<u8>, offset: u64): (vector<u128>, u64) {
+    let (len, new_offset) = deserialize_len(input, offset);
+    let i = 0;
+    let vec = Vector::empty<u128>();
+    while (i < len) {
+        let (opt_bs, o) = deserialize_u128(input, new_offset);
+        Vector::push_back(&mut vec, opt_bs);
+        new_offset = o;
+        i = i + 1;
+    };
+    (vec, new_offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_option_bytes` + + + +
public fun deserialize_option_bytes(input: &vector<u8>, offset: u64): (Option::Option<vector<u8>>, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_option_bytes(input: &vector<u8>, offset: u64): (Option::Option<vector<u8>>, u64) {
+    let (tag, new_offset) = deserialize_option_tag(input, offset);
+    if (!tag) {
+        return (Option::none<vector<u8>>(), new_offset)
+    } else {
+        let (bs, new_offset) = deserialize_bytes(input, new_offset);
+        return (Option::some<vector<u8>>(bs), new_offset)
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_address` + + + +
public fun deserialize_address(input: &vector<u8>, offset: u64): (address, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_address(input: &vector<u8>, offset: u64): (address, u64) {
+    let (content, new_offset) = deserialize_16_bytes(input, offset);
+    (BCS::to_address(content), new_offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_16_bytes` + + + +
public fun deserialize_16_bytes(input: &vector<u8>, offset: u64): (vector<u8>, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_16_bytes(input: &vector<u8>, offset: u64): (vector<u8>, u64) {
+    let content = get_n_bytes(input, offset, 16);
+    (content, offset + 16)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_bytes` + + + +
public fun deserialize_bytes(input: &vector<u8>, offset: u64): (vector<u8>, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_bytes(input: &vector<u8>, offset: u64): (vector<u8>, u64) {
+    let (len, new_offset) = deserialize_len(input, offset);
+    let content = get_n_bytes(input, new_offset, len);
+    (content, new_offset + len)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_u128` + + + +
public fun deserialize_u128(input: &vector<u8>, offset: u64): (u128, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_u128(input: &vector<u8>, offset: u64): (u128, u64) {
+    let u = get_n_bytes_as_u128(input, offset, 16);
+    (u, offset + 16)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_u64` + + + +
public fun deserialize_u64(input: &vector<u8>, offset: u64): (u64, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_u64(input: &vector<u8>, offset: u64): (u64, u64) {
+    let u = get_n_bytes_as_u128(input, offset, 8);
+    ((u as u64), offset + 8)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_u32` + + + +
public fun deserialize_u32(input: &vector<u8>, offset: u64): (u64, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_u32(input: &vector<u8>, offset: u64): (u64, u64) {
+    let u = get_n_bytes_as_u128(input, offset, 4);
+    ((u as u64), offset + 4)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_u16` + + + +
public fun deserialize_u16(input: &vector<u8>, offset: u64): (u64, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_u16(input: &vector<u8>, offset: u64): (u64, u64) {
+    let u = get_n_bytes_as_u128(input, offset, 2);
+    ((u as u64), offset + 2)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_u8` + + + +
public fun deserialize_u8(input: &vector<u8>, offset: u64): (u8, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_u8(input: &vector<u8>, offset: u64): (u8, u64) {
+    let u = get_byte(input, offset);
+    (u, offset + 1)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_option_tag` + + + +
public fun deserialize_option_tag(input: &vector<u8>, offset: u64): (bool, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_option_tag(input: &vector<u8>, offset: u64): (bool, u64) {
+    deserialize_bool(input, offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_len` + + + +
public fun deserialize_len(input: &vector<u8>, offset: u64): (u64, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_len(input: &vector<u8>, offset: u64): (u64, u64) {
+    deserialize_uleb128_as_u32(input, offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_bool` + + + +
public fun deserialize_bool(input: &vector<u8>, offset: u64): (bool, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_bool(input: &vector<u8>, offset: u64): (bool, u64) {
+    let b = get_byte(input, offset);
+    if (b == 1) {
+        return (true, offset + 1)
+    } else if (b == 0) {
+        return (false, offset + 1)
+    } else {
+        abort ERR_UNEXPECTED_BOOL_VALUE
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `get_byte` + + + +
fun get_byte(input: &vector<u8>, offset: u64): u8
+
+ + + +
+Implementation + + +
fun get_byte(input: &vector<u8>, offset: u64): u8 {
+    assert!(((offset + 1) <= Vector::length(input)) && (offset < offset + 1), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH));
+    *Vector::borrow(input, offset)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `get_n_bytes` + + + +
fun get_n_bytes(input: &vector<u8>, offset: u64, n: u64): vector<u8>
+
+ + + +
+Implementation + + +
fun get_n_bytes(input: &vector<u8>, offset: u64, n: u64): vector<u8> {
+    assert!(((offset + n) <= Vector::length(input)) && (offset < offset + n), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH));
+    let i = 0;
+    let content = Vector::empty<u8>();
+    while (i < n) {
+        let b = *Vector::borrow(input, offset + i);
+        Vector::push_back(&mut content, b);
+        i = i + 1;
+    };
+    content
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `get_n_bytes_as_u128` + + + +
fun get_n_bytes_as_u128(input: &vector<u8>, offset: u64, n: u64): u128
+
+ + + +
+Implementation + + +
fun get_n_bytes_as_u128(input: &vector<u8>, offset: u64, n: u64): u128 {
+    assert!(((offset + n) <= Vector::length(input)) && (offset < offset + n), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH));
+    let number: u128 = 0;
+    let i = 0;
+    while (i < n) {
+        let byte = *Vector::borrow(input, offset + i);
+        let s = (i as u8) * 8;
+        number = number + ((byte as u128) << s);
+        i = i + 1;
+    };
+    number
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `deserialize_uleb128_as_u32` + + + +
public fun deserialize_uleb128_as_u32(input: &vector<u8>, offset: u64): (u64, u64)
+
+ + + +
+Implementation + + +
public fun deserialize_uleb128_as_u32(input: &vector<u8>, offset: u64): (u64, u64) {
+    let value: u64 = 0;
+    let shift = 0;
+    let new_offset = offset;
+    while (shift < 32) {
+        let x = get_byte(input, new_offset);
+        new_offset = new_offset + 1;
+        let digit: u8 = x & 0x7F;
+        value = value | (digit as u64) << shift;
+        if ((value < 0) || (value > INTEGER32_MAX_VALUE)) {
+            abort ERR_OVERFLOW_PARSING_ULEB128_ENCODED_UINT32
+        };
+        if (digit == x) {
+            if (shift > 0 && digit == 0) {
+                abort ERR_INVALID_ULEB128_NUMBER_UNEXPECTED_ZERO_DIGIT
+            };
+            return (value, new_offset)
+        };
+        shift = shift + 7
+    };
+    abort ERR_OVERFLOW_PARSING_ULEB128_ENCODED_UINT32
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+pragma verify = false;
+
+ + + +
+ + + +## Function `serialize_u32_as_uleb128` + + + +
fun serialize_u32_as_uleb128(value: u64): vector<u8>
+
+ + + +
+Implementation + + +
fun serialize_u32_as_uleb128(value: u64): vector<u8> {
+    let output = Vector::empty<u8>();
+    while ((value >> 7) != 0) {
+        Vector::push_back(&mut output, (((value & 0x7f) | 0x80) as u8));
+        value = value >> 7;
+    };
+    Vector::push_back(&mut output, (value as u8));
+    output
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_option_bytes_vector` + + + +
public fun skip_option_bytes_vector(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_option_bytes_vector(input: &vector<u8>, offset: u64): u64 {
+    let (len, new_offset) = deserialize_len(input, offset);
+    let i = 0;
+    while (i < len) {
+        new_offset = skip_option_bytes(input, new_offset);
+        i = i + 1;
+    };
+    new_offset
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_option_bytes` + + + +
public fun skip_option_bytes(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_option_bytes(input: &vector<u8>, offset: u64):  u64 {
+    let (tag, new_offset) = deserialize_option_tag(input, offset);
+    if (!tag) {
+        new_offset
+    } else {
+        skip_bytes(input, new_offset)
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_bytes_vector` + + + +
public fun skip_bytes_vector(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_bytes_vector(input: &vector<u8>, offset: u64): u64 {
+    let (len, new_offset) = deserialize_len(input, offset);
+    let i = 0;
+    while (i < len) {
+        new_offset = skip_bytes(input, new_offset);
+        i = i + 1;
+    };
+    new_offset
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_bytes` + + + +
public fun skip_bytes(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_bytes(input: &vector<u8>, offset: u64): u64 {
+    let (len, new_offset) = deserialize_len(input, offset);
+    new_offset + len
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_n_bytes` + + + +
public fun skip_n_bytes(input: &vector<u8>, offset: u64, n: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_n_bytes(input: &vector<u8>, offset: u64, n:u64): u64 {
+    can_skip(input, offset, n );
+    offset + n
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_u64_vector` + + + +
public fun skip_u64_vector(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_u64_vector(input: &vector<u8>, offset: u64): u64 {
+    let (len, new_offset) = deserialize_len(input, offset);
+    can_skip(input, new_offset, len * 8);
+    new_offset + len * 8
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_u128_vector` + + + +
public fun skip_u128_vector(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_u128_vector(input: &vector<u8>, offset: u64): u64 {
+    let (len, new_offset) = deserialize_len(input, offset);
+    can_skip(input, new_offset, len * 16);
+    new_offset + len * 16
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_u256` + + + +
public fun skip_u256(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_u256(input: &vector<u8>, offset: u64): u64 {
+    can_skip(input, offset, 32 );
+    offset + 32
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_u128` + + + +
public fun skip_u128(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_u128(input: &vector<u8>, offset: u64): u64 {
+    can_skip(input, offset, 16 );
+    offset + 16
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_u64` + + + +
public fun skip_u64(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_u64(input: &vector<u8>, offset: u64): u64 {
+    can_skip(input, offset, 8 );
+    offset + 8
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_u32` + + + +
public fun skip_u32(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_u32(input: &vector<u8>, offset: u64): u64 {
+    can_skip(input, offset, 4 );
+    offset + 4
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_u16` + + + +
public fun skip_u16(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_u16(input: &vector<u8>, offset: u64): u64 {
+    can_skip(input, offset, 2 );
+    offset + 2
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_address` + + + +
public fun skip_address(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_address(input: &vector<u8>, offset: u64): u64 {
+    skip_n_bytes(input, offset, 16)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `skip_bool` + + + +
public fun skip_bool(input: &vector<u8>, offset: u64): u64
+
+ + + +
+Implementation + + +
public fun skip_bool(input: &vector<u8>, offset: u64):  u64{
+    can_skip(input, offset, 1);
+    offset + 1
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `can_skip` + + + +
fun can_skip(input: &vector<u8>, offset: u64, n: u64)
+
+ + + +
+Implementation + + +
fun can_skip(input: &vector<u8>, offset: u64, n: u64){
+    assert!(((offset + n) <= Vector::length(input)) && (offset < offset + n), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH));
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
+ + + + + + + +
native fun serialize<MoveValue>(v: &MoveValue): vector<u8>;
+
diff --git a/release/v13/docs/Bitwise.md b/release/v13/docs/Bitwise.md new file mode 100644 index 00000000..74d8a7ca --- /dev/null +++ b/release/v13/docs/Bitwise.md @@ -0,0 +1,179 @@ + + + +# Module `0x1::BitOperators` + +Functions for bit operations. + + +- [Function `and`](#0x1_BitOperators_and) +- [Function `or`](#0x1_BitOperators_or) +- [Function `xor`](#0x1_BitOperators_xor) +- [Function `not`](#0x1_BitOperators_not) +- [Function `lshift`](#0x1_BitOperators_lshift) +- [Function `rshift`](#0x1_BitOperators_rshift) +- [Module Specification](#@Module_Specification_0) + + +
+ + + + + +## Function `and` + +bit and: x & y + + +
public fun and(x: u64, y: u64): u64
+
+ + + +
+Implementation + + +
public fun and(x: u64, y: u64): u64 {
+    (x & y as u64)
+}
+
+ + + +
+ + + +## Function `or` + +bit or: x | y + + +
public fun or(x: u64, y: u64): u64
+
+ + + +
+Implementation + + +
public fun or(x: u64, y: u64): u64 {
+    (x | y as u64)
+}
+
+ + + +
+ + + +## Function `xor` + +bit xor: x ^ y + + +
public fun xor(x: u64, y: u64): u64
+
+ + + +
+Implementation + + +
public fun xor(x: u64, y: u64): u64 {
+    (x ^ y as u64)
+}
+
+ + + +
+ + + +## Function `not` + +bit not: !x + + +
public fun not(x: u64): u64
+
+ + + +
+Implementation + + +
public fun not(x: u64): u64 {
+   (x ^ 18446744073709551615u64 as u64)
+}
+
+ + + +
+ + + +## Function `lshift` + +left shift n bits. + + +
public fun lshift(x: u64, n: u8): u64
+
+ + + +
+Implementation + + +
public fun lshift(x: u64, n: u8): u64 {
+    (x << n  as u64)
+}
+
+ + + +
+ + + +## Function `rshift` + +right shift n bits. + + +
public fun rshift(x: u64, n: u8): u64
+
+ + + +
+Implementation + + +
public fun rshift(x: u64, n: u8): u64 {
+    (x >> n  as u64)
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+
diff --git a/release/v13/docs/Block.md b/release/v13/docs/Block.md new file mode 100644 index 00000000..07134739 --- /dev/null +++ b/release/v13/docs/Block.md @@ -0,0 +1,995 @@ + + + +# Module `0x1::Block` + +Block module provide metadata for generated blocks. + + +- [Resource `BlockMetadata`](#0x1_Block_BlockMetadata) +- [Struct `NewBlockEvent`](#0x1_Block_NewBlockEvent) +- [Struct `Checkpoint`](#0x1_Block_Checkpoint) +- [Resource `Checkpoints`](#0x1_Block_Checkpoints) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_Block_initialize) +- [Function `get_current_block_number`](#0x1_Block_get_current_block_number) +- [Function `get_parent_hash`](#0x1_Block_get_parent_hash) +- [Function `get_parents_hash`](#0x1_Block_get_parents_hash) +- [Function `get_current_author`](#0x1_Block_get_current_author) +- [Function `process_block_metadata`](#0x1_Block_process_block_metadata) +- [Function `checkpoints_init`](#0x1_Block_checkpoints_init) +- [Function `checkpoint_entry`](#0x1_Block_checkpoint_entry) +- [Function `checkpoint`](#0x1_Block_checkpoint) +- [Function `base_checkpoint`](#0x1_Block_base_checkpoint) +- [Function `latest_state_root`](#0x1_Block_latest_state_root) +- [Function `base_latest_state_root`](#0x1_Block_base_latest_state_root) +- [Function `update_state_root_entry`](#0x1_Block_update_state_root_entry) +- [Function `update_state_root`](#0x1_Block_update_state_root) +- [Function `base_update_state_root`](#0x1_Block_base_update_state_root) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::BCS;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+use 0x1::Event;
+use 0x1::FlexiDagConfig;
+use 0x1::Hash;
+use 0x1::Option;
+use 0x1::Ring;
+use 0x1::Timestamp;
+use 0x1::Vector;
+
+ + + + + +## Resource `BlockMetadata` + +Block metadata struct. + + +
struct BlockMetadata has key
+
+ + + +
+Fields + + +
+
+number: u64 +
+
+ number of the current block +
+
+parent_hash: vector<u8> +
+
+ Hash of the parent block. +
+
+author: address +
+
+ Author of the current block. +
+
+uncles: u64 +
+
+ number of uncles. +
+
+parents_hash: Option::Option<vector<u8>> +
+
+ Hash of the parents hash for a Dag block. +
+
+new_block_events: Event::EventHandle<Block::NewBlockEvent> +
+
+ Handle of events when new blocks are emitted +
+
+ + +
+ + + +## Struct `NewBlockEvent` + +Events emitted when new block generated. + + +
struct NewBlockEvent has drop, store
+
+ + + +
+Fields + + +
+
+number: u64 +
+
+ +
+
+author: address +
+
+ +
+
+timestamp: u64 +
+
+ +
+
+uncles: u64 +
+
+ +
+
+parents_hash: Option::Option<vector<u8>> +
+
+ +
+
+ + +
+ + + +## Struct `Checkpoint` + + + +
struct Checkpoint has copy, drop, store
+
+ + + +
+Fields + + +
+
+block_number: u64 +
+
+ +
+
+block_hash: vector<u8> +
+
+ +
+
+state_root: Option::Option<vector<u8>> +
+
+ +
+
+ + +
+ + + +## Resource `Checkpoints` + + + +
struct Checkpoints has store, key
+
+ + + +
+Fields + + +
+
+checkpoints: Ring::Ring<Block::Checkpoint> +
+
+ +
+
+index: u64 +
+
+ +
+
+last_number: u64 +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const BLOCK_HEADER_LENGTH: u64 = 247;
+
+ + + + + + + +
const BLOCK_INTERVAL_NUMBER: u64 = 5;
+
+ + + + + + + +
const CHECKPOINT_LENGTH: u64 = 60;
+
+ + + + + + + +
const EBLOCK_NUMBER_MISMATCH: u64 = 17;
+
+ + + + + + + +
const ERROR_INTERVAL_TOO_LITTLE: u64 = 20;
+
+ + + + + + + +
const ERROR_NOT_BLOCK_HEADER: u64 = 19;
+
+ + + + + + + +
const ERROR_NO_HAVE_CHECKPOINT: u64 = 18;
+
+ + + + + +## Function `initialize` + +This can only be invoked by the GENESIS_ACCOUNT at genesis + + +
public fun initialize(account: &signer, parent_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, parent_hash: vector<u8>) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+
+    move_to<BlockMetadata>(
+        account,
+        BlockMetadata {
+            number: 0,
+            parent_hash,
+            author: CoreAddresses::GENESIS_ADDRESS(),
+            uncles: 0,
+            parents_hash: Option::none<vector<u8>>(),
+            new_block_events: Event::new_event_handle<Self::NewBlockEvent>(account),
+        });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<BlockMetadata>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `get_current_block_number` + +Get the current block number + + +
public fun get_current_block_number(): u64
+
+ + + +
+Implementation + + +
public fun get_current_block_number(): u64 acquires BlockMetadata {
+  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `get_parent_hash` + +Get the hash of the parent block. + + +
public fun get_parent_hash(): vector<u8>
+
+ + + +
+Implementation + + +
public fun get_parent_hash(): vector<u8> acquires BlockMetadata {
+  *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parent_hash
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `get_parents_hash` + + + +
public fun get_parents_hash(): Option::Option<vector<u8>>
+
+ + + +
+Implementation + + +
public fun get_parents_hash(): Option::Option<vector<u8>> acquires BlockMetadata {
+    *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parents_hash
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `get_current_author` + +Gets the address of the author of the current block + + +
public fun get_current_author(): address
+
+ + + +
+Implementation + + +
public fun get_current_author(): address acquires BlockMetadata {
+  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).author
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `process_block_metadata` + +Call at block prologue + + +
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: Option::Option<vector<u8>>)
+
+ + + +
+Implementation + + +
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option<vector<u8>>) acquires BlockMetadata{
+    CoreAddresses::assert_genesis_address(account);
+
+    let block_metadata_ref = borrow_global_mut<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
+    assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH));
+    block_metadata_ref.number = number;
+    block_metadata_ref.author= author;
+    block_metadata_ref.parent_hash = parent_hash;
+    block_metadata_ref.uncles = uncles;
+    block_metadata_ref.parents_hash = parents_hash;
+
+    Event::emit_event<NewBlockEvent>(
+      &mut block_metadata_ref.new_block_events,
+      NewBlockEvent {
+          number,
+          author,
+          timestamp,
+          uncles,
+          parents_hash,
+      }
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if number != global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+
+ + + + + + + +
schema AbortsIfBlockMetadataNotExist {
+    aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+}
+
+ + + +
+ + + +## Function `checkpoints_init` + + + +
public fun checkpoints_init(account: &signer)
+
+ + + +
+Implementation + + +
public fun checkpoints_init(account: &signer){
+    CoreAddresses::assert_genesis_address(account);
+
+    let checkpoints = Ring::create_with_capacity<Checkpoint>(CHECKPOINT_LENGTH);
+    move_to<Checkpoints>(
+        account,
+        Checkpoints {
+           checkpoints,
+           index        : 0,
+           last_number  : 0,
+    });
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `checkpoint_entry` + + + +
public entry fun checkpoint_entry(_account: signer)
+
+ + + +
+Implementation + + +
public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints {
+    checkpoint();
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `checkpoint` + + + +
public fun checkpoint()
+
+ + + +
+Implementation + + +
public fun checkpoint() acquires BlockMetadata, Checkpoints{
+    let parent_block_number = get_current_block_number() - 1;
+    let parent_block_hash   = get_parent_hash();
+
+    let checkpoints = borrow_global_mut<Checkpoints>(CoreAddresses::GENESIS_ADDRESS());
+    base_checkpoint(checkpoints, parent_block_number, parent_block_hash);
+
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `base_checkpoint` + + + +
fun base_checkpoint(checkpoints: &mut Block::Checkpoints, parent_block_number: u64, parent_block_hash: vector<u8>)
+
+ + + +
+Implementation + + +
fun base_checkpoint(checkpoints: &mut Checkpoints, parent_block_number: u64, parent_block_hash:vector<u8>){
+    assert!(checkpoints.last_number + BLOCK_INTERVAL_NUMBER <= parent_block_number || checkpoints.last_number == 0, Errors::invalid_argument(ERROR_INTERVAL_TOO_LITTLE));
+
+    checkpoints.index = checkpoints.index + 1;
+    checkpoints.last_number = parent_block_number;
+    let op_checkpoint = Ring::push<Checkpoint>(&mut checkpoints.checkpoints, Checkpoint {
+                                                            block_number: parent_block_number,
+                                                            block_hash: parent_block_hash,
+                                                            state_root: Option::none<vector<u8>>(),
+                                                        } );
+    if(Option::is_some(&op_checkpoint)){
+        Option::destroy_some(op_checkpoint);
+    }else{
+        Option::destroy_none(op_checkpoint);
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `latest_state_root` + + + +
public fun latest_state_root(): (u64, vector<u8>)
+
+ + + +
+Implementation + + +
public fun latest_state_root():(u64,vector<u8>) acquires  Checkpoints{
+    let checkpoints = borrow_global<Checkpoints>(CoreAddresses::GENESIS_ADDRESS());
+    base_latest_state_root(checkpoints)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `base_latest_state_root` + + + +
fun base_latest_state_root(checkpoints: &Block::Checkpoints): (u64, vector<u8>)
+
+ + + +
+Implementation + + +
fun base_latest_state_root(checkpoints: &Checkpoints):(u64,vector<u8>){
+    let len = Ring::capacity<Checkpoint>(&checkpoints.checkpoints);
+    let j = if(checkpoints.index < len - 1){
+        checkpoints.index
+    }else{
+        len
+    };
+    let i = checkpoints.index;
+    while( j > 0){
+        let op_checkpoint = Ring::borrow(&checkpoints.checkpoints, i - 1 );
+        if( Option::is_some(op_checkpoint) && Option::is_some(&Option::borrow(op_checkpoint).state_root) ) {
+            let state_root = Option::borrow(&Option::borrow(op_checkpoint).state_root);
+            return (Option::borrow(op_checkpoint).block_number, *state_root)
+        };
+        j = j - 1;
+        i = i - 1;
+    };
+
+    abort Errors::invalid_state(ERROR_NO_HAVE_CHECKPOINT)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `update_state_root_entry` + + + +
public entry fun update_state_root_entry(_account: signer, header: vector<u8>)
+
+ + + +
+Implementation + + +
public entry fun update_state_root_entry(_account: signer , header: vector<u8>)
+acquires Checkpoints {
+    update_state_root(header);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `update_state_root` + + + +
public fun update_state_root(header: vector<u8>)
+
+ + + +
+Implementation + + +
public fun update_state_root(header: vector<u8>) acquires  Checkpoints {
+    let checkpoints = borrow_global_mut<Checkpoints>(CoreAddresses::GENESIS_ADDRESS());
+    base_update_state_root(checkpoints, header);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `base_update_state_root` + + + +
fun base_update_state_root(checkpoints: &mut Block::Checkpoints, header: vector<u8>)
+
+ + + +
+Implementation + + +
fun base_update_state_root(checkpoints: &mut Checkpoints, header: vector<u8>){
+    let prefix = Hash::sha3_256(b"STARCOIN::BlockHeader");
+
+    //parent_hash
+    let new_offset = BCS::skip_bytes(&header,0);
+    //timestamp
+    let new_offset = BCS::skip_u64(&header,new_offset);
+    //number
+    let (number,new_offset) = BCS::deserialize_u64(&header,new_offset);
+    //author
+    new_offset = BCS::skip_address(&header,new_offset);
+    //author_auth_key
+    new_offset = BCS::skip_option_bytes(&header,new_offset);
+    //txn_accumulator_root
+    new_offset = BCS::skip_bytes(&header,new_offset);
+    //block_accumulator_root
+    new_offset = BCS::skip_bytes(&header,new_offset);
+    //state_root
+    let (state_root,_new_offset) = BCS::deserialize_bytes(&header,new_offset);
+
+    Vector::append(&mut prefix,header);
+    let block_hash = Hash::sha3_256(prefix);
+
+    let len = Ring::capacity<Checkpoint>(&checkpoints.checkpoints);
+    let j = if(checkpoints.index < len - 1){
+        checkpoints.index
+    }else{
+        len
+    };
+    let i = checkpoints.index;
+    while( j > 0){
+        let op_checkpoint = Ring::borrow_mut(&mut checkpoints.checkpoints, i - 1);
+
+        if( Option::is_some(op_checkpoint) && &Option::borrow(op_checkpoint).block_hash == &block_hash && Option::borrow<Checkpoint>(op_checkpoint).block_number == number) {
+
+            let op_state_root = &mut Option::borrow_mut<Checkpoint>(op_checkpoint).state_root;
+            if(Option::is_some(op_state_root)){
+                Option::swap(op_state_root, state_root);
+            }else{
+                Option::fill(op_state_root, state_root);
+            };
+            return
+        };
+        j = j - 1;
+        i = i - 1;
+    };
+
+    abort Errors::invalid_state(ERROR_NO_HAVE_CHECKPOINT)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/BlockReward.md b/release/v13/docs/BlockReward.md new file mode 100644 index 00000000..213d255d --- /dev/null +++ b/release/v13/docs/BlockReward.md @@ -0,0 +1,397 @@ + + + +# Module `0x1::BlockReward` + +The module provide block rewarding calculation logic. + + +- [Resource `RewardQueue`](#0x1_BlockReward_RewardQueue) +- [Struct `RewardInfo`](#0x1_BlockReward_RewardInfo) +- [Struct `BlockRewardEvent`](#0x1_BlockReward_BlockRewardEvent) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_BlockReward_initialize) +- [Function `process_block_reward`](#0x1_BlockReward_process_block_reward) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Account;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+use 0x1::Event;
+use 0x1::RewardConfig;
+use 0x1::STC;
+use 0x1::Timestamp;
+use 0x1::Token;
+use 0x1::Treasury;
+use 0x1::TreasuryWithdrawDaoProposal;
+use 0x1::Vector;
+
+ + + + + +## Resource `RewardQueue` + +Queue of rewards distributed to miners. + + +
struct RewardQueue has key
+
+ + + +
+Fields + + +
+
+reward_number: u64 +
+
+ How many block rewards has been handled. +
+
+infos: vector<BlockReward::RewardInfo> +
+
+ informations about the reward distribution. +
+
+reward_events: Event::EventHandle<BlockReward::BlockRewardEvent> +
+
+ event handle used to emit block reward event. +
+
+ + +
+ + + +## Struct `RewardInfo` + +Reward info of miners. + + +
struct RewardInfo has store
+
+ + + +
+Fields + + +
+
+number: u64 +
+
+ number of the block miner minted. +
+
+reward: u128 +
+
+ how many stc rewards. +
+
+miner: address +
+
+ miner who mint the block. +
+
+gas_fees: Token::Token<STC::STC> +
+
+ store the gas fee that users consumed. +
+
+ + +
+ + + +## Struct `BlockRewardEvent` + +block reward event + + +
struct BlockRewardEvent has drop, store
+
+ + + +
+Fields + + +
+
+block_number: u64 +
+
+ block number +
+
+block_reward: u128 +
+
+ STC reward. +
+
+gas_fees: u128 +
+
+ gas fees in STC. +
+
+miner: address +
+
+ block miner +
+
+ + +
+ + + +## Constants + + + + + + +
const EAUTHOR_ADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 105;
+
+ + + + + + + +
const EAUTHOR_AUTH_KEY_IS_EMPTY: u64 = 101;
+
+ + + + + + + +
const ECURRENT_NUMBER_IS_WRONG: u64 = 102;
+
+ + + + + + + +
const EMINER_EXIST: u64 = 104;
+
+ + + + + + + +
const EREWARD_NUMBER_IS_WRONG: u64 = 103;
+
+ + + + + +## Function `initialize` + +Initialize the module, should be called in genesis. + + +
public fun initialize(account: &signer, reward_delay: u64)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, reward_delay: u64) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+
+    RewardConfig::initialize(account, reward_delay);
+    move_to<RewardQueue>(account, RewardQueue {
+        reward_number: 0,
+        infos: Vector::empty(),
+        reward_events: Event::new_event_handle<Self::BlockRewardEvent>(account),
+    });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+include Config::PublishNewConfigAbortsIf<RewardConfig::RewardConfig>;
+include Config::PublishNewConfigEnsures<RewardConfig::RewardConfig>;
+aborts_if exists<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `process_block_reward` + +Process the given block rewards. + + +
public fun process_block_reward(account: &signer, current_number: u64, current_reward: u128, current_author: address, _auth_key_vec: vector<u8>, previous_block_gas_fees: Token::Token<STC::STC>)
+
+ + + +
+Implementation + + +
public fun process_block_reward(account: &signer, current_number: u64, current_reward: u128,
+                                current_author: address, _auth_key_vec: vector<u8>,
+                                previous_block_gas_fees: Token::Token<STC>) acquires RewardQueue {
+    CoreAddresses::assert_genesis_address(account);
+    if (current_number == 0) {
+        Token::destroy_zero(previous_block_gas_fees);
+        return
+    };
+
+    let rewards = borrow_global_mut<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());
+    let len = Vector::length(&rewards.infos);
+    assert!((current_number == (rewards.reward_number + len + 1)), Errors::invalid_argument(ECURRENT_NUMBER_IS_WRONG));
+
+    // distribute gas fee to last block reward info.
+    // if not last block reward info, the passed in gas fee must be zero.
+    if (len == 0) {
+        Token::destroy_zero(previous_block_gas_fees);
+    } else {
+        let reward_info = Vector::borrow_mut(&mut rewards.infos, len - 1);
+        assert!(current_number == reward_info.number + 1, Errors::invalid_argument(ECURRENT_NUMBER_IS_WRONG));
+        Token::deposit(&mut reward_info.gas_fees, previous_block_gas_fees);
+    };
+
+    let reward_delay = RewardConfig::reward_delay();
+    if (len >= reward_delay) {//pay and remove
+        let i = len;
+        while (i > 0 && i >= reward_delay) {
+            let RewardInfo { number: reward_block_number, reward: block_reward, gas_fees, miner } = Vector::remove(&mut rewards.infos, 0);
+
+            let gas_fee_value = Token::value(&gas_fees);
+            let total_reward = gas_fees;
+            // add block reward to total.
+            if (block_reward > 0) {
+                // if no STC in Treasury, BlockReward will been 0.
+                let treasury_balance = Treasury::balance<STC>();
+                if (treasury_balance < block_reward) {
+                    block_reward = treasury_balance;
+                };
+                if (block_reward > 0) {
+                    let reward = TreasuryWithdrawDaoProposal::withdraw_for_block_reward<STC>(account, block_reward);
+                    Token::deposit(&mut total_reward, reward);
+                };
+            };
+            // distribute total.
+            if (Token::value(&total_reward) > 0) {
+                Account::deposit<STC>(miner, total_reward);
+            } else {
+                Token::destroy_zero(total_reward);
+            };
+            // emit reward event.
+            Event::emit_event<BlockRewardEvent>(
+                &mut rewards.reward_events,
+                BlockRewardEvent {
+                    block_number: reward_block_number,
+                    block_reward: block_reward,
+                    gas_fees: gas_fee_value,
+                    miner,
+                }
+            );
+
+            rewards.reward_number = rewards.reward_number + 1;
+            i = i - 1;
+        }
+    };
+
+    if (!Account::exists_at(current_author)) {
+        Account::create_account_with_address<STC>(current_author);
+    };
+    let current_info = RewardInfo {
+        number: current_number,
+        reward: current_reward,
+        miner: current_author,
+        gas_fees: Token::zero<STC>(),
+    };
+    Vector::push_back(&mut rewards.infos, current_info);
+
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if current_number == 0 && Token::value(previous_block_gas_fees) != 0;
+aborts_if current_number > 0 && !exists<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if current_number > 0 && (global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).reward_number + Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos) + 1) != current_number;
+aborts_if current_number > 0 && !exists<Config::Config<RewardConfig::RewardConfig>>(CoreAddresses::GENESIS_ADDRESS());
+let reward_info_length = Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos);
+aborts_if current_number > 0 && reward_info_length == 0 && Token::value(previous_block_gas_fees) != 0;
+aborts_if current_number > 0 && reward_info_length != 0 && Vector::borrow(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos, reward_info_length - 1).number != current_number - 1;
+aborts_if current_number > 0 && Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos) >= global<Config::Config<RewardConfig::RewardConfig>>(CoreAddresses::GENESIS_ADDRESS()).payload.reward_delay
+&& (global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).reward_number + 1) != Vector::borrow(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos, 0).number;
+aborts_if current_number > 0 && Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos) >= global<Config::Config<RewardConfig::RewardConfig>>(CoreAddresses::GENESIS_ADDRESS()).payload.reward_delay
+        && (global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).reward_number + 1) > max_u64();
+aborts_if current_number > 0 && !Account::exists_at(current_author) ;
+pragma verify = false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/ChainId.md b/release/v13/docs/ChainId.md new file mode 100644 index 00000000..89ab9fd3 --- /dev/null +++ b/release/v13/docs/ChainId.md @@ -0,0 +1,425 @@ + + + +# Module `0x1::ChainId` + +The module provides chain id information. + + +- [Resource `ChainId`](#0x1_ChainId_ChainId) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_ChainId_initialize) +- [Function `get`](#0x1_ChainId_get) +- [Function `is_dev`](#0x1_ChainId_is_dev) +- [Function `is_test`](#0x1_ChainId_is_test) +- [Function `is_halley`](#0x1_ChainId_is_halley) +- [Function `is_proxima`](#0x1_ChainId_is_proxima) +- [Function `is_barnard`](#0x1_ChainId_is_barnard) +- [Function `is_main`](#0x1_ChainId_is_main) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::CoreAddresses;
+use 0x1::Timestamp;
+
+ + + + + +## Resource `ChainId` + +chain id data structure. + + +
struct ChainId has key
+
+ + + +
+Fields + + +
+
+id: u8 +
+
+ real id. +
+
+ + +
+ + + +## Constants + + + + + + +
const BARNARD_CHAIN_ID: u8 = 251;
+
+ + + + + + + +
const DEV_CHAIN_ID: u8 = 254;
+
+ + + + + + + +
const HALLEY_CHAIN_ID: u8 = 253;
+
+ + + + + + + +
const MAIN_CHAIN_ID: u8 = 1;
+
+ + + + + + + +
const PROXIMA_CHAIN_ID: u8 = 252;
+
+ + + + + + + +
const TEST_CHAIN_ID: u8 = 255;
+
+ + + + + +## Function `initialize` + +Publish the chain ID under the genesis account + + +
public fun initialize(account: &signer, id: u8)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, id: u8) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+    move_to(account, ChainId { id });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<ChainId>(Signer::address_of(account));
+ensures exists<ChainId>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `get` + +Return the chain ID of this chain + + +
public fun get(): u8
+
+ + + +
+Implementation + + +
public fun get(): u8 acquires ChainId {
+    borrow_global<ChainId>(CoreAddresses::GENESIS_ADDRESS()).id
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `is_dev` + + + +
public fun is_dev(): bool
+
+ + + +
+Implementation + + +
public fun is_dev(): bool acquires ChainId {
+    get() == DEV_CHAIN_ID
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `is_test` + + + +
public fun is_test(): bool
+
+ + + +
+Implementation + + +
public fun is_test(): bool acquires ChainId {
+    get() == TEST_CHAIN_ID
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `is_halley` + + + +
public fun is_halley(): bool
+
+ + + +
+Implementation + + +
public fun is_halley(): bool acquires ChainId {
+    get() == HALLEY_CHAIN_ID
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `is_proxima` + + + +
public fun is_proxima(): bool
+
+ + + +
+Implementation + + +
public fun is_proxima(): bool acquires ChainId {
+    get() == PROXIMA_CHAIN_ID
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `is_barnard` + + + +
public fun is_barnard(): bool
+
+ + + +
+Implementation + + +
public fun is_barnard(): bool acquires ChainId {
+    get() == BARNARD_CHAIN_ID
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `is_main` + + + +
public fun is_main(): bool
+
+ + + +
+Implementation + + +
public fun is_main(): bool acquires ChainId {
+    get() == MAIN_CHAIN_ID
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+ensures exists<ChainId>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Collection.md b/release/v13/docs/Collection.md new file mode 100644 index 00000000..6716cbb4 --- /dev/null +++ b/release/v13/docs/Collection.md @@ -0,0 +1,430 @@ + + + +# Module `0x1::Collection` + +Deprecated since @v3 please use Collection2 +Provide a account based vector for save resource. + + +- [Struct `Collection`](#0x1_Collection_Collection) +- [Resource `CollectionStore`](#0x1_Collection_CollectionStore) +- [Constants](#@Constants_0) +- [Function `borrow`](#0x1_Collection_borrow) +- [Function `pop_back`](#0x1_Collection_pop_back) +- [Function `exists_at`](#0x1_Collection_exists_at) +- [Function `put`](#0x1_Collection_put) +- [Function `take`](#0x1_Collection_take) +- [Function `borrow_collection`](#0x1_Collection_borrow_collection) +- [Function `return_collection`](#0x1_Collection_return_collection) +- [Function `destroy_empty`](#0x1_Collection_destroy_empty) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Option;
+use 0x1::Signer;
+use 0x1::Vector;
+
+ + + + + +## Struct `Collection` + +Collection in memory, can not drop & store. + + +
struct Collection<T>
+
+ + + +
+Fields + + +
+
+items: vector<T> +
+
+ +
+
+owner: address +
+
+ the owner of Collection. +
+
+ + +
+ + + +## Resource `CollectionStore` + +Collection in global store. + + +
struct CollectionStore<T: store> has key
+
+ + + +
+Fields + + +
+
+items: Option::Option<vector<T>> +
+
+ items in the CollectionStore. + use Option at here is for temporary take away from store to construct Collection. +
+
+ + +
+ + + +## Constants + + + + + + +
const EDEPRECATED_FUNCTION: u64 = 19;
+
+ + + + + + + +
const ECOLLECTION_NOT_EXIST: u64 = 101;
+
+ + + + + +The operator require the collection owner. + + +
const ECOLLECTION_NOT_OWNER: u64 = 102;
+
+ + + + + +## Function `borrow` + +Acquire an immutable reference to the ith element of the collection c. +Aborts if i is out of bounds. + + +
public fun borrow<T>(c: &Collection::Collection<T>, i: u64): &T
+
+ + + +
+Implementation + + +
public fun borrow<T>(c: &Collection<T>, i: u64): &T{
+    Vector::borrow(&c.items, i)
+}
+
+ + + +
+ + + +## Function `pop_back` + +Pop an element from the end of vector v. +Aborts if v is empty. + + +
public fun pop_back<T>(account: &signer, c: &mut Collection::Collection<T>): T
+
+ + + +
+Implementation + + +
public fun pop_back<T>(account: &signer, c: &mut Collection<T>): T {
+    assert!(Signer::address_of(account) == c.owner, Errors::requires_address(ECOLLECTION_NOT_OWNER));
+    Vector::pop_back<T>(&mut c.items)
+}
+
+ + + +
+ + + +## Function `exists_at` + +check the Collection exists in addr + + +
fun exists_at<T: store>(addr: address): bool
+
+ + + +
+Implementation + + +
fun exists_at<T: store>(addr: address): bool{
+    exists<CollectionStore<T>>(addr)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `put` + +Deprecated since @v3 +Put items to account's Collection last position. + + +
public fun put<T: store>(_account: &signer, _item: T)
+
+ + + +
+Implementation + + +
public fun put<T: store>(_account: &signer, _item: T) {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `take` + +Take last item from account's Collection of T. + + +
public fun take<T: store>(account: &signer): T
+
+ + + +
+Implementation + + +
public fun take<T: store>(account: &signer): T acquires CollectionStore{
+    let addr = Signer::address_of(account);
+    let c = borrow_collection<T>(addr);
+    let item = pop_back(account, &mut c);
+    return_collection(c);
+    item
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `borrow_collection` + +Borrow collection of T from addr + + +
public fun borrow_collection<T: store>(addr: address): Collection::Collection<T>
+
+ + + +
+Implementation + + +
public fun borrow_collection<T: store>(addr: address): Collection<T> acquires CollectionStore{
+    assert!(exists_at<T>(addr), Errors::invalid_state(ECOLLECTION_NOT_EXIST));
+    let c = borrow_global_mut<CollectionStore<T>>(addr);
+    let items = Option::extract(&mut c.items);
+    Collection{
+        items,
+        owner: addr
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `return_collection` + +Return the Collection of T + + +
public fun return_collection<T: store>(c: Collection::Collection<T>)
+
+ + + +
+Implementation + + +
public fun return_collection<T: store>(c: Collection<T>) acquires CollectionStore{
+    let Collection{ items, owner } = c;
+    if (Vector::is_empty(&items)) {
+        let c = move_from<CollectionStore<T>>(owner);
+        destroy_empty(c);
+        Vector::destroy_empty(items);
+    }else{
+        let c = borrow_global_mut<CollectionStore<T>>(owner);
+        Option::fill(&mut c.items, items);
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `destroy_empty` + + + +
fun destroy_empty<T: store>(c: Collection::CollectionStore<T>)
+
+ + + +
+Implementation + + +
fun destroy_empty<T: store>(c: CollectionStore<T>){
+    let CollectionStore{ items } = c;
+    Option::destroy_none(items);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = false;
+
diff --git a/release/v13/docs/Collection2.md b/release/v13/docs/Collection2.md new file mode 100644 index 00000000..42e6ff21 --- /dev/null +++ b/release/v13/docs/Collection2.md @@ -0,0 +1,878 @@ + + + +# Module `0x1::Collection2` + +Provide a account based vector for save resource item. +The resource in CollectionStore can borrowed by anyone, anyone can get immutable ref of item. +and the owner of Collection can allow others to add item to Collection or get mut ref from Collection.git + + +- [Struct `Collection`](#0x1_Collection2_Collection) +- [Resource `CollectionStore`](#0x1_Collection2_CollectionStore) +- [Constants](#@Constants_0) +- [Function `length`](#0x1_Collection2_length) +- [Function `borrow`](#0x1_Collection2_borrow) +- [Function `push_back`](#0x1_Collection2_push_back) +- [Function `borrow_mut`](#0x1_Collection2_borrow_mut) +- [Function `pop_back`](#0x1_Collection2_pop_back) +- [Function `remove`](#0x1_Collection2_remove) +- [Function `append`](#0x1_Collection2_append) +- [Function `append_all`](#0x1_Collection2_append_all) +- [Function `exists_at`](#0x1_Collection2_exists_at) +- [Function `is_accept`](#0x1_Collection2_is_accept) +- [Function `accept`](#0x1_Collection2_accept) +- [Function `put`](#0x1_Collection2_put) +- [Function `put_all`](#0x1_Collection2_put_all) +- [Function `take`](#0x1_Collection2_take) +- [Function `create_collection`](#0x1_Collection2_create_collection) +- [Function `length_of`](#0x1_Collection2_length_of) +- [Function `borrow_collection`](#0x1_Collection2_borrow_collection) +- [Function `return_collection`](#0x1_Collection2_return_collection) +- [Function `destroy_collection`](#0x1_Collection2_destroy_collection) +- [Function `destroy_empty`](#0x1_Collection2_destroy_empty) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Option;
+use 0x1::Signer;
+use 0x1::Vector;
+
+ + + + + +## Struct `Collection` + +Collection in memory, can not drop & store. + + +
struct Collection<T>
+
+ + + +
+Fields + + +
+
+items: vector<T> +
+
+ +
+
+owner: address +
+
+ +
+
+can_put: bool +
+
+ +
+
+can_mut: bool +
+
+ +
+
+can_take: bool +
+
+ +
+
+ + +
+ + + +## Resource `CollectionStore` + +Collection in global store. + + +
struct CollectionStore<T: store> has key
+
+ + + +
+Fields + + +
+
+items: Option::Option<vector<T>> +
+
+ items in the CollectionStore. + use Option at here is for temporary take away from store to construct Collection. +
+
+anyone_can_put: bool +
+
+ +
+
+anyone_can_mut: bool +
+
+ +
+
+ + +
+ + + +## Constants + + + + +The operator require the collection owner or collection set anyone_can_put to true. + + +
const ERR_COLLECTION_CAN_NOT_ADD: u64 = 102;
+
+ + + + + +The operator require the collection owner or collection set anyone_can_mut to true. + + +
const ERR_COLLECTION_CAN_NOT_MUT: u64 = 103;
+
+ + + + + +The operator require the collection owner + + +
const ERR_COLLECTION_CAN_NOT_TAKE: u64 = 104;
+
+ + + + + + + +
const ERR_COLLECTION_INVALID_BORROW_STATE: u64 = 105;
+
+ + + + + + + +
const ERR_COLLECTION_IS_NOT_EMPTY: u64 = 106;
+
+ + + + + + + +
const ERR_COLLECTION_NOT_EXIST: u64 = 101;
+
+ + + + + +## Function `length` + +Return the length of the collection. + + +
public fun length<T>(c: &Collection2::Collection<T>): u64
+
+ + + +
+Implementation + + +
public fun length<T>(c: &Collection<T>): u64{
+    Vector::length(&c.items)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `borrow` + +Acquire an immutable reference to the ith element of the collection c. +Aborts if i is out of bounds. + + +
public fun borrow<T>(c: &Collection2::Collection<T>, i: u64): &T
+
+ + + +
+Implementation + + +
public fun borrow<T>(c: &Collection<T>, i: u64): &T{
+    Vector::borrow(&c.items, i)
+}
+
+ + + +
+ + + +## Function `push_back` + +Add item v to the end of the collection c. +require owner of Collection. + + +
public fun push_back<T>(c: &mut Collection2::Collection<T>, t: T)
+
+ + + +
+Implementation + + +
public fun push_back<T>(c: &mut Collection<T>, t: T){
+    assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD));
+    Vector::push_back<T>(&mut c.items, t);
+}
+
+ + + +
+ + + +## Function `borrow_mut` + +Return a mutable reference to the ith item in the Collection c. +Aborts if i is out of bounds. + + +
public fun borrow_mut<T>(c: &mut Collection2::Collection<T>, i: u64): &mut T
+
+ + + +
+Implementation + + +
public fun borrow_mut<T>(c: &mut Collection<T>, i: u64): &mut T{
+    assert!(c.can_mut, Errors::requires_address(ERR_COLLECTION_CAN_NOT_MUT));
+    Vector::borrow_mut<T>(&mut c.items, i)
+}
+
+ + + +
+ + + +## Function `pop_back` + +Pop an element from the end of vector v. +Aborts if v is empty. + + +
public fun pop_back<T>(c: &mut Collection2::Collection<T>): T
+
+ + + +
+Implementation + + +
public fun pop_back<T>(c: &mut Collection<T>): T {
+    assert!(c.can_take, Errors::requires_address(ERR_COLLECTION_CAN_NOT_TAKE));
+    Vector::pop_back<T>(&mut c.items)
+}
+
+ + + +
+ + + +## Function `remove` + + + +
public fun remove<T>(c: &mut Collection2::Collection<T>, i: u64): T
+
+ + + +
+Implementation + + +
public fun remove<T>(c: &mut Collection<T>, i: u64): T{
+    assert!(c.can_take, Errors::requires_address(ERR_COLLECTION_CAN_NOT_TAKE));
+    Vector::remove<T>(&mut c.items, i)
+}
+
+ + + +
+ + + +## Function `append` + + + +
public fun append<T>(c: &mut Collection2::Collection<T>, other: T)
+
+ + + +
+Implementation + + +
public fun append<T>(c: &mut Collection<T>, other: T) {
+    assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD));
+    Vector::append<T>(&mut c.items, Vector::singleton(other))
+}
+
+ + + +
+ + + +## Function `append_all` + + + +
public fun append_all<T>(c: &mut Collection2::Collection<T>, other: vector<T>)
+
+ + + +
+Implementation + + +
public fun append_all<T>(c: &mut Collection<T>, other: vector<T>) {
+    assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD));
+    Vector::append<T>(&mut c.items, other)
+}
+
+ + + +
+ + + +## Function `exists_at` + +check the Collection exists in addr + + +
public fun exists_at<T: store>(addr: address): bool
+
+ + + +
+Implementation + + +
public fun exists_at<T: store>(addr: address): bool{
+    exists<CollectionStore<T>>(addr)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `is_accept` + +check addr is accept T and other can send T to addr, +it means exists a Collection of T at addr and anyone_can_put of the Collection is true + + +
public fun is_accept<T: store>(addr: address): bool
+
+ + + +
+Implementation + + +
public fun is_accept<T: store>(addr: address): bool acquires CollectionStore {
+    if (!exists<CollectionStore<T>>(addr)){
+        return false
+    };
+    let cs = borrow_global<CollectionStore<T>>(addr);
+    cs.anyone_can_put
+}
+
+ + + +
+ + + +## Function `accept` + +signer allow other send T to self +create a Collection of T and set anyone_can_put to true +if the Collection exists, just update anyone_can_put to true + + +
public fun accept<T: store>(signer: &signer)
+
+ + + +
+Implementation + + +
public fun accept<T: store>(signer: &signer) acquires CollectionStore {
+     let addr = Signer::address_of(signer);
+    if (!exists<CollectionStore<T>>(addr)){
+        Self::create_collection<T>(signer, true, false);
+    };
+    let cs = borrow_global_mut<CollectionStore<T>>(addr);
+    if (!cs.anyone_can_put) {
+        cs.anyone_can_put = true;
+    }
+}
+
+ + + +
+ + + +## Function `put` + +Put items to to_addr's Collection of T +put = borrow_collection + append + return_collection. + + +
public fun put<T: store>(signer: &signer, owner: address, item: T)
+
+ + + +
+Implementation + + +
public fun put<T: store>(signer: &signer, owner: address, item: T) acquires CollectionStore{
+    let c = Self::borrow_collection(signer, owner);
+    Self::append(&mut c, item);
+    Self::return_collection(c);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `put_all` + +Put all items to owner's collection of T. + + +
public fun put_all<T: store>(signer: &signer, owner: address, items: vector<T>)
+
+ + + +
+Implementation + + +
public fun put_all<T: store>(signer: &signer, owner: address, items: vector<T>) acquires CollectionStore{
+    let c = Self::borrow_collection(signer, owner);
+    Self::append_all(&mut c, items);
+    Self::return_collection(c);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `take` + +Take last item from signer's Collection of T. + + +
public fun take<T: store>(signer: &signer): T
+
+ + + +
+Implementation + + +
public fun take<T: store>(signer: &signer): T acquires CollectionStore{
+    let addr = Signer::address_of(signer);
+    let c = borrow_collection<T>(signer, addr);
+    let item = pop_back(&mut c);
+    return_collection(c);
+    item
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `create_collection` + + + +
public fun create_collection<T: store>(signer: &signer, anyone_can_put: bool, anyone_can_mut: bool)
+
+ + + +
+Implementation + + +
public fun create_collection<T:store>(signer: &signer, anyone_can_put: bool, anyone_can_mut: bool) {
+    move_to(signer, CollectionStore<T>{items: Option::some(Vector::empty<T>()), anyone_can_put, anyone_can_mut})
+}
+
+ + + +
+ + + +## Function `length_of` + +Return the length of Collection from owner, if collection do not exist, return 0. + + +
public fun length_of<T: store>(owner: address): u64
+
+ + + +
+Implementation + + +
public fun length_of<T: store>(owner: address) : u64 acquires CollectionStore{
+    if (exists_at<T>(owner)){
+        let cs = borrow_global_mut<CollectionStore<T>>(owner);
+        //if items is None, indicate it is borrowed
+        assert!(!Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE));
+        let items = Option::borrow(&cs.items);
+        Vector::length(items)
+    }else{
+        0
+    }
+}
+
+ + + +
+ + + +## Function `borrow_collection` + +Borrow collection of T from owner, auto detected the collection's can_put|can_mut|can_take by the sender and Collection config. + + +
public fun borrow_collection<T: store>(sender: &signer, owner: address): Collection2::Collection<T>
+
+ + + +
+Implementation + + +
public fun borrow_collection<T: store>(sender: &signer, owner: address): Collection<T> acquires CollectionStore{
+    assert!(exists_at<T>(owner), Errors::invalid_state(ERR_COLLECTION_NOT_EXIST));
+    let cs = borrow_global_mut<CollectionStore<T>>(owner);
+    //if items is None, indicate it is borrowed
+    assert!(!Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE));
+    let items = Option::extract(&mut cs.items);
+    let is_owner = owner == Signer::address_of(sender);
+    let can_put = cs.anyone_can_put || is_owner;
+    let can_mut = cs.anyone_can_mut || is_owner;
+    let can_take = is_owner;
+    Collection{
+        items,
+        owner,
+        can_put,
+        can_mut,
+        can_take,
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `return_collection` + +Return the Collection of T + + +
public fun return_collection<T: store>(c: Collection2::Collection<T>)
+
+ + + +
+Implementation + + +
public fun return_collection<T: store>(c: Collection<T>) acquires CollectionStore{
+    let Collection{ items, owner, can_put:_, can_mut:_, can_take:_ } = c;
+    let cs = borrow_global_mut<CollectionStore<T>>(owner);
+    assert!(Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE));
+    Option::fill(&mut cs.items, items);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `destroy_collection` + + + +
public fun destroy_collection<T: store>(signer: &signer)
+
+ + + +
+Implementation + + +
public fun destroy_collection<T: store>(signer: &signer) acquires CollectionStore{
+    let c = move_from<CollectionStore<T>>(Signer::address_of(signer));
+    destroy_empty(c);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `destroy_empty` + + + +
fun destroy_empty<T: store>(c: Collection2::CollectionStore<T>)
+
+ + + +
+Implementation + + +
fun destroy_empty<T: store>(c: CollectionStore<T>){
+    let CollectionStore{ items, anyone_can_put:_, anyone_can_mut:_,} = c;
+    if (Option::is_some(&items)) {
+        let item_vec = Option::extract(&mut items);
+        assert!(Vector::is_empty(&item_vec), Errors::invalid_state(ERR_COLLECTION_IS_NOT_EMPTY));
+        Vector::destroy_empty(item_vec);
+        Option::destroy_none(items);
+    }else{
+        Option::destroy_none(items);
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = false;
+
diff --git a/release/v13/docs/Compare.md b/release/v13/docs/Compare.md new file mode 100644 index 00000000..998884cc --- /dev/null +++ b/release/v13/docs/Compare.md @@ -0,0 +1,340 @@ + + + +# Module `0x1::Compare` + + + +- [Constants](#@Constants_0) +- [Function `cmp_bcs_bytes`](#0x1_Compare_cmp_bcs_bytes) +- [Function `cmp_bytes`](#0x1_Compare_cmp_bytes) +- [Function `cmp_u64`](#0x1_Compare_cmp_u64) +- [Function `is_equal`](#0x1_Compare_is_equal) +- [Function `is_less_than`](#0x1_Compare_is_less_than) +- [Function `is_greater_than`](#0x1_Compare_is_greater_than) +- [Module Specification](#@Module_Specification_1) + + +
+ + + + + +## Constants + + + + + + +
const EQUAL: u8 = 0;
+
+ + + + + + + +
const GREATER_THAN: u8 = 2;
+
+ + + + + + + +
const LESS_THAN: u8 = 1;
+
+ + + + + +## Function `cmp_bcs_bytes` + +Compare v1 and v2 using +(1) byte-by-byte comparison from right to left until we reach the end of the shorter vector, +then +(2) vector length to break ties. +Returns either EQUAL (0u8), LESS_THAN (1u8), or GREATER_THAN (2u8). +This function is designed to compare BCS (Starcoin Canonical Serialization)-encoded values +(i.e., vectors produced by BCS::to_bytes). A typical client will call +Compare::cmp_bcs_bytes(BCS::to_bytes(&t1), BCS::to_bytes(&t2)). The comparison provides the +following guarantees w.r.t the original values t1 and t2: +- cmp_bcs_bytes(bcs_ext(t1), bcs_ext(t2)) == LESS_THAN iff cmp_bcs_bytes(t2, t1) == GREATER_THAN +- Compare::cmp<T>(t1, t2) == EQUAL iff t1 == t2 and (similarly) +Compare::cmp<T>(t1, t2) != EQUAL iff t1 != t2, where == and != denote the Move +bytecode operations for polymorphic equality. +- for all primitive types T with < and > comparison operators exposed in Move bytecode +(u8, u64, u128), we have +compare_bcs_bytes(bcs_ext(t1), bcs_ext(t2)) == LESS_THAN iff t1 < t2 and (similarly) +compare_bcs_bytes(bcs_ext(t1), bcs_ext(t2)) == LESS_THAN iff t1 > t2. +For all other types, the order is whatever the BCS encoding of the type and the comparison +strategy above gives you. One case where the order might be surprising is the address type. +CoreAddresses are 16 byte hex values that BCS encodes with the identity function. The right to +left, byte-by-byte comparison means that (for example) +compare_bcs_bytes(bcs_ext(0x01), bcs_ext(0x10)) == LESS_THAN (as you'd expect), but +compare_bcs_bytes(bcs_ext(0x100), bcs_ext(0x001)) == LESS_THAN (as you probably wouldn't expect). +Keep this in mind when using this function to compare addresses. + + +
public fun cmp_bcs_bytes(v1: &vector<u8>, v2: &vector<u8>): u8
+
+ + + +
+Implementation + + +
public fun cmp_bcs_bytes(v1: &vector<u8>, v2: &vector<u8>): u8 {
+    let i1 = Vector::length(v1);
+    let i2 = Vector::length(v2);
+    let len_cmp = cmp_u64(i1, i2);
+
+    // BCS uses little endian encoding for all integer types, so we choose to compare from left
+    // to right. Going right to left would make the behavior of Compare.cmp diverge from the
+    // bytecode operators < and > on integer values (which would be confusing).
+    while (i1 > 0 && i2 > 0) {
+        i1 = i1 - 1;
+        i2 = i2 - 1;
+        let v1 = *Vector::borrow(v1, i1);
+        let v2 = *Vector::borrow(v2, i2);
+        let elem_cmp = if (v1 == v2) EQUAL
+            else if (v1 < v2) LESS_THAN
+            else GREATER_THAN;
+        if (elem_cmp != 0) return elem_cmp
+        // else, compare next element
+    };
+    // all compared elements equal; use length comparison to break the tie
+    len_cmp
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `cmp_bytes` + + + +
public fun cmp_bytes(v1: &vector<u8>, v2: &vector<u8>): u8
+
+ + + +
+Implementation + + +
public fun cmp_bytes(v1: &vector<u8>, v2: &vector<u8>): u8 {
+    let l1 = Vector::length(v1);
+    let l2 = Vector::length(v2);
+    let len_cmp = cmp_u64(l1, l2);
+    let i = 0;
+    while (i < l1 && i < l2) {
+        let v1 = *Vector::borrow(v1, i);
+        let v2 = *Vector::borrow(v2, i);
+        let elem_cmp = if (v1 == v2) EQUAL
+            else if (v1 < v2) LESS_THAN
+            else GREATER_THAN;
+        if (elem_cmp != 0) {
+            return elem_cmp
+        };
+        // else, compare next element
+        i = i + 1;
+    };
+    // all compared elements equal; use length comparison to break the tie
+    len_cmp
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `cmp_u64` + + + +
fun cmp_u64(i1: u64, i2: u64): u8
+
+ + + +
+Implementation + + +
fun cmp_u64(i1: u64, i2: u64): u8 {
+    if (i1 == i2) EQUAL
+    else if (i1 < i2) LESS_THAN
+    else GREATER_THAN
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `is_equal` + + + +
public fun is_equal(result: u8): bool
+
+ + + +
+Implementation + + +
public fun is_equal(result: u8): bool {
+    result == EQUAL
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `is_less_than` + + + +
public fun is_less_than(result: u8): bool
+
+ + + +
+Implementation + + +
public fun is_less_than(result: u8): bool {
+    result == LESS_THAN
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `is_greater_than` + + + +
public fun is_greater_than(result: u8): bool
+
+ + + +
+Implementation + + +
public fun is_greater_than(result: u8): bool {
+    result == GREATER_THAN
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Config.md b/release/v13/docs/Config.md new file mode 100644 index 00000000..cdffd8bb --- /dev/null +++ b/release/v13/docs/Config.md @@ -0,0 +1,773 @@ + + + +# Module `0x1::Config` + +The module provides a general implmentation of configuration for onchain contracts. + + +- [Resource `Config`](#0x1_Config_Config) +- [Struct `ModifyConfigCapability`](#0x1_Config_ModifyConfigCapability) +- [Resource `ModifyConfigCapabilityHolder`](#0x1_Config_ModifyConfigCapabilityHolder) +- [Struct `ConfigChangeEvent`](#0x1_Config_ConfigChangeEvent) +- [Constants](#@Constants_0) +- [Function `get_by_address`](#0x1_Config_get_by_address) +- [Function `config_exist_by_address`](#0x1_Config_config_exist_by_address) +- [Function `set`](#0x1_Config_set) +- [Function `set_with_capability`](#0x1_Config_set_with_capability) +- [Function `publish_new_config_with_capability`](#0x1_Config_publish_new_config_with_capability) +- [Function `publish_new_config`](#0x1_Config_publish_new_config) +- [Function `extract_modify_config_capability`](#0x1_Config_extract_modify_config_capability) +- [Function `restore_modify_config_capability`](#0x1_Config_restore_modify_config_capability) +- [Function `destroy_modify_config_capability`](#0x1_Config_destroy_modify_config_capability) +- [Function `account_address`](#0x1_Config_account_address) +- [Function `emit_config_change_event`](#0x1_Config_emit_config_change_event) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Option;
+use 0x1::Signer;
+
+ + + + + +## Resource `Config` + +A generic singleton resource that holds a value of a specific type. + + +
struct Config<ConfigValue: copy, drop, store> has key
+
+ + + +
+Fields + + +
+
+payload: ConfigValue +
+
+ +
+
+ + +
+ + + +## Struct `ModifyConfigCapability` + +Accounts with this privilege can modify config of type ConfigValue under account_address + + +
struct ModifyConfigCapability<ConfigValue: copy, drop, store> has store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+events: Event::EventHandle<Config::ConfigChangeEvent<ConfigValue>> +
+
+ +
+
+ + +
+ + + +## Resource `ModifyConfigCapabilityHolder` + +A holder for ModifyConfigCapability, for extraction and restoration of ModifyConfigCapability. + + +
struct ModifyConfigCapabilityHolder<ConfigValue: copy, drop, store> has store, key
+
+ + + +
+Fields + + +
+
+cap: Option::Option<Config::ModifyConfigCapability<ConfigValue>> +
+
+ +
+
+ + +
+ + + +## Struct `ConfigChangeEvent` + +Event emitted when config value is changed. + + +
struct ConfigChangeEvent<ConfigValue: copy, drop, store> has drop, store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+value: ConfigValue +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ECAPABILITY_HOLDER_NOT_EXISTS: u64 = 101;
+
+ + + + + + + +
const ECONFIG_VALUE_DOES_NOT_EXIST: u64 = 13;
+
+ + + + + +## Function `get_by_address` + +Get a copy of ConfigValue value stored under addr. + + +
public fun get_by_address<ConfigValue: copy, drop, store>(addr: address): ConfigValue
+
+ + + +
+Implementation + + +
public fun get_by_address<ConfigValue: copy + drop + store>(addr: address): ConfigValue acquires Config {
+    assert!(exists<Config<ConfigValue>>(addr), Errors::invalid_state(ECONFIG_VALUE_DOES_NOT_EXIST));
+    *&borrow_global<Config<ConfigValue>>(addr).payload
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Config<ConfigValue>>(addr);
+ensures exists<Config<ConfigValue>>(addr);
+ensures result == spec_get<ConfigValue>(addr);
+
+ + + +
+ + + +## Function `config_exist_by_address` + +Check whether the config of ConfigValue type exists under addr. + + +
public fun config_exist_by_address<ConfigValue: copy, drop, store>(addr: address): bool
+
+ + + +
+Implementation + + +
public fun config_exist_by_address<ConfigValue: copy + drop + store>(addr: address): bool {
+    exists<Config<ConfigValue>>(addr)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == exists<Config<ConfigValue>>(addr);
+
+ + + +
+ + + +## Function `set` + +Set a config item to a new value with capability stored under signer + + +
public fun set<ConfigValue: copy, drop, store>(account: &signer, payload: ConfigValue)
+
+ + + +
+Implementation + + +
public fun set<ConfigValue: copy + drop + store>(
+    account: &signer,
+    payload: ConfigValue,
+) acquires Config, ModifyConfigCapabilityHolder {
+    let signer_address = Signer::address_of(account);
+    assert!(
+        exists<ModifyConfigCapabilityHolder<ConfigValue>>(signer_address),
+        Errors::requires_capability(ECAPABILITY_HOLDER_NOT_EXISTS),
+    );
+    let cap_holder = borrow_global_mut<ModifyConfigCapabilityHolder<ConfigValue>>(signer_address);
+    assert!(Option::is_some(&cap_holder.cap), Errors::requires_capability(ECAPABILITY_HOLDER_NOT_EXISTS));
+    set_with_capability(Option::borrow_mut(&mut cap_holder.cap), payload);
+}
+
+ + + +
+ +
+Specification + + + +
let addr = Signer::address_of(account);
+let cap_opt = spec_cap<ConfigValue>(addr);
+let cap = Option::borrow(spec_cap<ConfigValue>(Signer::address_of(account)));
+aborts_if !exists<ModifyConfigCapabilityHolder<ConfigValue>>(addr);
+aborts_if Option::is_none<ModifyConfigCapability<ConfigValue>>(cap_opt);
+ensures exists<ModifyConfigCapabilityHolder<ConfigValue>>(addr);
+pragma aborts_if_is_partial;
+ensures exists<Config<ConfigValue>>(
+    Option::borrow(spec_cap<ConfigValue>(Signer::address_of(account))).account_address,
+);
+ensures global<Config<ConfigValue>>(
+    Option::borrow(spec_cap<ConfigValue>(Signer::address_of(account))).account_address,
+).payload == payload;
+
+ + + + + + + +
fun spec_cap<ConfigValue>(addr: address): Option<ModifyConfigCapability<ConfigValue>> {
+   global<ModifyConfigCapabilityHolder<ConfigValue>>(addr).cap
+}
+
+ + + +
+ + + +## Function `set_with_capability` + +Set a config item to a new value with cap. + + +
public fun set_with_capability<ConfigValue: copy, drop, store>(cap: &mut Config::ModifyConfigCapability<ConfigValue>, payload: ConfigValue)
+
+ + + +
+Implementation + + +
public fun set_with_capability<ConfigValue: copy + drop + store>(
+    cap: &mut ModifyConfigCapability<ConfigValue>,
+    payload: ConfigValue,
+) acquires Config {
+    let addr = cap.account_address;
+    assert!(exists<Config<ConfigValue>>(addr), Errors::invalid_state(ECONFIG_VALUE_DOES_NOT_EXIST));
+    let config = borrow_global_mut<Config<ConfigValue>>(addr);
+    config.payload = copy payload;
+    emit_config_change_event(cap, payload);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Config<ConfigValue>>(cap.account_address);
+ensures exists<Config<ConfigValue>>(cap.account_address);
+ensures global<Config<ConfigValue>>(cap.account_address).payload == payload;
+
+ + + +
+ + + +## Function `publish_new_config_with_capability` + +Publish a new config item. The caller will use the returned ModifyConfigCapability to specify the access control +policy for who can modify the config. + + +
public fun publish_new_config_with_capability<ConfigValue: copy, drop, store>(account: &signer, payload: ConfigValue): Config::ModifyConfigCapability<ConfigValue>
+
+ + + +
+Implementation + + +
public fun publish_new_config_with_capability<ConfigValue: copy + drop + store>(
+    account: &signer,
+    payload: ConfigValue,
+): ModifyConfigCapability<ConfigValue> acquires ModifyConfigCapabilityHolder{
+    publish_new_config<ConfigValue>(account, payload);
+    extract_modify_config_capability<ConfigValue>(account)
+}
+
+ + + +
+ +
+Specification + + + +
include PublishNewConfigAbortsIf<ConfigValue>;
+ensures exists<Config<ConfigValue>>(Signer::address_of(account));
+ensures global<Config<ConfigValue>>(Signer::address_of(account)).payload == payload;
+ensures exists<ModifyConfigCapabilityHolder<ConfigValue>>(Signer::address_of(account));
+ensures Option::is_none(global<ModifyConfigCapabilityHolder<ConfigValue>>(Signer::address_of(account)).cap);
+
+ + + +
+ + + +## Function `publish_new_config` + +Publish a new config item under account address. + + +
public fun publish_new_config<ConfigValue: copy, drop, store>(account: &signer, payload: ConfigValue)
+
+ + + +
+Implementation + + +
public fun publish_new_config<ConfigValue: copy + drop + store>(account: &signer, payload: ConfigValue) {
+    move_to(account, Config<ConfigValue>{ payload });
+    let cap = ModifyConfigCapability<ConfigValue> {
+        account_address: Signer::address_of(account),
+        events: Event::new_event_handle<ConfigChangeEvent<ConfigValue>>(account),
+    };
+    move_to(account, ModifyConfigCapabilityHolder{cap: Option::some(cap)});
+}
+
+ + + +
+ +
+Specification + + + +
include PublishNewConfigAbortsIf<ConfigValue>;
+ensures exists<Config<ConfigValue>>(Signer::address_of(account));
+ensures global<Config<ConfigValue>>(Signer::address_of(account)).payload == payload;
+ensures exists<ModifyConfigCapabilityHolder<ConfigValue>>(Signer::address_of(account));
+ensures Option::is_some(global<ModifyConfigCapabilityHolder<ConfigValue>>(Signer::address_of(account)).cap);
+
+ + + + + + + +
schema PublishNewConfigAbortsIf<ConfigValue> {
+    account: signer;
+    aborts_if exists<Config<ConfigValue>>(Signer::address_of(account));
+    aborts_if exists<ModifyConfigCapabilityHolder<ConfigValue>>(Signer::address_of(account));
+}
+
+ + + + + + + +
schema AbortsIfConfigNotExist<ConfigValue> {
+    addr: address;
+    aborts_if !exists<Config<ConfigValue>>(addr);
+}
+
+ + + + + + + +
schema AbortsIfConfigOrCapabilityNotExist<ConfigValue> {
+    addr: address;
+    aborts_if !exists<Config<ConfigValue>>(addr);
+    aborts_if !exists<ModifyConfigCapabilityHolder<ConfigValue>>(addr);
+}
+
+ + + + + + + +
schema PublishNewConfigEnsures<ConfigValue> {
+    account: signer;
+    ensures exists<Config<ConfigValue>>(Signer::address_of(account));
+    ensures exists<ModifyConfigCapabilityHolder<ConfigValue>>(Signer::address_of(account));
+}
+
+ + + + + + + +
schema AbortsIfCapNotExist<ConfigValue> {
+    address: address;
+    aborts_if !exists<ModifyConfigCapabilityHolder<ConfigValue>>(address);
+    aborts_if Option::is_none<ModifyConfigCapability<ConfigValue>>(
+        global<ModifyConfigCapabilityHolder<ConfigValue>>(address).cap,
+    );
+}
+
+ + + +
+ + + +## Function `extract_modify_config_capability` + +Extract account's ModifyConfigCapability for ConfigValue type + + +
public fun extract_modify_config_capability<ConfigValue: copy, drop, store>(account: &signer): Config::ModifyConfigCapability<ConfigValue>
+
+ + + +
+Implementation + + +
public fun extract_modify_config_capability<ConfigValue: copy + drop + store>(
+    account: &signer,
+): ModifyConfigCapability<ConfigValue> acquires ModifyConfigCapabilityHolder {
+    let signer_address = Signer::address_of(account);
+    assert!(
+        exists<ModifyConfigCapabilityHolder<ConfigValue>>(signer_address),
+        Errors::requires_capability(ECAPABILITY_HOLDER_NOT_EXISTS)
+    );
+    let cap_holder = borrow_global_mut<ModifyConfigCapabilityHolder<ConfigValue>>(signer_address);
+    Option::extract(&mut cap_holder.cap)
+}
+
+ + + +
+ +
+Specification + + + +
let address = Signer::address_of(account);
+include AbortsIfCapNotExist<ConfigValue>;
+ensures exists<ModifyConfigCapabilityHolder<ConfigValue>>(address);
+ensures Option::is_none<ModifyConfigCapability<ConfigValue>>(
+    global<ModifyConfigCapabilityHolder<ConfigValue>>(address).cap
+);
+ensures result == old(Option::borrow(global<ModifyConfigCapabilityHolder<ConfigValue>>(address).cap));
+
+ + + +
+ + + +## Function `restore_modify_config_capability` + +Restore account's ModifyConfigCapability + + +
public fun restore_modify_config_capability<ConfigValue: copy, drop, store>(cap: Config::ModifyConfigCapability<ConfigValue>)
+
+ + + +
+Implementation + + +
public fun restore_modify_config_capability<ConfigValue: copy + drop + store>(
+    cap: ModifyConfigCapability<ConfigValue>,
+) acquires ModifyConfigCapabilityHolder {
+    let cap_holder = borrow_global_mut<ModifyConfigCapabilityHolder<ConfigValue>>(cap.account_address);
+    Option::fill(&mut cap_holder.cap, cap);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ModifyConfigCapabilityHolder<ConfigValue>>(cap.account_address);
+aborts_if Option::is_some(global<ModifyConfigCapabilityHolder<ConfigValue>>(cap.account_address).cap);
+ensures exists<ModifyConfigCapabilityHolder<ConfigValue>>(cap.account_address);
+ensures Option::is_some(global<ModifyConfigCapabilityHolder<ConfigValue>>(cap.account_address).cap);
+ensures Option::borrow(global<ModifyConfigCapabilityHolder<ConfigValue>>(cap.account_address).cap) == cap;
+
+ + + +
+ + + +## Function `destroy_modify_config_capability` + +Destroy the given ModifyConfigCapability + + +
public fun destroy_modify_config_capability<ConfigValue: copy, drop, store>(cap: Config::ModifyConfigCapability<ConfigValue>)
+
+ + + +
+Implementation + + +
public fun destroy_modify_config_capability<ConfigValue: copy + drop + store>(
+    cap: ModifyConfigCapability<ConfigValue>,
+) {
+    let ModifyConfigCapability{account_address:_, events} = cap;
+    Event::destroy_handle(events)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `account_address` + +Return the address of the given ModifyConfigCapability + + +
public fun account_address<ConfigValue: copy, drop, store>(cap: &Config::ModifyConfigCapability<ConfigValue>): address
+
+ + + +
+Implementation + + +
public fun account_address<ConfigValue: copy + drop + store>(cap: &ModifyConfigCapability<ConfigValue>): address {
+    cap.account_address
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == cap.account_address;
+
+ + + +
+ + + +## Function `emit_config_change_event` + +Emit a config change event. + + +
fun emit_config_change_event<ConfigValue: copy, drop, store>(cap: &mut Config::ModifyConfigCapability<ConfigValue>, value: ConfigValue)
+
+ + + +
+Implementation + + +
fun emit_config_change_event<ConfigValue: copy + drop + store>(
+    cap: &mut ModifyConfigCapability<ConfigValue>,
+    value: ConfigValue,
+) {
+    Event::emit_event<ConfigChangeEvent<ConfigValue>>(
+        &mut cap.events,
+        ConfigChangeEvent {
+            account_address: cap.account_address,
+            value,
+        },
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
+ + + + + + + +
fun spec_get<ConfigValue>(addr: address): ConfigValue {
+   global<Config<ConfigValue>>(addr).payload
+}
+
diff --git a/release/v13/docs/ConsensusConfig.md b/release/v13/docs/ConsensusConfig.md new file mode 100644 index 00000000..fc33060d --- /dev/null +++ b/release/v13/docs/ConsensusConfig.md @@ -0,0 +1,700 @@ + + + +# Module `0x1::ConsensusConfig` + +The module provide configuration of consensus parameters. + + +- [Struct `ConsensusConfig`](#0x1_ConsensusConfig_ConsensusConfig) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_ConsensusConfig_initialize) +- [Function `new_consensus_config`](#0x1_ConsensusConfig_new_consensus_config) +- [Function `get_config`](#0x1_ConsensusConfig_get_config) +- [Function `uncle_rate_target`](#0x1_ConsensusConfig_uncle_rate_target) +- [Function `base_block_time_target`](#0x1_ConsensusConfig_base_block_time_target) +- [Function `base_reward_per_block`](#0x1_ConsensusConfig_base_reward_per_block) +- [Function `epoch_block_count`](#0x1_ConsensusConfig_epoch_block_count) +- [Function `base_block_difficulty_window`](#0x1_ConsensusConfig_base_block_difficulty_window) +- [Function `base_reward_per_uncle_percent`](#0x1_ConsensusConfig_base_reward_per_uncle_percent) +- [Function `min_block_time_target`](#0x1_ConsensusConfig_min_block_time_target) +- [Function `max_block_time_target`](#0x1_ConsensusConfig_max_block_time_target) +- [Function `base_max_uncles_per_block`](#0x1_ConsensusConfig_base_max_uncles_per_block) +- [Function `base_block_gas_limit`](#0x1_ConsensusConfig_base_block_gas_limit) +- [Function `strategy`](#0x1_ConsensusConfig_strategy) +- [Function `compute_reward_per_block`](#0x1_ConsensusConfig_compute_reward_per_block) +- [Function `do_compute_reward_per_block`](#0x1_ConsensusConfig_do_compute_reward_per_block) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+use 0x1::Math;
+use 0x1::Timestamp;
+
+ + + + + +## Struct `ConsensusConfig` + +consensus configurations. + + +
struct ConsensusConfig has copy, drop, store
+
+ + + +
+Fields + + +
+
+uncle_rate_target: u64 +
+
+ Uncle block rate per epoch +
+
+base_block_time_target: u64 +
+
+ Average target time to calculate a block's difficulty +
+
+base_reward_per_block: u128 +
+
+ Rewards per block +
+
+base_reward_per_uncle_percent: u64 +
+
+ Percentage of base_reward_per_block to reward a uncle block +
+
+epoch_block_count: u64 +
+
+ Blocks each epoch +
+
+base_block_difficulty_window: u64 +
+
+ How many ancestor blocks which use to calculate next block's difficulty +
+
+min_block_time_target: u64 +
+
+ Minimum target time to calculate a block's difficulty +
+
+max_block_time_target: u64 +
+
+ Maximum target time to calculate a block's difficulty +
+
+base_max_uncles_per_block: u64 +
+
+ Maximum number of uncle block per block +
+
+base_block_gas_limit: u64 +
+
+ Maximum gases per block +
+
+strategy: u8 +
+
+ Strategy to calculate difficulty +
+
+ + +
+ + + +## Constants + + + + + + +
const EINVALID_ARGUMENT: u64 = 18;
+
+ + + + + +## Function `initialize` + +Initialization of the module. + + +
public fun initialize(account: &signer, uncle_rate_target: u64, epoch_block_count: u64, base_block_time_target: u64, base_block_difficulty_window: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8)
+
+ + + +
+Implementation + + +
public fun initialize(
+    account: &signer,
+    uncle_rate_target: u64,
+    epoch_block_count: u64,
+    base_block_time_target: u64,
+    base_block_difficulty_window: u64,
+    base_reward_per_block: u128,
+    base_reward_per_uncle_percent: u64,
+    min_block_time_target: u64,
+    max_block_time_target: u64,
+    base_max_uncles_per_block: u64,
+    base_block_gas_limit: u64,
+    strategy: u8,
+) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+
+    Config::publish_new_config<Self::ConsensusConfig>(
+        account,
+        new_consensus_config(
+            uncle_rate_target,
+            base_block_time_target,
+            base_reward_per_block,
+            base_reward_per_uncle_percent,
+            epoch_block_count,
+            base_block_difficulty_window,
+            min_block_time_target,
+            max_block_time_target,
+            base_max_uncles_per_block,
+            base_block_gas_limit,
+            strategy,
+        ),
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if uncle_rate_target == 0;
+aborts_if epoch_block_count == 0;
+aborts_if base_reward_per_block == 0;
+aborts_if base_block_time_target == 0;
+aborts_if base_block_difficulty_window == 0;
+aborts_if min_block_time_target == 0;
+aborts_if max_block_time_target < min_block_time_target;
+include Config::PublishNewConfigAbortsIf<ConsensusConfig>;
+include Config::PublishNewConfigEnsures<ConsensusConfig>;
+
+ + + +
+ + + +## Function `new_consensus_config` + +Create a new consensus config mainly used in DAO. + + +
public fun new_consensus_config(uncle_rate_target: u64, base_block_time_target: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, epoch_block_count: u64, base_block_difficulty_window: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8): ConsensusConfig::ConsensusConfig
+
+ + + +
+Implementation + + +
public fun new_consensus_config(uncle_rate_target: u64,
+                                base_block_time_target: u64,
+                                base_reward_per_block: u128,
+                                base_reward_per_uncle_percent: u64,
+                                epoch_block_count: u64,
+                                base_block_difficulty_window: u64,
+                                min_block_time_target: u64,
+                                max_block_time_target: u64,
+                                base_max_uncles_per_block: u64,
+                                base_block_gas_limit: u64,
+                                strategy: u8,): ConsensusConfig {
+    assert!(uncle_rate_target > 0, Errors::invalid_argument(EINVALID_ARGUMENT));
+    assert!(base_block_time_target > 0, Errors::invalid_argument(EINVALID_ARGUMENT));
+    assert!(base_reward_per_block > 0, Errors::invalid_argument(EINVALID_ARGUMENT));
+    assert!(epoch_block_count > 0, Errors::invalid_argument(EINVALID_ARGUMENT));
+    assert!(base_block_difficulty_window > 0, Errors::invalid_argument(EINVALID_ARGUMENT));
+    // base_reward_per_uncle_percent can been zero.
+    assert!(min_block_time_target > 0, Errors::invalid_argument(EINVALID_ARGUMENT));
+    assert!(max_block_time_target >= min_block_time_target, Errors::invalid_argument(EINVALID_ARGUMENT));
+
+    ConsensusConfig {
+        uncle_rate_target,
+        base_block_time_target,
+        base_reward_per_block,
+        epoch_block_count,
+        base_block_difficulty_window,
+        base_reward_per_uncle_percent,
+        min_block_time_target,
+        max_block_time_target,
+        base_max_uncles_per_block,
+        base_block_gas_limit,
+        strategy,
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if uncle_rate_target == 0;
+aborts_if epoch_block_count == 0;
+aborts_if base_reward_per_block == 0;
+aborts_if base_block_time_target == 0;
+aborts_if base_block_difficulty_window == 0;
+aborts_if min_block_time_target == 0;
+aborts_if max_block_time_target < min_block_time_target;
+
+ + + +
+ + + +## Function `get_config` + +Get config data. + + +
public fun get_config(): ConsensusConfig::ConsensusConfig
+
+ + + +
+Implementation + + +
public fun get_config(): ConsensusConfig {
+    Config::get_by_address<ConsensusConfig>(CoreAddresses::GENESIS_ADDRESS())
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Config::Config<ConsensusConfig>>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + + + + + +
fun spec_get_config(): ConsensusConfig {
+   global<Config::Config<ConsensusConfig>>(CoreAddresses::GENESIS_ADDRESS()).payload
+}
+
+ + + +
+ + + +## Function `uncle_rate_target` + +Get uncle_rate_target + + +
public fun uncle_rate_target(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun uncle_rate_target(config: &ConsensusConfig): u64 {
+    config.uncle_rate_target
+}
+
+ + + +
+ + + +## Function `base_block_time_target` + +Get base_block_time_target + + +
public fun base_block_time_target(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun base_block_time_target(config: &ConsensusConfig): u64 {
+    config.base_block_time_target
+}
+
+ + + +
+ + + +## Function `base_reward_per_block` + +Get base_reward_per_block + + +
public fun base_reward_per_block(config: &ConsensusConfig::ConsensusConfig): u128
+
+ + + +
+Implementation + + +
public fun base_reward_per_block(config: &ConsensusConfig): u128 {
+    config.base_reward_per_block
+}
+
+ + + +
+ + + +## Function `epoch_block_count` + +Get epoch_block_count + + +
public fun epoch_block_count(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun epoch_block_count(config: &ConsensusConfig): u64 {
+    config.epoch_block_count
+}
+
+ + + +
+ + + +## Function `base_block_difficulty_window` + +Get base_block_difficulty_window + + +
public fun base_block_difficulty_window(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun base_block_difficulty_window(config: &ConsensusConfig): u64 {
+    config.base_block_difficulty_window
+}
+
+ + + +
+ + + +## Function `base_reward_per_uncle_percent` + +Get base_reward_per_uncle_percent + + +
public fun base_reward_per_uncle_percent(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun base_reward_per_uncle_percent(config: &ConsensusConfig): u64 {
+    config.base_reward_per_uncle_percent
+}
+
+ + + +
+ + + +## Function `min_block_time_target` + +Get min_block_time_target + + +
public fun min_block_time_target(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun min_block_time_target(config: &ConsensusConfig): u64 {
+    config.min_block_time_target
+}
+
+ + + +
+ + + +## Function `max_block_time_target` + +Get max_block_time_target + + +
public fun max_block_time_target(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun max_block_time_target(config: &ConsensusConfig): u64 {
+    config.max_block_time_target
+}
+
+ + + +
+ + + +## Function `base_max_uncles_per_block` + +Get base_max_uncles_per_block + + +
public fun base_max_uncles_per_block(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun base_max_uncles_per_block(config: &ConsensusConfig): u64 {
+    config.base_max_uncles_per_block
+}
+
+ + + +
+ + + +## Function `base_block_gas_limit` + +Get base_block_gas_limit + + +
public fun base_block_gas_limit(config: &ConsensusConfig::ConsensusConfig): u64
+
+ + + +
+Implementation + + +
public fun base_block_gas_limit(config: &ConsensusConfig): u64 {
+    config.base_block_gas_limit
+}
+
+ + + +
+ + + +## Function `strategy` + +Get strategy + + +
public fun strategy(config: &ConsensusConfig::ConsensusConfig): u8
+
+ + + +
+Implementation + + +
public fun strategy(config: &ConsensusConfig): u8 {
+    config.strategy
+}
+
+ + + +
+ + + +## Function `compute_reward_per_block` + +Compute block reward given the new_epoch_block_time_target. + + +
public fun compute_reward_per_block(new_epoch_block_time_target: u64): u128
+
+ + + +
+Implementation + + +
public fun compute_reward_per_block(new_epoch_block_time_target: u64): u128 {
+    let config = get_config();
+    do_compute_reward_per_block(&config, new_epoch_block_time_target)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Config::Config<ConsensusConfig>>(CoreAddresses::GENESIS_ADDRESS());
+include Math::MulDivAbortsIf{x: spec_get_config().base_reward_per_block, y: new_epoch_block_time_target, z: spec_get_config().base_block_time_target};
+
+ + + +
+ + + +## Function `do_compute_reward_per_block` + +Compute block reward given the new_epoch_block_time_target, and the consensus config. + + +
public fun do_compute_reward_per_block(config: &ConsensusConfig::ConsensusConfig, new_epoch_block_time_target: u64): u128
+
+ + + +
+Implementation + + +
public fun do_compute_reward_per_block(config: &ConsensusConfig, new_epoch_block_time_target: u64): u128 {
+    Math::mul_div(config.base_reward_per_block, (new_epoch_block_time_target as u128), (config.base_block_time_target as u128))
+}
+
+ + + +
+ +
+Specification + + + +
include Math::MulDivAbortsIf{x: config.base_reward_per_block, y: new_epoch_block_time_target, z: config.base_block_time_target};
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/ConsensusStrategy.md b/release/v13/docs/ConsensusStrategy.md new file mode 100644 index 00000000..f8f72b50 --- /dev/null +++ b/release/v13/docs/ConsensusStrategy.md @@ -0,0 +1,143 @@ + + + +# Module `0x1::ConsensusStrategy` + +The module provides the information of current consensus strategy. + + +- [Struct `ConsensusStrategy`](#0x1_ConsensusStrategy_ConsensusStrategy) +- [Function `initialize`](#0x1_ConsensusStrategy_initialize) +- [Function `get`](#0x1_ConsensusStrategy_get) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::Timestamp;
+
+ + + + + +## Struct `ConsensusStrategy` + +ConsensusStrategy data. + + +
struct ConsensusStrategy has copy, drop, store
+
+ + + +
+Fields + + +
+
+value: u8 +
+
+ Value of strategy +
+
+ + +
+ + + +## Function `initialize` + +Publish the chain ID under the genesis account + + +
public fun initialize(account: &signer, consensus_strategy: u8)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, consensus_strategy: u8) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+    let cap = Config::publish_new_config_with_capability<ConsensusStrategy>(
+        account,
+        ConsensusStrategy { value:consensus_strategy }
+    );
+    //destroy the cap, so ConsensusStrategy can not been change.
+    Config::destroy_modify_config_capability(cap);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<Config::Config<ConsensusStrategy>>(Signer::address_of(account));
+aborts_if exists<Config::ModifyConfigCapabilityHolder<ConsensusStrategy>>(Signer::address_of(account));
+ensures exists<Config::Config<ConsensusStrategy>>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `get` + +Return the consensus strategy type of this chain + + +
public fun get(): u8
+
+ + + +
+Implementation + + +
public fun get(): u8 {
+    Config::get_by_address<ConsensusStrategy>(CoreAddresses::GENESIS_ADDRESS()).value
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Config::Config<ConsensusStrategy>>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/CoreAddresses.md b/release/v13/docs/CoreAddresses.md new file mode 100644 index 00000000..70f433be --- /dev/null +++ b/release/v13/docs/CoreAddresses.md @@ -0,0 +1,178 @@ + + + +# Module `0x1::CoreAddresses` + +The module provide addresses used in stdlib. + + +- [Constants](#@Constants_0) +- [Function `GENESIS_ADDRESS`](#0x1_CoreAddresses_GENESIS_ADDRESS) +- [Function `assert_genesis_address`](#0x1_CoreAddresses_assert_genesis_address) +- [Function `ASSOCIATION_ROOT_ADDRESS`](#0x1_CoreAddresses_ASSOCIATION_ROOT_ADDRESS) +- [Function `VM_RESERVED_ADDRESS`](#0x1_CoreAddresses_VM_RESERVED_ADDRESS) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Signer;
+
+ + + + + +## Constants + + + + + + +
const ENOT_GENESIS_ACCOUNT: u64 = 11;
+
+ + + + + +## Function `GENESIS_ADDRESS` + +The address of the genesis + + +
public fun GENESIS_ADDRESS(): address
+
+ + + +
+Implementation + + +
public fun GENESIS_ADDRESS(): address {
+    @0x1
+}
+
+ + + +
+ + + +## Function `assert_genesis_address` + +Assert signer is genesis. + + +
public fun assert_genesis_address(account: &signer)
+
+ + + +
+Implementation + + +
public fun assert_genesis_address(account: &signer) {
+    assert!(Signer::address_of(account) == GENESIS_ADDRESS(),
+            Errors::requires_address(ENOT_GENESIS_ACCOUNT))
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+include AbortsIfNotGenesisAddress;
+
+ + +Specifies that a function aborts if the account does not have the Diem root address. + + + + + +
schema AbortsIfNotGenesisAddress {
+    account: signer;
+    aborts_if Signer::address_of(account) != GENESIS_ADDRESS();
+}
+
+ + + +
+ + + +## Function `ASSOCIATION_ROOT_ADDRESS` + +The address of the root association account. This account is +created in genesis, and cannot be changed. This address has +ultimate authority over the permissions granted (or removed) from +accounts on-chain. + + +
public fun ASSOCIATION_ROOT_ADDRESS(): address
+
+ + + +
+Implementation + + +
public fun ASSOCIATION_ROOT_ADDRESS(): address {
+    @0xA550C18
+}
+
+ + + +
+ + + +## Function `VM_RESERVED_ADDRESS` + +The reserved address for transactions inserted by the VM into blocks (e.g. +block metadata transactions). Because the transaction is sent from +the VM, an account _cannot_ exist at the 0x0 address since there +is no signer for the transaction. + + +
public fun VM_RESERVED_ADDRESS(): address
+
+ + + +
+Implementation + + +
public fun VM_RESERVED_ADDRESS(): address {
+    @0x0
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Dao.md b/release/v13/docs/Dao.md new file mode 100644 index 00000000..db025649 --- /dev/null +++ b/release/v13/docs/Dao.md @@ -0,0 +1,2330 @@ + + + +# Module `0x1::Dao` + + + +- [Resource `DaoGlobalInfo`](#0x1_Dao_DaoGlobalInfo) +- [Struct `DaoConfig`](#0x1_Dao_DaoConfig) +- [Struct `ProposalCreatedEvent`](#0x1_Dao_ProposalCreatedEvent) +- [Struct `VoteChangedEvent`](#0x1_Dao_VoteChangedEvent) +- [Resource `Proposal`](#0x1_Dao_Proposal) +- [Resource `Vote`](#0x1_Dao_Vote) +- [Constants](#@Constants_0) +- [Function `plugin`](#0x1_Dao_plugin) +- [Function `new_dao_config`](#0x1_Dao_new_dao_config) +- [Function `propose`](#0x1_Dao_propose) +- [Function `cast_vote`](#0x1_Dao_cast_vote) +- [Function `do_cast_vote`](#0x1_Dao_do_cast_vote) +- [Function `change_vote`](#0x1_Dao_change_vote) +- [Function `do_flip_vote`](#0x1_Dao_do_flip_vote) +- [Function `revoke_vote`](#0x1_Dao_revoke_vote) +- [Function `do_revoke_vote`](#0x1_Dao_do_revoke_vote) +- [Function `unstake_votes`](#0x1_Dao_unstake_votes) +- [Function `queue_proposal_action`](#0x1_Dao_queue_proposal_action) +- [Function `extract_proposal_action`](#0x1_Dao_extract_proposal_action) +- [Function `destroy_terminated_proposal`](#0x1_Dao_destroy_terminated_proposal) +- [Function `proposal_exists`](#0x1_Dao_proposal_exists) +- [Function `proposal_state`](#0x1_Dao_proposal_state) +- [Function `do_proposal_state`](#0x1_Dao_do_proposal_state) +- [Function `proposal_info`](#0x1_Dao_proposal_info) +- [Function `vote_of`](#0x1_Dao_vote_of) +- [Function `has_vote`](#0x1_Dao_has_vote) +- [Function `generate_next_proposal_id`](#0x1_Dao_generate_next_proposal_id) +- [Function `voting_delay`](#0x1_Dao_voting_delay) +- [Function `voting_period`](#0x1_Dao_voting_period) +- [Function `quorum_votes`](#0x1_Dao_quorum_votes) +- [Function `voting_quorum_rate`](#0x1_Dao_voting_quorum_rate) +- [Function `min_action_delay`](#0x1_Dao_min_action_delay) +- [Function `get_config`](#0x1_Dao_get_config) +- [Function `modify_dao_config`](#0x1_Dao_modify_dao_config) +- [Function `set_voting_delay`](#0x1_Dao_set_voting_delay) +- [Function `set_voting_period`](#0x1_Dao_set_voting_period) +- [Function `set_voting_quorum_rate`](#0x1_Dao_set_voting_quorum_rate) +- [Function `set_min_action_delay`](#0x1_Dao_set_min_action_delay) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Option;
+use 0x1::Signer;
+use 0x1::Timestamp;
+use 0x1::Token;
+use 0x1::Treasury;
+
+ + + + + +## Resource `DaoGlobalInfo` + +global DAO info of the specified token type Token. + + +
struct DaoGlobalInfo<Token: store> has key
+
+ + + +
+Fields + + +
+
+next_proposal_id: u64 +
+
+ next proposal id. +
+
+proposal_create_event: Event::EventHandle<Dao::ProposalCreatedEvent> +
+
+ proposal creating event. +
+
+vote_changed_event: Event::EventHandle<Dao::VoteChangedEvent> +
+
+ voting event. +
+
+ + +
+ + + +## Struct `DaoConfig` + +Configuration of the Token's DAO. + + +
struct DaoConfig<TokenT: copy, drop, store> has copy, drop, store
+
+ + + +
+Fields + + +
+
+voting_delay: u64 +
+
+ after proposal created, how long use should wait before he can vote (in milliseconds) +
+
+voting_period: u64 +
+
+ how long the voting window is (in milliseconds). +
+
+voting_quorum_rate: u8 +
+
+ the quorum rate to agree on the proposal. + if 50% votes needed, then the voting_quorum_rate should be 50. + it should between (0, 100]. +
+
+min_action_delay: u64 +
+
+ how long the proposal should wait before it can be executed (in milliseconds). +
+
+ + +
+ +
+Specification + + + +
invariant voting_quorum_rate > 0 && voting_quorum_rate <= 100;
+invariant voting_delay > 0;
+invariant voting_period > 0;
+invariant min_action_delay > 0;
+
+ + + +
+ + + +## Struct `ProposalCreatedEvent` + +emitted when proposal created. + + +
struct ProposalCreatedEvent has drop, store
+
+ + + +
+Fields + + +
+
+proposal_id: u64 +
+
+ the proposal id. +
+
+proposer: address +
+
+ proposer is the user who create the proposal. +
+
+ + +
+ + + +## Struct `VoteChangedEvent` + +emitted when user vote/revoke_vote. + + +
struct VoteChangedEvent has drop, store
+
+ + + +
+Fields + + +
+
+proposal_id: u64 +
+
+ the proposal id. +
+
+voter: address +
+
+ the voter. +
+
+proposer: address +
+
+ creator of the proposal. +
+
+agree: bool +
+
+ agree with the proposal or not +
+
+vote: u128 +
+
+ latest vote count of the voter. +
+
+ + +
+ + + +## Resource `Proposal` + +Proposal data struct. + + +
struct Proposal<Token: store, Action: store> has key
+
+ + + +
+Fields + + +
+
+id: u64 +
+
+ id of the proposal +
+
+proposer: address +
+
+ creator of the proposal +
+
+start_time: u64 +
+
+ when voting begins. +
+
+end_time: u64 +
+
+ when voting ends. +
+
+for_votes: u128 +
+
+ count of voters who agree with the proposal +
+
+against_votes: u128 +
+
+ count of voters who're against the proposal +
+
+eta: u64 +
+
+ executable after this time. +
+
+action_delay: u64 +
+
+ after how long, the agreed proposal can be executed. +
+
+quorum_votes: u128 +
+
+ how many votes to reach to make the proposal pass. +
+
+action: Option::Option<Action> +
+
+ proposal action. +
+
+ + +
+ + + +## Resource `Vote` + +User vote info. + + +
struct Vote<TokenT: store> has key
+
+ + + +
+Fields + + +
+
+proposer: address +
+
+ vote for the proposal under the proposer. +
+
+id: u64 +
+
+ proposal id. +
+
+stake: Token::Token<TokenT> +
+
+ how many tokens to stake. +
+
+agree: bool +
+
+ vote for or vote against. +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_NOT_AUTHORIZED: u64 = 1401;
+
+ + + + + + + +
const ACTIVE: u8 = 2;
+
+ + + + + + + +
const AGREED: u8 = 4;
+
+ + + + + + + +
const DEFEATED: u8 = 3;
+
+ + + + + + + +
const ERR_ACTION_DELAY_TOO_SMALL: u64 = 1402;
+
+ + + + + + + +
const ERR_ACTION_MUST_EXIST: u64 = 1409;
+
+ + + + + + + +
const ERR_CONFIG_PARAM_INVALID: u64 = 1407;
+
+ + + + + + + +
const ERR_PROPOSAL_ID_MISMATCH: u64 = 1404;
+
+ + + + + + + +
const ERR_PROPOSAL_STATE_INVALID: u64 = 1403;
+
+ + + + + + + +
const ERR_PROPOSER_MISMATCH: u64 = 1405;
+
+ + + + + + + +
const ERR_QUORUM_RATE_INVALID: u64 = 1406;
+
+ + + + + + + +
const ERR_VOTED_OTHERS_ALREADY: u64 = 1410;
+
+ + + + + + + +
const ERR_VOTE_STATE_MISMATCH: u64 = 1408;
+
+ + + + + + + +
const EXECUTABLE: u8 = 6;
+
+ + + + + + + +
const EXTRACTED: u8 = 7;
+
+ + + + + +Proposal state + + +
const PENDING: u8 = 1;
+
+ + + + + + + +
const QUEUED: u8 = 5;
+
+ + + + + +## Function `plugin` + +plugin function, can only be called by token issuer. +Any token who wants to have gov functionality +can optin this module by call this register function. + + +
public fun plugin<TokenT: copy, drop, store>(signer: &signer, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64)
+
+ + + +
+Implementation + + +
public fun plugin<TokenT: copy + drop + store>(
+    signer: &signer,
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+) {
+    let token_issuer = Token::token_address<TokenT>();
+    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    // let proposal_id = ProposalId {next: 0};
+    let gov_info = DaoGlobalInfo<TokenT> {
+        next_proposal_id: 0,
+        proposal_create_event: Event::new_event_handle<ProposalCreatedEvent>(signer),
+        vote_changed_event: Event::new_event_handle<VoteChangedEvent>(signer),
+    };
+    move_to(signer, gov_info);
+    let config = new_dao_config<TokenT>(
+        voting_delay,
+        voting_period,
+        voting_quorum_rate,
+        min_action_delay,
+    );
+    Config::publish_new_config(signer, config);
+}
+
+ + + +
+ +
+Specification + + + +
let sender = Signer::address_of(signer);
+aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS();
+include NewDaoConfigParamSchema<TokenT>;
+include Config::PublishNewConfigAbortsIf<DaoConfig<TokenT>>{account: signer};
+aborts_if exists<DaoGlobalInfo<TokenT>>(sender);
+
+ + + + + + + +
schema RequirePluginDao<TokenT> {
+    let token_addr = Token::SPEC_TOKEN_TEST_ADDRESS();
+    aborts_if !exists<DaoGlobalInfo<TokenT>>(token_addr);
+    aborts_if !exists<Config::Config<DaoConfig<TokenT>>>(token_addr);
+}
+
+ + + + + + + +
schema AbortIfDaoInfoNotExist<TokenT> {
+    let token_addr = Token::SPEC_TOKEN_TEST_ADDRESS();
+    aborts_if !exists<DaoGlobalInfo<TokenT>>(token_addr);
+}
+
+ + + + + + + +
schema AbortIfDaoConfigNotExist<TokenT> {
+    let token_addr = Token::SPEC_TOKEN_TEST_ADDRESS();
+    aborts_if !exists<Config::Config<DaoConfig<TokenT>>>(token_addr);
+}
+
+ + + + + + + +
schema AbortIfTimestampNotExist {
+    aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+}
+
+ + + + +
apply
+    AbortIfDaoInfoNotExist<TokenT>
+to
+    generate_next_proposal_id<TokenT>;
+apply
+    AbortIfDaoConfigNotExist<TokenT>
+to
+    get_config<TokenT>,
+    voting_delay<TokenT>,
+    voting_period<TokenT>,
+    voting_quorum_rate<TokenT>,
+    min_action_delay<TokenT>,
+    quorum_votes<TokenT>;
+
+ + + +
+ + + +## Function `new_dao_config` + +create a dao config + + +
public fun new_dao_config<TokenT: copy, drop, store>(voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64): Dao::DaoConfig<TokenT>
+
+ + + +
+Implementation + + +
public fun new_dao_config<TokenT: copy + drop + store>(
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+): DaoConfig<TokenT> {
+    assert!(voting_delay > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
+    assert!(voting_period > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
+    assert!(
+        voting_quorum_rate > 0 && voting_quorum_rate <= 100,
+        Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID),
+    );
+    assert!(min_action_delay > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
+    DaoConfig { voting_delay, voting_period, voting_quorum_rate, min_action_delay }
+}
+
+ + + +
+ +
+Specification + + + +
include NewDaoConfigParamSchema<TokenT>;
+
+ + + + + + + +
schema NewDaoConfigParamSchema<TokenT> {
+    voting_delay: u64;
+    voting_period: u64;
+    voting_quorum_rate: u8;
+    min_action_delay: u64;
+    aborts_if voting_delay == 0;
+    aborts_if voting_period == 0;
+    aborts_if voting_quorum_rate == 0 || voting_quorum_rate > 100;
+    aborts_if min_action_delay == 0;
+}
+
+ + + +
+ + + +## Function `propose` + +propose a proposal. +action: the actual action to execute. +action_delay: the delay to execute after the proposal is agreed + + +
public fun propose<TokenT: copy, drop, store, ActionT: copy, drop, store>(signer: &signer, action: ActionT, action_delay: u64)
+
+ + + +
+Implementation + + +
public fun propose<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    signer: &signer,
+    action: ActionT,
+    action_delay: u64,
+) acquires DaoGlobalInfo {
+    if (action_delay == 0) {
+        action_delay = min_action_delay<TokenT>();
+    } else {
+        assert!(action_delay >= min_action_delay<TokenT>(), Errors::invalid_argument(ERR_ACTION_DELAY_TOO_SMALL));
+    };
+    let proposal_id = generate_next_proposal_id<TokenT>();
+    let proposer = Signer::address_of(signer);
+    let start_time = Timestamp::now_milliseconds() + voting_delay<TokenT>();
+    let quorum_votes = quorum_votes<TokenT>();
+    let proposal = Proposal<TokenT, ActionT> {
+        id: proposal_id,
+        proposer,
+        start_time,
+        end_time: start_time + voting_period<TokenT>(),
+        for_votes: 0,
+        against_votes: 0,
+        eta: 0,
+        action_delay,
+        quorum_votes,
+        action: Option::some(action),
+    };
+    move_to(signer, proposal);
+    // emit event
+    let gov_info = borrow_global_mut<DaoGlobalInfo<TokenT>>(Token::token_address<TokenT>());
+    Event::emit_event(
+        &mut gov_info.proposal_create_event,
+        ProposalCreatedEvent { proposal_id, proposer },
+    );
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+let proposer = Signer::address_of(signer);
+include GenerateNextProposalIdSchema<TokenT>;
+pragma addition_overflow_unchecked = true;
+include AbortIfDaoConfigNotExist<TokenT>;
+include AbortIfDaoInfoNotExist<TokenT>;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if action_delay > 0 && action_delay < spec_dao_config<TokenT>().min_action_delay;
+include CheckQuorumVotes<TokenT>;
+let sender = Signer::address_of(signer);
+aborts_if exists<Proposal<TokenT, ActionT>>(sender);
+modifies global<DaoGlobalInfo<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+ensures exists<Proposal<TokenT, ActionT>>(sender);
+
+ + + +
+ + + +## Function `cast_vote` + +votes for a proposal. +User can only vote once, then the stake is locked, +which can only be unstaked by user after the proposal is expired, or cancelled, or executed. +So think twice before casting vote. + + +
public fun cast_vote<TokenT: copy, drop, store, ActionT: copy, drop, store>(signer: &signer, proposer_address: address, proposal_id: u64, stake: Token::Token<TokenT>, agree: bool)
+
+ + + +
+Implementation + + +
public fun cast_vote<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    signer: &signer,
+    proposer_address: address,
+    proposal_id: u64,
+    stake: Token::Token<TokenT>,
+    agree: bool,
+) acquires Proposal, DaoGlobalInfo, Vote {
+    {
+        let state = proposal_state<TokenT, ActionT>(proposer_address, proposal_id);
+        // only when proposal is active, use can cast vote.
+        assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID));
+    };
+    let proposal = borrow_global_mut<Proposal<TokenT, ActionT>>(proposer_address);
+    assert!(proposal.id == proposal_id, Errors::invalid_argument(ERR_PROPOSAL_ID_MISMATCH));
+    let sender = Signer::address_of(signer);
+    let total_voted = if (exists<Vote<TokenT>>(sender)) {
+        let my_vote = borrow_global_mut<Vote<TokenT>>(sender);
+        assert!(my_vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY));
+        assert!(my_vote.agree == agree, Errors::invalid_state(ERR_VOTE_STATE_MISMATCH));
+
+        do_cast_vote(proposal, my_vote, stake);
+        Token::value(&my_vote.stake)
+    } else {
+        let my_vote = Vote<TokenT> {
+            proposer: proposer_address,
+            id: proposal_id,
+            stake: Token::zero(),
+            agree,
+        };
+        do_cast_vote(proposal, &mut my_vote, stake);
+        let total_voted = Token::value(&my_vote.stake);
+        move_to(signer, my_vote);
+        total_voted
+    };
+
+    // emit event
+    let gov_info = borrow_global_mut<DaoGlobalInfo<TokenT>>(Token::token_address<TokenT>());
+    Event::emit_event(
+        &mut gov_info.vote_changed_event,
+        VoteChangedEvent {
+            proposal_id,
+            proposer: proposer_address,
+            voter: sender,
+            agree,
+            vote: total_voted,
+        },
+    );
+}
+
+ + + +
+ +
+Specification + + + +
pragma addition_overflow_unchecked = true;
+include AbortIfDaoInfoNotExist<TokenT>;
+let expected_states = vec(ACTIVE);
+include CheckProposalStates<TokenT, ActionT> {expected_states};
+let sender = Signer::address_of(signer);
+let vote_exists = exists<Vote<TokenT>>(sender);
+include vote_exists ==> CheckVoteOnCast<TokenT, ActionT> {
+    voter: sender,
+    proposal_id: proposal_id,
+    agree: agree,
+    stake_value: stake.value,
+};
+modifies global<Proposal<TokenT, ActionT>>(proposer_address);
+ensures !vote_exists ==> global<Vote<TokenT>>(sender).stake.value == stake.value;
+
+ + + +
+ + + +## Function `do_cast_vote` + + + +
fun do_cast_vote<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposal: &mut Dao::Proposal<TokenT, ActionT>, vote: &mut Dao::Vote<TokenT>, stake: Token::Token<TokenT>)
+
+ + + +
+Implementation + + +
fun do_cast_vote<TokenT: copy + drop + store, ActionT: copy + drop + store>(proposal: &mut Proposal<TokenT, ActionT>, vote: &mut Vote<TokenT>, stake: Token::Token<TokenT>) {
+    let stake_value = Token::value(&stake);
+    Token::deposit(&mut vote.stake, stake);
+    if (vote.agree) {
+        proposal.for_votes = proposal.for_votes + stake_value;
+    } else {
+        proposal.against_votes = proposal.against_votes + stake_value;
+    };
+}
+
+ + + +
+ +
+Specification + + + +
pragma addition_overflow_unchecked = true;
+aborts_if vote.stake.value + stake.value > MAX_U128;
+ensures vote.stake.value == old(vote).stake.value + stake.value;
+ensures vote.agree ==> old(proposal).for_votes + stake.value == proposal.for_votes;
+ensures vote.agree ==> old(proposal).against_votes == proposal.against_votes;
+ensures !vote.agree ==> old(proposal).against_votes + stake.value == proposal.against_votes;
+ensures !vote.agree ==> old(proposal).for_votes == proposal.for_votes;
+
+ + + +
+ + + +## Function `change_vote` + +Let user change their vote during the voting time. + + +
public fun change_vote<TokenT: copy, drop, store, ActionT: copy, drop, store>(signer: &signer, proposer_address: address, proposal_id: u64, agree: bool)
+
+ + + +
+Implementation + + +
public fun change_vote<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    signer: &signer,
+    proposer_address: address,
+    proposal_id: u64,
+    agree: bool,
+) acquires Proposal, DaoGlobalInfo, Vote {
+    {
+        let state = proposal_state<TokenT, ActionT>(proposer_address, proposal_id);
+        // only when proposal is active, user can change vote.
+        assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID));
+    };
+    let proposal = borrow_global_mut<Proposal<TokenT, ActionT>>(proposer_address);
+    assert!(proposal.id == proposal_id, Errors::invalid_argument(ERR_PROPOSAL_ID_MISMATCH));
+    let my_vote = borrow_global_mut<Vote<TokenT>>(Signer::address_of(signer));
+    {
+        assert!(my_vote.proposer == proposer_address, Errors::invalid_argument(ERR_PROPOSER_MISMATCH));
+        assert!(my_vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY));
+    };
+
+    // flip the vote
+    if (my_vote.agree != agree) {
+        let total_voted = do_flip_vote(my_vote, proposal);
+        // emit event
+        let gov_info = borrow_global_mut<DaoGlobalInfo<TokenT>>(Token::token_address<TokenT>());
+        Event::emit_event(
+            &mut gov_info.vote_changed_event,
+            VoteChangedEvent {
+                proposal_id,
+                proposer: proposer_address,
+                voter: Signer::address_of(signer),
+                agree,
+                vote: total_voted,
+            },
+        );
+    };
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+let expected_states = vec(ACTIVE);
+include CheckProposalStates<TokenT, ActionT>{expected_states};
+let sender = Signer::address_of(signer);
+aborts_if !exists<Vote<TokenT>>(sender);
+let vote = global<Vote<TokenT>>(sender);
+include CheckVoteOnProposal<TokenT>{vote, proposer_address, proposal_id};
+include vote.agree != agree ==> CheckChangeVote<TokenT, ActionT>{vote, proposer_address};
+ensures vote.agree != agree ==> vote.agree == agree;
+
+ + + +
+ + + +## Function `do_flip_vote` + + + +
fun do_flip_vote<TokenT: copy, drop, store, ActionT: copy, drop, store>(my_vote: &mut Dao::Vote<TokenT>, proposal: &mut Dao::Proposal<TokenT, ActionT>): u128
+
+ + + +
+Implementation + + +
fun do_flip_vote<TokenT: copy + drop + store, ActionT: copy + drop + store>(my_vote: &mut Vote<TokenT>, proposal: &mut Proposal<TokenT, ActionT>): u128 {
+    my_vote.agree = !my_vote.agree;
+    let total_voted = Token::value(&my_vote.stake);
+    if (my_vote.agree) {
+        proposal.for_votes = proposal.for_votes + total_voted;
+        proposal.against_votes = proposal.against_votes - total_voted;
+    } else {
+        proposal.for_votes = proposal.for_votes - total_voted;
+        proposal.against_votes = proposal.against_votes + total_voted;
+    };
+    total_voted
+}
+
+ + + +
+ +
+Specification + + + +
include CheckFlipVote<TokenT, ActionT>;
+ensures my_vote.agree == !old(my_vote).agree;
+
+ + + +
+ + + +## Function `revoke_vote` + +Revoke some voting powers from vote on proposal_id of proposer_address. + + +
public fun revoke_vote<TokenT: copy, drop, store, ActionT: copy, drop, store>(signer: &signer, proposer_address: address, proposal_id: u64, voting_power: u128): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
public fun revoke_vote<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    signer: &signer,
+    proposer_address: address,
+    proposal_id: u64,
+    voting_power: u128,
+): Token::Token<TokenT> acquires Proposal, Vote, DaoGlobalInfo {
+    {
+        let state = proposal_state<TokenT, ActionT>(proposer_address, proposal_id);
+        // only when proposal is active, user can revoke vote.
+        assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID));
+    };
+    // get proposal
+    let proposal = borrow_global_mut<Proposal<TokenT, ActionT>>(proposer_address);
+
+    // get vote
+    let my_vote = move_from<Vote<TokenT>>(Signer::address_of(signer));
+    {
+        assert!(my_vote.proposer == proposer_address, Errors::invalid_argument(ERR_PROPOSER_MISMATCH));
+        assert!(my_vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY));
+    };
+    // revoke vote on proposal
+    let reverted_stake =do_revoke_vote(proposal, &mut my_vote, voting_power);
+    // emit vote changed event
+    let gov_info = borrow_global_mut<DaoGlobalInfo<TokenT>>(Token::token_address<TokenT>());
+    Event::emit_event(
+        &mut gov_info.vote_changed_event,
+        VoteChangedEvent {
+            proposal_id,
+            proposer: proposer_address,
+            voter: Signer::address_of(signer),
+            agree: my_vote.agree,
+            vote: Token::value(&my_vote.stake),
+        },
+    );
+
+    // if user has no stake, destroy his vote. resolve https://github.com/starcoinorg/starcoin/issues/2925.
+    if (Token::value(&my_vote.stake) == 0u128) {
+        let Vote {stake, proposer: _, id: _, agree: _} = my_vote;
+        Token::destroy_zero(stake);
+    } else {
+        move_to(signer, my_vote);
+    };
+
+    reverted_stake
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+include AbortIfDaoInfoNotExist<TokenT>;
+let expected_states = vec(ACTIVE);
+include CheckProposalStates<TokenT, ActionT> {expected_states};
+let sender = Signer::address_of(signer);
+aborts_if !exists<Vote<TokenT>>(sender);
+let vote = global<Vote<TokenT>>(sender);
+include CheckVoteOnProposal<TokenT> {vote, proposer_address, proposal_id};
+include CheckRevokeVote<TokenT, ActionT> {
+    vote,
+    proposal: global<Proposal<TokenT, ActionT>>(proposer_address),
+    to_revoke: voting_power,
+};
+modifies global<Vote<TokenT>>(sender);
+modifies global<Proposal<TokenT, ActionT>>(proposer_address);
+modifies global<DaoGlobalInfo<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+ensures global<Vote<TokenT>>(sender).stake.value + result.value == old(global<Vote<TokenT>>(sender)).stake.value;
+ensures result.value == voting_power;
+
+ + + +
+ + + +## Function `do_revoke_vote` + + + +
fun do_revoke_vote<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposal: &mut Dao::Proposal<TokenT, ActionT>, vote: &mut Dao::Vote<TokenT>, to_revoke: u128): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
fun do_revoke_vote<TokenT: copy + drop + store, ActionT: copy + drop + store>(proposal: &mut Proposal<TokenT, ActionT>, vote: &mut Vote<TokenT>, to_revoke: u128): Token::Token<TokenT> {
+    spec {
+        assume vote.stake.value >= to_revoke;
+    };
+    let reverted_stake = Token::withdraw(&mut vote.stake, to_revoke);
+    if (vote.agree) {
+        proposal.for_votes = proposal.for_votes - to_revoke;
+    } else {
+        proposal.against_votes = proposal.against_votes - to_revoke;
+    };
+    spec {
+        assert Token::value(reverted_stake) == to_revoke;
+    };
+    reverted_stake
+}
+
+ + + +
+ +
+Specification + + + +
include CheckRevokeVote<TokenT, ActionT>;
+ensures vote.agree ==> old(proposal).for_votes == proposal.for_votes + to_revoke;
+ensures !vote.agree ==> old(proposal).against_votes == proposal.against_votes + to_revoke;
+ensures result.value == to_revoke;
+
+ + + +
+ + + +## Function `unstake_votes` + +Retrieve back my staked token voted for a proposal. + + +
public fun unstake_votes<TokenT: copy, drop, store, ActionT: copy, drop, store>(signer: &signer, proposer_address: address, proposal_id: u64): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
public fun unstake_votes<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    signer: &signer,
+    proposer_address: address,
+    proposal_id: u64,
+): Token::Token<TokenT> acquires Proposal, Vote {
+    // only check state when proposal exists.
+    // because proposal can be destroyed after it ends in DEFEATED or EXTRACTED state.
+    if (proposal_exists<TokenT, ActionT>(proposer_address, proposal_id)) {
+        let state = proposal_state<TokenT, ActionT>(proposer_address, proposal_id);
+        // Only after vote period end, user can unstake his votes.
+        assert!(state > ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID));
+    };
+    let Vote { proposer, id, stake, agree: _ } = move_from<Vote<TokenT>>(
+        Signer::address_of(signer),
+    );
+    // these checks are still required.
+    assert!(proposer == proposer_address, Errors::requires_address(ERR_PROPOSER_MISMATCH));
+    assert!(id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY));
+    stake
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+let expected_states = vec(DEFEATED);
+let expected_states1 = concat(expected_states,vec(AGREED));
+let expected_states2 = concat(expected_states1,vec(QUEUED));
+let expected_states3 = concat(expected_states2,vec(EXECUTABLE));
+let expected_states4 = concat(expected_states3,vec(EXTRACTED));
+aborts_if expected_states4[0] != DEFEATED;
+aborts_if expected_states4[1] != AGREED;
+aborts_if expected_states4[2] != QUEUED;
+aborts_if expected_states4[3] != EXECUTABLE;
+aborts_if expected_states4[4] != EXTRACTED;
+include spec_proposal_exists<TokenT, ActionT>(proposer_address, proposal_id) ==>
+            CheckProposalStates<TokenT, ActionT>{expected_states: expected_states4};
+let sender = Signer::address_of(signer);
+aborts_if !exists<Vote<TokenT>>(sender);
+let vote = global<Vote<TokenT>>(sender);
+include CheckVoteOnProposal<TokenT>{vote, proposer_address, proposal_id};
+ensures !exists<Vote<TokenT>>(sender);
+ensures result.value == old(vote).stake.value;
+
+ + + +
+ + + +## Function `queue_proposal_action` + +queue agreed proposal to execute. + + +
public entry fun queue_proposal_action<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun queue_proposal_action<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+) acquires Proposal {
+    // Only agreed proposal can be submitted.
+    assert!(
+        proposal_state<TokenT, ActionT>(proposer_address, proposal_id) == AGREED,
+        Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID)
+    );
+    let proposal = borrow_global_mut<Proposal<TokenT, ActionT>>(proposer_address);
+    proposal.eta = Timestamp::now_milliseconds() + proposal.action_delay;
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+let expected_states = vec(AGREED);
+include CheckProposalStates<TokenT, ActionT>{expected_states};
+let proposal = global<Proposal<TokenT, ActionT>>(proposer_address);
+aborts_if Timestamp::spec_now_millseconds() + proposal.action_delay > MAX_U64;
+ensures proposal.eta >= Timestamp::spec_now_millseconds();
+
+ + + +
+ + + +## Function `extract_proposal_action` + +extract proposal action to execute. + + +
public fun extract_proposal_action<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposer_address: address, proposal_id: u64): ActionT
+
+ + + +
+Implementation + + +
public fun extract_proposal_action<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+): ActionT acquires Proposal {
+    // Only executable proposal's action can be extracted.
+    assert!(
+        proposal_state<TokenT, ActionT>(proposer_address, proposal_id) == EXECUTABLE,
+        Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID),
+    );
+    let proposal = borrow_global_mut<Proposal<TokenT, ActionT>>(proposer_address);
+    let action: ActionT = Option::extract(&mut proposal.action);
+    action
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+let expected_states = vec(EXECUTABLE);
+include CheckProposalStates<TokenT, ActionT>{expected_states};
+modifies global<Proposal<TokenT, ActionT>>(proposer_address);
+ensures Option::is_none(global<Proposal<TokenT, ActionT>>(proposer_address).action);
+
+ + + +
+ + + +## Function `destroy_terminated_proposal` + +remove terminated proposal from proposer + + +
public entry fun destroy_terminated_proposal<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun destroy_terminated_proposal<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+) acquires Proposal {
+    let proposal_state = proposal_state<TokenT, ActionT>(proposer_address, proposal_id);
+    assert!(
+        proposal_state == DEFEATED || proposal_state == EXTRACTED,
+        Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID),
+    );
+    let Proposal {
+        id: _,
+        proposer: _,
+        start_time: _,
+        end_time: _,
+        for_votes: _,
+        against_votes: _,
+        eta: _,
+        action_delay: _,
+        quorum_votes: _,
+        action,
+    } = move_from<Proposal<TokenT, ActionT>>(proposer_address);
+    if (proposal_state == DEFEATED) {
+        let _ = Option::extract(&mut action);
+    };
+    Option::destroy_none(action);
+}
+
+ + + +
+ +
+Specification + + + +
let expected_states = concat(vec(DEFEATED), vec(EXTRACTED));
+aborts_if len(expected_states) != 2;
+aborts_if expected_states[0] != DEFEATED;
+aborts_if expected_states[1] != EXTRACTED;
+aborts_if !exists<Proposal<TokenT, ActionT>>(proposer_address);
+let proposal = global<Proposal<TokenT, ActionT>>(proposer_address);
+aborts_if proposal.id != proposal_id;
+include AbortIfTimestampNotExist;
+let current_time = Timestamp::spec_now_millseconds();
+let state = do_proposal_state(proposal, current_time);
+aborts_if (forall s in expected_states : s != state);
+aborts_if state == DEFEATED && Option::is_none(global<Proposal<TokenT, ActionT>>(proposer_address).action);
+aborts_if state == EXTRACTED && Option::is_some(global<Proposal<TokenT, ActionT>>(proposer_address).action);
+modifies global<Proposal<TokenT, ActionT>>(proposer_address);
+
+ + + +
+ + + +## Function `proposal_exists` + +check whether a proposal exists in proposer_address with id proposal_id. + + +
public fun proposal_exists<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposer_address: address, proposal_id: u64): bool
+
+ + + +
+Implementation + + +
public fun proposal_exists<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+): bool acquires Proposal {
+    if (exists<Proposal<TokenT, ActionT>>(proposer_address)) {
+        let proposal = borrow_global<Proposal<TokenT, ActionT>>(proposer_address);
+        return proposal.id == proposal_id
+    };
+    false
+}
+
+ + + +
+ +
+Specification + + + +
ensures exists<Proposal<TokenT, ActionT>>(proposer_address) &&
+            borrow_global<Proposal<TokenT, ActionT>>(proposer_address).id == proposal_id ==>
+            result;
+
+ + + + + + + +
fun spec_proposal_exists<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+   proposer_address: address,
+   proposal_id: u64,
+): bool {
+   if (exists<Proposal<TokenT, ActionT>>(proposer_address)) {
+       let proposal = global<Proposal<TokenT, ActionT>>(proposer_address);
+       proposal.id == proposal_id
+   } else {
+       false
+   }
+}
+
+ + + +
+ + + +## Function `proposal_state` + +Get the proposal state. + + +
public fun proposal_state<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposer_address: address, proposal_id: u64): u8
+
+ + + +
+Implementation + + +
public fun proposal_state<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+): u8 acquires Proposal {
+    let proposal = borrow_global<Proposal<TokenT, ActionT>>(proposer_address);
+    assert!(proposal.id == proposal_id, Errors::invalid_argument(ERR_PROPOSAL_ID_MISMATCH));
+    let current_time = Timestamp::now_milliseconds();
+    do_proposal_state(proposal, current_time)
+}
+
+ + + +
+ +
+Specification + + + +
include AbortIfTimestampNotExist;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if !exists<Proposal<TokenT, ActionT>>(proposer_address);
+let proposal = global<Proposal<TokenT, ActionT>>(proposer_address);
+aborts_if proposal.id != proposal_id;
+
+ + + +
+ + + +## Function `do_proposal_state` + + + +
fun do_proposal_state<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposal: &Dao::Proposal<TokenT, ActionT>, current_time: u64): u8
+
+ + + +
+Implementation + + +
fun do_proposal_state<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    proposal: &Proposal<TokenT, ActionT>,
+    current_time: u64,
+): u8 {
+    if (current_time < proposal.start_time) {
+        // Pending
+        PENDING
+    } else if (current_time <= proposal.end_time) {
+        // Active
+        ACTIVE
+    } else if (proposal.for_votes <= proposal.against_votes ||
+        proposal.for_votes < proposal.quorum_votes) {
+        // Defeated
+        DEFEATED
+    } else if (proposal.eta == 0) {
+        // Agreed.
+        AGREED
+    } else if (current_time < proposal.eta) {
+        // Queued, waiting to execute
+        QUEUED
+    } else if (Option::is_some(&proposal.action)) {
+        EXECUTABLE
+    } else {
+        EXTRACTED
+    }
+}
+
+ + + +
+ + + +## Function `proposal_info` + +get proposal's information. +return: (id, start_time, end_time, for_votes, against_votes). + + +
public fun proposal_info<TokenT: copy, drop, store, ActionT: copy, drop, store>(proposer_address: address): (u64, u64, u64, u128, u128)
+
+ + + +
+Implementation + + +
public fun proposal_info<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    proposer_address: address,
+): (u64, u64, u64, u128, u128) acquires Proposal {
+    let proposal = borrow_global<Proposal<TokenT, ActionT>>(proposer_address);
+    (proposal.id, proposal.start_time, proposal.end_time, proposal.for_votes, proposal.against_votes)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Proposal<TokenT, ActionT>>(proposer_address);
+
+ + + +
+ + + +## Function `vote_of` + +Get voter's vote info on proposal with proposal_id of proposer_address. + + +
public fun vote_of<TokenT: copy, drop, store>(voter: address, proposer_address: address, proposal_id: u64): (bool, u128)
+
+ + + +
+Implementation + + +
public fun vote_of<TokenT: copy + drop + store>(
+    voter: address,
+    proposer_address: address,
+    proposal_id: u64,
+): (bool, u128) acquires Vote {
+    let vote = borrow_global<Vote<TokenT>>(voter);
+    assert!(vote.proposer == proposer_address, Errors::requires_address(ERR_PROPOSER_MISMATCH));
+    assert!(vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY));
+    (vote.agree, Token::value(&vote.stake))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Vote<TokenT>>(voter);
+let vote = global<Vote<TokenT>>(voter);
+include CheckVoteOnProposal<TokenT>{vote, proposer_address, proposal_id};
+
+ + + +
+ + + +## Function `has_vote` + +Check whether voter has voted on proposal with proposal_id of proposer_address. + + +
public fun has_vote<TokenT: copy, drop, store>(voter: address, proposer_address: address, proposal_id: u64): bool
+
+ + + +
+Implementation + + +
public fun has_vote<TokenT: copy + drop + store>(
+    voter: address,
+    proposer_address: address,
+    proposal_id: u64,
+): bool acquires Vote {
+    if (!exists<Vote<TokenT>>(voter)) {
+        return false
+    };
+
+    let vote = borrow_global<Vote<TokenT>>(voter);
+    vote.proposer == proposer_address && vote.id == proposal_id
+}
+
+ + + +
+ + + +## Function `generate_next_proposal_id` + + + +
fun generate_next_proposal_id<TokenT: store>(): u64
+
+ + + +
+Implementation + + +
fun generate_next_proposal_id<TokenT: store>(): u64 acquires DaoGlobalInfo {
+    let gov_info = borrow_global_mut<DaoGlobalInfo<TokenT>>(Token::token_address<TokenT>());
+    let proposal_id = gov_info.next_proposal_id;
+    gov_info.next_proposal_id = proposal_id + 1;
+    proposal_id
+}
+
+ + + +
+ +
+Specification + + + +
include GenerateNextProposalIdSchema<TokenT>;
+ensures result == old(global<DaoGlobalInfo<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id);
+
+ + + + + + + +
schema GenerateNextProposalIdSchema<TokenT> {
+    aborts_if global<DaoGlobalInfo<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id >= MAX_U64;
+    modifies global<DaoGlobalInfo<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+    ensures
+        global<DaoGlobalInfo<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id ==
+        old(global<DaoGlobalInfo<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id) + 1;
+}
+
+ + + +
+ + + +## Function `voting_delay` + +get default voting delay of the DAO. + + +
public fun voting_delay<TokenT: copy, drop, store>(): u64
+
+ + + +
+Implementation + + +
public fun voting_delay<TokenT: copy + drop + store>(): u64 {
+    get_config<TokenT>().voting_delay
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `voting_period` + +get the default voting period of the DAO. + + +
public fun voting_period<TokenT: copy, drop, store>(): u64
+
+ + + +
+Implementation + + +
public fun voting_period<TokenT: copy + drop + store>(): u64 {
+    get_config<TokenT>().voting_period
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `quorum_votes` + +Quorum votes to make proposal pass. + + +
public fun quorum_votes<TokenT: copy, drop, store>(): u128
+
+ + + +
+Implementation + + +
public fun quorum_votes<TokenT: copy + drop + store>(): u128 {
+    let market_cap = Token::market_cap<TokenT>();
+    let balance_in_treasury = Treasury::balance<TokenT>();
+    let supply = market_cap - balance_in_treasury;
+    let rate = voting_quorum_rate<TokenT>();
+    let rate = (rate as u128);
+    supply * rate / 100
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+include CheckQuorumVotes<TokenT>;
+
+ + + + + + + +
fun spec_quorum_votes<TokenT: copy + drop + store>(): u128 {
+   let supply = Token::spec_abstract_total_value<TokenT>() - Treasury::spec_balance<TokenT>();
+   supply * spec_dao_config<TokenT>().voting_quorum_rate / 100
+}
+
+ + + +
+ + + +## Function `voting_quorum_rate` + +Get the quorum rate in percent. + + +
public fun voting_quorum_rate<TokenT: copy, drop, store>(): u8
+
+ + + +
+Implementation + + +
public fun voting_quorum_rate<TokenT: copy + drop + store>(): u8 {
+    get_config<TokenT>().voting_quorum_rate
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == global<Config::Config<DaoConfig<TokenT>>>((Token::SPEC_TOKEN_TEST_ADDRESS())).payload.voting_quorum_rate;
+
+ + + +
+ + + +## Function `min_action_delay` + +Get the min_action_delay of the DAO. + + +
public fun min_action_delay<TokenT: copy, drop, store>(): u64
+
+ + + +
+Implementation + + +
public fun min_action_delay<TokenT: copy + drop + store>(): u64 {
+    get_config<TokenT>().min_action_delay
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == spec_dao_config<TokenT>().min_action_delay;
+
+ + + +
+ + + +## Function `get_config` + + + +
fun get_config<TokenT: copy, drop, store>(): Dao::DaoConfig<TokenT>
+
+ + + +
+Implementation + + +
fun get_config<TokenT: copy + drop + store>(): DaoConfig<TokenT> {
+    let token_issuer = Token::token_address<TokenT>();
+    Config::get_by_address<DaoConfig<TokenT>>(token_issuer)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == global<Config::Config<DaoConfig<TokenT>>>(Token::SPEC_TOKEN_TEST_ADDRESS()).payload;
+
+ + + + + + + +
fun spec_dao_config<TokenT: copy + drop + store>(): DaoConfig<TokenT> {
+   global<Config::Config<DaoConfig<TokenT>>>((Token::SPEC_TOKEN_TEST_ADDRESS())).payload
+}
+
+ + + + + + + +
schema CheckModifyConfigWithCap<TokenT> {
+    cap: Config::ModifyConfigCapability<DaoConfig<TokenT>>;
+    aborts_if cap.account_address != Token::SPEC_TOKEN_TEST_ADDRESS();
+    aborts_if !exists<Config::Config<DaoConfig<TokenT>>>(cap.account_address);
+}
+
+ + + +
+ + + +## Function `modify_dao_config` + +update function, modify dao config. +if any param is 0, it means no change to that param. + + +
public fun modify_dao_config<TokenT: copy, drop, store>(cap: &mut Config::ModifyConfigCapability<Dao::DaoConfig<TokenT>>, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64)
+
+ + + +
+Implementation + + +
public fun modify_dao_config<TokenT: copy + drop + store>(
+    cap: &mut Config::ModifyConfigCapability<DaoConfig<TokenT>>,
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+) {
+    assert!(Config::account_address(cap) == Token::token_address<TokenT>(), Errors::invalid_argument(ERR_NOT_AUTHORIZED));
+    let config = get_config<TokenT>();
+    if (voting_period > 0) {
+        config.voting_period = voting_period;
+    };
+    if (voting_delay > 0) {
+        config.voting_delay = voting_delay;
+    };
+    if (voting_quorum_rate > 0) {
+        assert!(voting_quorum_rate <= 100, Errors::invalid_argument(ERR_QUORUM_RATE_INVALID));
+        config.voting_quorum_rate = voting_quorum_rate;
+    };
+    if (min_action_delay > 0) {
+        config.min_action_delay = min_action_delay;
+    };
+    Config::set_with_capability<DaoConfig<TokenT>>(cap, config);
+}
+
+ + + +
+ +
+Specification + + + +
include CheckModifyConfigWithCap<TokenT>;
+aborts_if voting_quorum_rate > 0 && voting_quorum_rate > 100;
+
+ + + +
+ + + +## Function `set_voting_delay` + +set voting delay + + +
public fun set_voting_delay<TokenT: copy, drop, store>(cap: &mut Config::ModifyConfigCapability<Dao::DaoConfig<TokenT>>, value: u64)
+
+ + + +
+Implementation + + +
public fun set_voting_delay<TokenT: copy + drop + store>(
+    cap: &mut Config::ModifyConfigCapability<DaoConfig<TokenT>>,
+    value: u64,
+) {
+    assert!(Config::account_address(cap) == Token::token_address<TokenT>(), Errors::invalid_argument(ERR_NOT_AUTHORIZED));
+    assert!(value > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
+    let config = get_config<TokenT>();
+    config.voting_delay = value;
+    Config::set_with_capability<DaoConfig<TokenT>>(cap, config);
+}
+
+ + + +
+ +
+Specification + + + +
include CheckModifyConfigWithCap<TokenT>;
+aborts_if value == 0;
+
+ + + +
+ + + +## Function `set_voting_period` + +set voting period + + +
public fun set_voting_period<TokenT: copy, drop, store>(cap: &mut Config::ModifyConfigCapability<Dao::DaoConfig<TokenT>>, value: u64)
+
+ + + +
+Implementation + + +
public fun set_voting_period<TokenT: copy + drop + store>(
+    cap: &mut Config::ModifyConfigCapability<DaoConfig<TokenT>>,
+    value: u64,
+) {
+    assert!(Config::account_address(cap) == Token::token_address<TokenT>(), Errors::invalid_argument(ERR_NOT_AUTHORIZED));
+    assert!(value > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
+    let config = get_config<TokenT>();
+    config.voting_period = value;
+    Config::set_with_capability<DaoConfig<TokenT>>(cap, config);
+}
+
+ + + +
+ +
+Specification + + + +
include CheckModifyConfigWithCap<TokenT>;
+aborts_if value == 0;
+
+ + + +
+ + + +## Function `set_voting_quorum_rate` + +set voting quorum rate + + +
public fun set_voting_quorum_rate<TokenT: copy, drop, store>(cap: &mut Config::ModifyConfigCapability<Dao::DaoConfig<TokenT>>, value: u8)
+
+ + + +
+Implementation + + +
public fun set_voting_quorum_rate<TokenT: copy + drop + store>(
+    cap: &mut Config::ModifyConfigCapability<DaoConfig<TokenT>>,
+    value: u8,
+) {
+    assert!(Config::account_address(cap) == Token::token_address<TokenT>(), Errors::invalid_argument(ERR_NOT_AUTHORIZED));
+    assert!(value <= 100 && value > 0, Errors::invalid_argument(ERR_QUORUM_RATE_INVALID));
+    let config = get_config<TokenT>();
+    config.voting_quorum_rate = value;
+    Config::set_with_capability<DaoConfig<TokenT>>(cap, config);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !(value > 0 && value <= 100);
+include CheckModifyConfigWithCap<TokenT>;
+
+ + + +
+ + + +## Function `set_min_action_delay` + +set min action delay + + +
public fun set_min_action_delay<TokenT: copy, drop, store>(cap: &mut Config::ModifyConfigCapability<Dao::DaoConfig<TokenT>>, value: u64)
+
+ + + +
+Implementation + + +
public fun set_min_action_delay<TokenT: copy + drop + store>(
+    cap: &mut Config::ModifyConfigCapability<DaoConfig<TokenT>>,
+    value: u64,
+) {
+    assert!(Config::account_address(cap) == Token::token_address<TokenT>(), Errors::invalid_argument(ERR_NOT_AUTHORIZED));
+    assert!(value > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID));
+    let config = get_config<TokenT>();
+    config.min_action_delay = value;
+    Config::set_with_capability<DaoConfig<TokenT>>(cap, config);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if value == 0;
+include CheckModifyConfigWithCap<TokenT>;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/DaoVoteScripts.md b/release/v13/docs/DaoVoteScripts.md new file mode 100644 index 00000000..7bd67431 --- /dev/null +++ b/release/v13/docs/DaoVoteScripts.md @@ -0,0 +1,197 @@ + + + +# Module `0x1::DaoVoteScripts` + + + +- [Function `cast_vote`](#0x1_DaoVoteScripts_cast_vote) +- [Function `revoke_vote`](#0x1_DaoVoteScripts_revoke_vote) +- [Function `flip_vote`](#0x1_DaoVoteScripts_flip_vote) +- [Function `revoke_vote_of_power`](#0x1_DaoVoteScripts_revoke_vote_of_power) +- [Function `unstake_vote`](#0x1_DaoVoteScripts_unstake_vote) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::Account;
+use 0x1::Dao;
+use 0x1::Signer;
+use 0x1::Token;
+
+ + + + + +## Function `cast_vote` + + + +
public entry fun cast_vote<Token: copy, drop, store, ActionT: copy, drop, store>(signer: signer, proposer_address: address, proposal_id: u64, agree: bool, votes: u128)
+
+ + + +
+Implementation + + +
public entry fun cast_vote<Token: copy + drop + store, ActionT: copy + drop + store>(
+    signer: signer,
+    proposer_address: address,
+    proposal_id: u64,
+    agree: bool,
+    votes: u128,
+) {
+    let sender = Signer::address_of(&signer);
+    if (Dao::has_vote<Token>(sender, proposer_address, proposal_id)) {
+        // if already voted, and vote is not same as the current cast, change the existing vote.
+        // resolve https://github.com/starcoinorg/starcoin/issues/2925.
+        let (agree_voted, _) = Dao::vote_of<Token>(sender, proposer_address, proposal_id);
+        if (agree_voted != agree) {
+            Dao::change_vote<Token, ActionT>(&signer, proposer_address, proposal_id, agree);
+        }
+    };
+
+    let votes = Account::withdraw<Token>(&signer, votes);
+    Dao::cast_vote<Token, ActionT>(&signer, proposer_address, proposal_id, votes, agree);
+}
+
+ + + +
+ + + +## Function `revoke_vote` + +revoke all votes on a proposal + + +
public entry fun revoke_vote<Token: copy, drop, store, Action: copy, drop, store>(signer: signer, proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun revoke_vote<Token: copy + drop + store, Action: copy + drop + store>(
+    signer: signer,
+    proposer_address: address,
+    proposal_id: u64,
+) {
+    let sender = Signer::address_of(&signer);
+    let (_, power) = Dao::vote_of<Token>(sender, proposer_address, proposal_id);
+    let my_token = Dao::revoke_vote<Token, Action>(&signer, proposer_address, proposal_id, power);
+    Account::deposit(sender, my_token);
+}
+
+ + + +
+ + + +## Function `flip_vote` + +Let user change their vote during the voting time. + + +
public entry fun flip_vote<TokenT: copy, drop, store, ActionT: copy, drop, store>(signer: signer, proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun flip_vote<TokenT: copy + drop + store, ActionT: copy + drop + store>(
+    signer: signer,
+    proposer_address: address,
+    proposal_id: u64,
+) {
+    let (agree, _) = Dao::vote_of<TokenT>(Signer::address_of(&signer), proposer_address, proposal_id);
+    Dao::change_vote<TokenT, ActionT>(&signer, proposer_address, proposal_id, !agree);
+}
+
+ + + +
+ + + +## Function `revoke_vote_of_power` + +revoke some votes on a proposal + + +
public entry fun revoke_vote_of_power<Token: copy, drop, store, Action: copy, drop, store>(signer: signer, proposer_address: address, proposal_id: u64, power: u128)
+
+ + + +
+Implementation + + +
public entry fun revoke_vote_of_power<Token: copy + drop + store, Action: copy + drop + store>(
+    signer: signer,
+    proposer_address: address,
+    proposal_id: u64,
+    power: u128,
+) {
+    let sender = Signer::address_of(&signer);
+    let my_token = Dao::revoke_vote<Token, Action>(&signer, proposer_address, proposal_id, power);
+    Account::deposit(sender, my_token);
+}
+
+ + + +
+ + + +## Function `unstake_vote` + + + +
public entry fun unstake_vote<Token: copy, drop, store, Action: copy, drop, store>(signer: signer, proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun unstake_vote<Token: copy + drop + store, Action: copy + drop + store>(
+    signer: signer,
+    proposer_address: address,
+    proposal_id: u64,
+) {
+    let my_token = Dao::unstake_votes<Token, Action>(&signer, proposer_address, proposal_id);
+    Account::deposit(Signer::address_of(&signer), my_token);
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_partial = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/Debug.md b/release/v13/docs/Debug.md new file mode 100644 index 00000000..9d714ba9 --- /dev/null +++ b/release/v13/docs/Debug.md @@ -0,0 +1,72 @@ + + + +# Module `0x1::Debug` + +The module provide debug print for Move. + + +- [Function `print`](#0x1_Debug_print) +- [Function `print_stack_trace`](#0x1_Debug_print_stack_trace) +- [Module Specification](#@Module_Specification_0) + + +
+ + + + + +## Function `print` + +Print data of Type T. + + +
public fun print<T: store>(x: &T)
+
+ + + +
+Implementation + + +
native public fun print<T: store>(x: &T);
+
+ + + +
+ + + +## Function `print_stack_trace` + +Print current stack. + + +
public fun print_stack_trace()
+
+ + + +
+Implementation + + +
native public fun print_stack_trace();
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/DummyToken.md b/release/v13/docs/DummyToken.md new file mode 100644 index 00000000..ebf1331d --- /dev/null +++ b/release/v13/docs/DummyToken.md @@ -0,0 +1,46 @@ + + + +# Module `0x1::DummyTokenScripts` + + + +- [Function `mint`](#0x1_DummyTokenScripts_mint) + + +
use 0x1::Account;
+use 0x1::DummyToken;
+use 0x1::Signer;
+use 0x1::Token;
+
+ + + + + +## Function `mint` + + + +
public entry fun mint(sender: signer, amount: u128)
+
+ + + +
+Implementation + + +
public entry fun mint(sender: signer, amount: u128){
+    let token = DummyToken::mint(&sender, amount);
+    let sender_addr = Signer::address_of(&sender);
+    if(Account::is_accept_token<DummyToken>(sender_addr)){
+        Account::do_accept_token<DummyToken>(&sender);
+    };
+    Account::deposit(sender_addr, token);
+}
+
+ + + +
diff --git a/release/v13/docs/EasyGas.md b/release/v13/docs/EasyGas.md new file mode 100644 index 00000000..13225827 --- /dev/null +++ b/release/v13/docs/EasyGas.md @@ -0,0 +1,140 @@ + + + +# 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) +- [Function `deposit`](#0x1_EasyGasScript_deposit) + + +
use 0x1::EasyGas;
+use 0x1::TransferScripts;
+
+ + + + + +## 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);
+}
+
+ + + +
+ + + +## Function `deposit` + + + +
public entry fun deposit<TokenType: store>(sender: signer, amount: u128)
+
+ + + +
+Implementation + + +
public entry fun deposit<TokenType: store>(sender: signer, amount:u128)  {
+    let address = EasyGas::get_gas_fee_address();
+    peer_to_peer_v2<TokenType>(sender, address, amount)
+}
+
+ + + +
diff --git a/release/v13/docs/EmptyScripts.md b/release/v13/docs/EmptyScripts.md new file mode 100644 index 00000000..08c13a3c --- /dev/null +++ b/release/v13/docs/EmptyScripts.md @@ -0,0 +1,48 @@ + + + +# Module `0x1::EmptyScripts` + + + +- [Function `empty_script`](#0x1_EmptyScripts_empty_script) +- [Module Specification](#@Module_Specification_0) + + +
+ + + + + +## Function `empty_script` + + + +
public entry fun empty_script()
+
+ + + +
+Implementation + + +
public entry fun empty_script() {
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_partial = false;
+pragma aborts_if_is_strict = false;
+
diff --git a/release/v13/docs/Epoch.md b/release/v13/docs/Epoch.md new file mode 100644 index 00000000..17ac2e3c --- /dev/null +++ b/release/v13/docs/Epoch.md @@ -0,0 +1,1041 @@ + + + +# Module `0x1::Epoch` + +The module provide epoch functionality for starcoin. + + +- [Resource `Epoch`](#0x1_Epoch_Epoch) +- [Struct `NewEpochEvent`](#0x1_Epoch_NewEpochEvent) +- [Resource `EpochData`](#0x1_Epoch_EpochData) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_Epoch_initialize) +- [Function `compute_next_block_time_target`](#0x1_Epoch_compute_next_block_time_target) +- [Function `adjust_epoch`](#0x1_Epoch_adjust_epoch) +- [Function `adjust_gas_limit`](#0x1_Epoch_adjust_gas_limit) +- [Function `compute_gas_limit`](#0x1_Epoch_compute_gas_limit) +- [Function `in_or_decrease_gas_limit`](#0x1_Epoch_in_or_decrease_gas_limit) +- [Function `update_epoch_data`](#0x1_Epoch_update_epoch_data) +- [Function `emit_epoch_event`](#0x1_Epoch_emit_epoch_event) +- [Function `start_time`](#0x1_Epoch_start_time) +- [Function `uncles`](#0x1_Epoch_uncles) +- [Function `total_gas`](#0x1_Epoch_total_gas) +- [Function `block_gas_limit`](#0x1_Epoch_block_gas_limit) +- [Function `start_block_number`](#0x1_Epoch_start_block_number) +- [Function `end_block_number`](#0x1_Epoch_end_block_number) +- [Function `number`](#0x1_Epoch_number) +- [Function `block_time_target`](#0x1_Epoch_block_time_target) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::ConsensusConfig;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Math;
+use 0x1::Option;
+use 0x1::Timestamp;
+
+ + + + + +## Resource `Epoch` + +Current epoch info. + + +
struct Epoch has key
+
+ + + +
+Fields + + +
+
+number: u64 +
+
+ Number of current epoch +
+
+start_time: u64 +
+
+ Start time of current epoch +
+
+start_block_number: u64 +
+
+ Start block's number of current epoch +
+
+end_block_number: u64 +
+
+ End block's number of current epoch +
+
+block_time_target: u64 +
+
+ Average target time to calculate a block's difficulty in current epoch +
+
+reward_per_block: u128 +
+
+ Rewards per block in current epoch +
+
+reward_per_uncle_percent: u64 +
+
+ Percentage of reward_per_block to reward a uncle block in current epoch +
+
+block_difficulty_window: u64 +
+
+ How many ancestor blocks which use to calculate next block's difficulty in current epoch +
+
+max_uncles_per_block: u64 +
+
+ Maximum number of uncle block per block in current epoch +
+
+block_gas_limit: u64 +
+
+ Maximum gases per block in current epoch +
+
+strategy: u8 +
+
+ Strategy to calculate difficulty in current epoch +
+
+new_epoch_events: Event::EventHandle<Epoch::NewEpochEvent> +
+
+ Switch Epoch Event +
+
+ + +
+ + + +## Struct `NewEpochEvent` + +New epoch event. + + +
struct NewEpochEvent has drop, store
+
+ + + +
+Fields + + +
+
+number: u64 +
+
+ Epoch::number +
+
+start_time: u64 +
+
+ Epoch::start_time +
+
+start_block_number: u64 +
+
+ Epoch::start_block_number +
+
+end_block_number: u64 +
+
+ Epoch::end_block_number +
+
+block_time_target: u64 +
+
+ Epoch::block_time_target +
+
+reward_per_block: u128 +
+
+ Epoch::reward_per_block +
+
+previous_epoch_total_reward: u128 +
+
+ Total rewards during previous epoch +
+
+ + +
+ + + +## Resource `EpochData` + +Epoch data. + + +
struct EpochData has key
+
+ + + +
+Fields + + +
+
+uncles: u64 +
+
+ Up to now, Number of uncle block during current epoch +
+
+total_reward: u128 +
+
+ Up to now, Total rewards during current epoch +
+
+total_gas: u128 +
+
+ Up to now, Total gases during current epoch +
+
+ + +
+ + + +## Constants + + + + + + +
const EINVALID_UNCLES_COUNT: u64 = 101;
+
+ + + + + + + +
const EUNREACHABLE: u64 = 19;
+
+ + + + + + + +
const HUNDRED: u64 = 100;
+
+ + + + + + + +
const THOUSAND: u64 = 1000;
+
+ + + + + + + +
const THOUSAND_U128: u128 = 1000;
+
+ + + + + +## Function `initialize` + +Initialization of the module. + + +
public fun initialize(account: &signer)
+
+ + + +
+Implementation + + +
public fun initialize(
+    account: &signer,
+) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+
+    let config = ConsensusConfig::get_config();
+    move_to<Epoch>(
+        account,
+        Epoch {
+            number: 0,
+            start_time: Timestamp::now_milliseconds(),
+            start_block_number: 0,
+            end_block_number: ConsensusConfig::epoch_block_count(&config),
+            block_time_target: ConsensusConfig::base_block_time_target(&config),
+            reward_per_block: ConsensusConfig::base_reward_per_block(&config),
+            reward_per_uncle_percent: ConsensusConfig::base_reward_per_uncle_percent(&config),
+            block_difficulty_window: ConsensusConfig::base_block_difficulty_window(&config),
+            max_uncles_per_block: ConsensusConfig::base_max_uncles_per_block(&config),
+            block_gas_limit: ConsensusConfig::base_block_gas_limit(&config),
+            strategy: ConsensusConfig::strategy(&config),
+            new_epoch_events: Event::new_event_handle<NewEpochEvent>(account),
+        },
+    );
+    move_to<EpochData>(account, EpochData { uncles: 0, total_reward: 0, total_gas: 0 });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if !exists<Config::Config<ConsensusConfig>>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if exists<Epoch>(Signer::address_of(account));
+aborts_if exists<EpochData>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `compute_next_block_time_target` + +compute next block time_target. + + +
public fun compute_next_block_time_target(config: &ConsensusConfig::ConsensusConfig, last_epoch_time_target: u64, epoch_start_time: u64, now_milli_second: u64, start_block_number: u64, end_block_number: u64, total_uncles: u64): u64
+
+ + + +
+Implementation + + +
public fun compute_next_block_time_target(config: &ConsensusConfig, last_epoch_time_target: u64, epoch_start_time: u64, now_milli_second: u64, start_block_number: u64, end_block_number: u64, total_uncles: u64): u64 {
+    let total_time = now_milli_second - epoch_start_time;
+    let blocks = end_block_number - start_block_number;
+    let avg_block_time = total_time / blocks;
+    let uncles_rate = total_uncles * THOUSAND / blocks;
+    let new_epoch_block_time_target = (THOUSAND + uncles_rate) * avg_block_time /
+            (ConsensusConfig::uncle_rate_target(config) + THOUSAND);
+    if (new_epoch_block_time_target > last_epoch_time_target * 2) {
+        new_epoch_block_time_target = last_epoch_time_target * 2;
+    };
+    if (new_epoch_block_time_target < last_epoch_time_target / 2) {
+        new_epoch_block_time_target = last_epoch_time_target / 2;
+    };
+    let min_block_time_target = ConsensusConfig::min_block_time_target(config);
+    let max_block_time_target = ConsensusConfig::max_block_time_target(config);
+    if (new_epoch_block_time_target < min_block_time_target) {
+        new_epoch_block_time_target = min_block_time_target;
+    };
+    if (new_epoch_block_time_target > max_block_time_target) {
+        new_epoch_block_time_target = max_block_time_target;
+    };
+    new_epoch_block_time_target
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `adjust_epoch` + +adjust_epoch try to advance to next epoch if current epoch ends. + + +
public fun adjust_epoch(account: &signer, block_number: u64, timestamp: u64, uncles: u64, parent_gas_used: u64): u128
+
+ + + +
+Implementation + + +
public fun adjust_epoch(account: &signer, block_number: u64, timestamp: u64, uncles: u64, parent_gas_used:u64): u128
+acquires Epoch, EpochData {
+    CoreAddresses::assert_genesis_address(account);
+
+    let epoch_ref = borrow_global_mut<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+    assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+
+    let epoch_data = borrow_global_mut<EpochData>(CoreAddresses::GENESIS_ADDRESS());
+    let (new_epoch, reward_per_block) = if (block_number < epoch_ref.end_block_number) {
+        (false, epoch_ref.reward_per_block)
+    } else if (block_number == epoch_ref.end_block_number) {
+        //start a new epoch
+        assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+        // block time target unit is milli_seconds.
+        let now_milli_seconds = timestamp;
+
+        let config = ConsensusConfig::get_config();
+        let last_epoch_time_target = epoch_ref.block_time_target;
+        let new_epoch_block_time_target = compute_next_block_time_target(&config, last_epoch_time_target, epoch_ref.start_time, now_milli_seconds, epoch_ref.start_block_number, epoch_ref.end_block_number, epoch_data.uncles);
+        let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(&config, new_epoch_block_time_target);
+
+        //update epoch by adjust result or config, because ConsensusConfig may be updated.
+        epoch_ref.number = epoch_ref.number + 1;
+        epoch_ref.start_time = now_milli_seconds;
+        epoch_ref.start_block_number = block_number;
+        epoch_ref.end_block_number = block_number + ConsensusConfig::epoch_block_count(&config);
+        epoch_ref.block_time_target = new_epoch_block_time_target;
+        epoch_ref.reward_per_block = new_reward_per_block;
+        epoch_ref.reward_per_uncle_percent = ConsensusConfig::base_reward_per_uncle_percent(&config);
+        epoch_ref.block_difficulty_window = ConsensusConfig::base_block_difficulty_window(&config);
+        epoch_ref.max_uncles_per_block = ConsensusConfig::base_max_uncles_per_block(&config);
+        epoch_ref.strategy = ConsensusConfig::strategy(&config);
+
+        epoch_data.uncles = 0;
+        let last_epoch_total_gas = epoch_data.total_gas + (parent_gas_used as u128);
+        adjust_gas_limit(&config, epoch_ref, last_epoch_time_target, new_epoch_block_time_target, last_epoch_total_gas);
+        emit_epoch_event(epoch_ref, epoch_data.total_reward);
+        (true, new_reward_per_block)
+    } else {
+        //This should never happened.
+        abort EUNREACHABLE
+    };
+    let reward = reward_per_block +
+            reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
+    update_epoch_data(epoch_data, new_epoch, reward, uncles, parent_gas_used);
+    reward
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<Epoch>(Signer::address_of(account));
+aborts_if global<Epoch>(Signer::address_of(account)).max_uncles_per_block < uncles;
+aborts_if exists<EpochData>(Signer::address_of(account));
+aborts_if block_number == global<Epoch>(Signer::address_of(account)).end_block_number && uncles != 0;
+
+ + + +
+ + + +## Function `adjust_gas_limit` + + + +
fun adjust_gas_limit(config: &ConsensusConfig::ConsensusConfig, epoch_ref: &mut Epoch::Epoch, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_total_gas: u128)
+
+ + + +
+Implementation + + +
fun adjust_gas_limit(config: &ConsensusConfig, epoch_ref: &mut Epoch, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_total_gas:u128) {
+    let new_gas_limit = compute_gas_limit(config, last_epoch_time_target, new_epoch_time_target, epoch_ref.block_gas_limit, last_epoch_total_gas);
+    if (Option::is_some(&new_gas_limit)) {
+        epoch_ref.block_gas_limit = Option::destroy_some(new_gas_limit);
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `compute_gas_limit` + +Compute block's gas limit of next epoch. + + +
public fun compute_gas_limit(config: &ConsensusConfig::ConsensusConfig, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_block_gas_limit: u64, last_epoch_total_gas: u128): Option::Option<u64>
+
+ + + +
+Implementation + + +
public fun compute_gas_limit(config: &ConsensusConfig, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_block_gas_limit: u64, last_epoch_total_gas: u128) : Option::Option<u64> {
+    let epoch_block_count = (ConsensusConfig::epoch_block_count(config) as u128);
+    let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div((last_epoch_block_gas_limit as u128) * epoch_block_count, (80 as u128), (HUNDRED as u128)));
+    let new_gas_limit = Option::none<u64>();
+
+    let min_block_time_target = ConsensusConfig::min_block_time_target(config);
+    let max_block_time_target = ConsensusConfig::max_block_time_target(config);
+    let base_block_gas_limit =  ConsensusConfig::base_block_gas_limit(config);
+    if (last_epoch_time_target == new_epoch_time_target) {
+        if (new_epoch_time_target == min_block_time_target && gas_limit_threshold) {
+            let increase_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 110, base_block_gas_limit);
+            new_gas_limit = Option::some(increase_gas_limit);
+        } else if (new_epoch_time_target == max_block_time_target && !gas_limit_threshold) {
+            let decrease_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 90, base_block_gas_limit);
+            new_gas_limit = Option::some(decrease_gas_limit);
+        }
+    };
+
+    new_gas_limit
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `in_or_decrease_gas_limit` + + + +
fun in_or_decrease_gas_limit(last_epoch_block_gas_limit: u64, percent: u64, min_block_gas_limit: u64): u64
+
+ + + +
+Implementation + + +
fun in_or_decrease_gas_limit(last_epoch_block_gas_limit: u64, percent: u64, min_block_gas_limit: u64): u64 {
+    let tmp_gas_limit = Math::mul_div((last_epoch_block_gas_limit as u128), (percent as u128), (HUNDRED as u128));
+    let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit  as u128)) {
+        (tmp_gas_limit as u64)
+    } else {
+        min_block_gas_limit
+    };
+
+    new_gas_limit
+}
+
+ + + +
+ +
+Specification + + + +
include Math::MulDivAbortsIf{x: last_epoch_block_gas_limit, y: percent, z: HUNDRED};
+aborts_if Math::spec_mul_div() > MAX_U64;
+
+ + + +
+ + + +## Function `update_epoch_data` + + + +
fun update_epoch_data(epoch_data: &mut Epoch::EpochData, new_epoch: bool, reward: u128, uncles: u64, parent_gas_used: u64)
+
+ + + +
+Implementation + + +
fun update_epoch_data(epoch_data: &mut EpochData, new_epoch: bool, reward: u128, uncles: u64, parent_gas_used:u64) {
+    if (new_epoch) {
+        epoch_data.total_reward = reward;
+        epoch_data.uncles = uncles;
+        epoch_data.total_gas = 0;
+    } else {
+        epoch_data.total_reward = epoch_data.total_reward + reward;
+        epoch_data.uncles = epoch_data.uncles + uncles;
+        epoch_data.total_gas = epoch_data.total_gas + (parent_gas_used as u128);
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !new_epoch && epoch_data.total_reward + reward > MAX_U128;
+aborts_if !new_epoch && epoch_data.uncles + uncles > MAX_U64;
+aborts_if !new_epoch && epoch_data.total_gas + parent_gas_used > MAX_U128;
+
+ + + +
+ + + +## Function `emit_epoch_event` + + + +
fun emit_epoch_event(epoch_ref: &mut Epoch::Epoch, previous_epoch_total_reward: u128)
+
+ + + +
+Implementation + + +
fun emit_epoch_event(epoch_ref: &mut Epoch, previous_epoch_total_reward: u128) {
+    Event::emit_event(
+        &mut epoch_ref.new_epoch_events,
+        NewEpochEvent {
+            number: epoch_ref.number,
+            start_time: epoch_ref.start_time,
+            start_block_number: epoch_ref.start_block_number,
+            end_block_number: epoch_ref.end_block_number,
+            block_time_target: epoch_ref.block_time_target,
+            reward_per_block: epoch_ref.reward_per_block,
+            previous_epoch_total_reward,
+        },
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `start_time` + +Get start time of current epoch + + +
public fun start_time(): u64
+
+ + + +
+Implementation + + +
public fun start_time(): u64 acquires Epoch {
+    let epoch_ref = borrow_global<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_ref.start_time
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `uncles` + +Get uncles number of current epoch + + +
public fun uncles(): u64
+
+ + + +
+Implementation + + +
public fun uncles(): u64 acquires EpochData {
+    let epoch_data = borrow_global<EpochData>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_data.uncles
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<EpochData>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `total_gas` + +Get total gas of current epoch + + +
public fun total_gas(): u128
+
+ + + +
+Implementation + + +
public fun total_gas(): u128 acquires EpochData {
+    let epoch_data = borrow_global<EpochData>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_data.total_gas
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<EpochData>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `block_gas_limit` + +Get block's gas_limit of current epoch + + +
public fun block_gas_limit(): u64
+
+ + + +
+Implementation + + +
public fun block_gas_limit(): u64 acquires Epoch {
+    let epoch_ref = borrow_global<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_ref.block_gas_limit
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `start_block_number` + +Get start block's number of current epoch + + +
public fun start_block_number(): u64
+
+ + + +
+Implementation + + +
public fun start_block_number(): u64 acquires Epoch {
+    let epoch_ref = borrow_global<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_ref.start_block_number
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `end_block_number` + +Get end block's number of current epoch + + +
public fun end_block_number(): u64
+
+ + + +
+Implementation + + +
public fun end_block_number(): u64 acquires Epoch {
+    let epoch_ref = borrow_global<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_ref.end_block_number
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `number` + +Get current epoch number + + +
public fun number(): u64
+
+ + + +
+Implementation + + +
public fun number(): u64 acquires Epoch {
+    let epoch_ref = borrow_global<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_ref.number
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `block_time_target` + +Get current block time target + + +
public fun block_time_target(): u64
+
+ + + +
+Implementation + + +
public fun block_time_target(): u64 acquires Epoch {
+    let epoch_ref = borrow_global<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+    epoch_ref.block_time_target
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Epoch>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Errors.md b/release/v13/docs/Errors.md new file mode 100644 index 00000000..75b214eb --- /dev/null +++ b/release/v13/docs/Errors.md @@ -0,0 +1,623 @@ + + + +# Module `0x1::Errors` + +Module defining error codes used in Move aborts throughout the framework. + +A u64 error code is constructed from two values: + +1. The *error category* which is encoded in the lower 8 bits of the code. Error categories are +declared in this module and are globally unique across the Diem framework. There is a limited +fixed set of predefined categories, and the framework is guaranteed to use those consistently. + +2. The *error reason* which is encoded in the remaining 56 bits of the code. The reason is a unique +number relative to the module which raised the error and can be used to obtain more information about +the error at hand. It is mostly used for diagnosis purposes. Error reasons may change over time as the +framework evolves. + +Rules to declare or use *error reason*: +1. error reason is declared as const in the user module +2. error reason name must start with "E", for example, const EACCOUNT_DOES_NOT_EXIST = ... +3. value less than 100 is reserved for general purpose and shared by all modules +4. don't change general purpose error reason value, it's co-related with error code in starcoin vm +5. self-defined error reason value must be large than 100 +6. error reason must be used together with error category + + +- [Constants](#@Constants_0) +- [Function `make`](#0x1_Errors_make) +- [Function `invalid_state`](#0x1_Errors_invalid_state) +- [Function `requires_address`](#0x1_Errors_requires_address) +- [Function `requires_role`](#0x1_Errors_requires_role) +- [Function `requires_capability`](#0x1_Errors_requires_capability) +- [Function `not_published`](#0x1_Errors_not_published) +- [Function `already_published`](#0x1_Errors_already_published) +- [Function `invalid_argument`](#0x1_Errors_invalid_argument) +- [Function `limit_exceeded`](#0x1_Errors_limit_exceeded) +- [Function `internal`](#0x1_Errors_internal) +- [Function `deprecated`](#0x1_Errors_deprecated) +- [Function `custom`](#0x1_Errors_custom) +- [Module Specification](#@Module_Specification_1) + + +
+ + + + + +## Constants + + + + +Attempting to publish a resource that is already published. Example: calling an initialization function +twice. + + +
const ALREADY_PUBLISHED: u8 = 6;
+
+ + + + + +A custom error category for extension points. + + +
const CUSTOM: u8 = 255;
+
+ + + + + +deprecated code + + +
const DEPRECATED: u8 = 11;
+
+ + + + + +An internal error (bug) has occurred. + + +
const INTERNAL: u8 = 10;
+
+ + + + + +An argument provided to an operation is invalid. Example: a signing key has the wrong format. + + +
const INVALID_ARGUMENT: u8 = 7;
+
+ + + + + +The system is in a state where the performed operation is not allowed. Example: call to a function only allowed +in genesis + + +
const INVALID_STATE: u8 = 1;
+
+ + + + + +A limit on an amount, e.g. a currency, is exceeded. Example: withdrawal of money after account limits window +is exhausted. + + +
const LIMIT_EXCEEDED: u8 = 8;
+
+ + + + + +A resource is required but not published. Example: access to non-existing resource. + + +
const NOT_PUBLISHED: u8 = 5;
+
+ + + + + +The signer of a transaction does not have the expected address for this operation. Example: a call to a function +which publishes a resource under a particular address. + + +
const REQUIRES_ADDRESS: u8 = 2;
+
+ + + + + +The signer of a transaction does not have a required capability. + + +
const REQUIRES_CAPABILITY: u8 = 4;
+
+ + + + + +The signer of a transaction does not have the expected role for this operation. Example: a call to a function +which requires the signer to have the role of treasury compliance. + + +
const REQUIRES_ROLE: u8 = 3;
+
+ + + + + +## Function `make` + +A function to create an error from from a category and a reason. + + +
fun make(category: u8, reason: u64): u64
+
+ + + +
+Implementation + + +
fun make(category: u8, reason: u64): u64 {
+    (category as u64) + (reason << 8)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+pragma verify = false;
+aborts_if [abstract] false;
+ensures [abstract] result == category;
+
+ + + +
+ + + +## Function `invalid_state` + +Create an error of invalid_state + + +
public fun invalid_state(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun invalid_state(reason: u64): u64 { make(INVALID_STATE, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == INVALID_STATE;
+
+ + + +
+ + + +## Function `requires_address` + +Create an error of requires_address. + + +
public fun requires_address(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun requires_address(reason: u64): u64 { make(REQUIRES_ADDRESS, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == REQUIRES_ADDRESS;
+
+ + + +
+ + + +## Function `requires_role` + +Create an error of requires_role. + + +
public fun requires_role(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun requires_role(reason: u64): u64 { make(REQUIRES_ROLE, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == REQUIRES_ROLE;
+
+ + + +
+ + + +## Function `requires_capability` + +Create an error of requires_capability. + + +
public fun requires_capability(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun requires_capability(reason: u64): u64 { make(REQUIRES_CAPABILITY, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == REQUIRES_CAPABILITY;
+
+ + + +
+ + + +## Function `not_published` + +Create an error of not_published. + + +
public fun not_published(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun not_published(reason: u64): u64 { make(NOT_PUBLISHED, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == NOT_PUBLISHED;
+
+ + + +
+ + + +## Function `already_published` + +Create an error of already_published. + + +
public fun already_published(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun already_published(reason: u64): u64 { make(ALREADY_PUBLISHED, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == ALREADY_PUBLISHED;
+
+ + + +
+ + + +## Function `invalid_argument` + +Create an error of invalid_argument. + + +
public fun invalid_argument(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun invalid_argument(reason: u64): u64 { make(INVALID_ARGUMENT, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == INVALID_ARGUMENT;
+
+ + + +
+ + + +## Function `limit_exceeded` + +Create an error of limit_exceeded. + + +
public fun limit_exceeded(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun limit_exceeded(reason: u64): u64 { make(LIMIT_EXCEEDED, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == LIMIT_EXCEEDED;
+
+ + + +
+ + + +## Function `internal` + +Create an error of internal. + + +
public fun internal(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun internal(reason: u64): u64 { make(INTERNAL, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == INTERNAL;
+
+ + + +
+ + + +## Function `deprecated` + +Create an error of deprecated. + + +
public fun deprecated(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun deprecated(reason: u64): u64 { make(DEPRECATED, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == DEPRECATED;
+
+ + + +
+ + + +## Function `custom` + +Create an error of custom. + + +
public fun custom(reason: u64): u64
+
+ + + +
+Implementation + + +
public fun custom(reason: u64): u64 { make(CUSTOM, reason) }
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == CUSTOM;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Event.md b/release/v13/docs/Event.md new file mode 100644 index 00000000..aed6dda1 --- /dev/null +++ b/release/v13/docs/Event.md @@ -0,0 +1,300 @@ + + + +# Module `0x1::Event` + +The Event module defines an EventHandleGenerator that is used to create +EventHandles with unique GUIDs. It contains a counter for the number +of EventHandles it generates. An EventHandle is used to count the number of +events emitted to a handle and emit events to the event store. + + +- [Resource `EventHandleGenerator`](#0x1_Event_EventHandleGenerator) +- [Struct `EventHandle`](#0x1_Event_EventHandle) +- [Constants](#@Constants_0) +- [Function `publish_generator`](#0x1_Event_publish_generator) +- [Function `fresh_guid`](#0x1_Event_fresh_guid) +- [Function `new_event_handle`](#0x1_Event_new_event_handle) +- [Function `emit_event`](#0x1_Event_emit_event) +- [Function `write_to_event_store`](#0x1_Event_write_to_event_store) +- [Function `destroy_handle`](#0x1_Event_destroy_handle) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::BCS;
+use 0x1::Errors;
+use 0x1::Signer;
+use 0x1::Vector;
+
+ + + + + +## Resource `EventHandleGenerator` + +A resource representing the counter used to generate uniqueness under each account. There won't be destructor for +this resource to guarantee the uniqueness of the generated handle. + + +
struct EventHandleGenerator has key
+
+ + + +
+Fields + + +
+
+counter: u64 +
+
+ +
+
+addr: address +
+
+ +
+
+ + +
+ + + +## Struct `EventHandle` + +A handle for an event such that: +1. Other modules can emit events to this handle. +2. Storage can use this handle to prove the total number of events that happened in the past. + + +
struct EventHandle<T: drop, store> has store
+
+ + + +
+Fields + + +
+
+counter: u64 +
+
+ Total number of events emitted to this event stream. +
+
+guid: vector<u8> +
+
+ A globally unique ID for this event stream. +
+
+ + +
+ + + +## Constants + + + + +The event generator resource was in an invalid state + + +
const EEVENT_GENERATOR: u64 = 0;
+
+ + + + + +## Function `publish_generator` + +Publishs a new event handle generator. + + +
public fun publish_generator(account: &signer)
+
+ + + +
+Implementation + + +
public fun publish_generator(account: &signer) {
+    let addr = Signer::address_of(account);
+    assert!(!exists<EventHandleGenerator>(addr), Errors::already_published(EEVENT_GENERATOR));
+    move_to(account, EventHandleGenerator{ counter: 0, addr })
+}
+
+ + + +
+ + + +## Function `fresh_guid` + +Derive a fresh unique id by using sender's EventHandleGenerator. The generated vector is indeed unique because it +was derived from the hash(sender's EventHandleGenerator || sender_address). This module guarantees that the +EventHandleGenerator is only going to be monotonically increased and there's no way to revert it or destroy it. Thus +such counter is going to give distinct value for each of the new event stream under each sender. And since we +hash it with the sender's address, the result is guaranteed to be globally unique. + + +
fun fresh_guid(counter: &mut Event::EventHandleGenerator): vector<u8>
+
+ + + +
+Implementation + + +
fun fresh_guid(counter: &mut EventHandleGenerator): vector<u8> {
+    let sender_bytes = BCS::to_bytes(&counter.addr);
+    let count_bytes = BCS::to_bytes(&counter.counter);
+    counter.counter = counter.counter + 1;
+
+    // EventHandleGenerator goes first just in case we want to extend address in the future.
+    Vector::append(&mut count_bytes, sender_bytes);
+
+    count_bytes
+}
+
+ + + +
+ + + +## Function `new_event_handle` + +Use EventHandleGenerator to generate a unique event handle for sig + + +
public fun new_event_handle<T: drop, store>(account: &signer): Event::EventHandle<T>
+
+ + + +
+Implementation + + +
public fun new_event_handle<T: drop + store>(account: &signer): EventHandle<T>
+acquires EventHandleGenerator {
+    let addr = Signer::address_of(account);
+    assert!(exists<EventHandleGenerator>(addr), Errors::not_published(EEVENT_GENERATOR));
+    EventHandle<T> {
+        counter: 0,
+        guid: fresh_guid(borrow_global_mut<EventHandleGenerator>(addr))
+    }
+}
+
+ + + +
+ + + +## Function `emit_event` + +Emit an event with payload msg by using handle_ref's key and counter. + + +
public fun emit_event<T: drop, store>(handle_ref: &mut Event::EventHandle<T>, msg: T)
+
+ + + +
+Implementation + + +
public fun emit_event<T: drop + store>(handle_ref: &mut EventHandle<T>, msg: T) {
+    let guid = *&handle_ref.guid;
+
+    write_to_event_store<T>(guid, handle_ref.counter, msg);
+    handle_ref.counter = handle_ref.counter + 1;
+}
+
+ + + +
+ + + +## Function `write_to_event_store` + +Native procedure that writes to the actual event stream in Event store +This will replace the "native" portion of EmitEvent bytecode + + +
fun write_to_event_store<T: drop, store>(guid: vector<u8>, count: u64, msg: T)
+
+ + + +
+Implementation + + +
native fun write_to_event_store<T: drop + store>(guid: vector<u8>, count: u64, msg: T);
+
+ + + +
+ + + +## Function `destroy_handle` + +Destroy a unique handle. + + +
public fun destroy_handle<T: drop, store>(handle: Event::EventHandle<T>)
+
+ + + +
+Implementation + + +
public fun destroy_handle<T: drop + store>(handle: EventHandle<T>) {
+    EventHandle<T> { counter: _, guid: _ } = handle;
+}
+
+ + + +
+ + + +## Module Specification + + + +Functions of the event module are mocked out using the intrinsic +pragma. They are implemented in the prover's prelude. + + +
pragma intrinsic = true;
+
diff --git a/release/v13/docs/EventUtil.md b/release/v13/docs/EventUtil.md new file mode 100644 index 00000000..420e3c6f --- /dev/null +++ b/release/v13/docs/EventUtil.md @@ -0,0 +1,175 @@ + + + +# Module `0x1::EventUtil` + + + +- [Resource `EventHandleWrapper`](#0x1_EventUtil_EventHandleWrapper) +- [Constants](#@Constants_0) +- [Function `init_event`](#0x1_EventUtil_init_event) +- [Function `uninit_event`](#0x1_EventUtil_uninit_event) +- [Function `emit_event`](#0x1_EventUtil_emit_event) +- [Function `exist_event`](#0x1_EventUtil_exist_event) + + +
use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Signer;
+
+ + + + + +## Resource `EventHandleWrapper` + + + +
struct EventHandleWrapper<EventT: drop, store> has key
+
+ + + +
+Fields + + +
+
+handle: Event::EventHandle<EventT> +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_INIT_REPEATE: u64 = 101;
+
+ + + + + + + +
const ERR_RESOURCE_NOT_EXISTS: u64 = 102;
+
+ + + + + +## Function `init_event` + + + +
public fun init_event<EventT: drop, store>(sender: &signer)
+
+ + + +
+Implementation + + +
public fun init_event<EventT: store + drop>(sender: &signer) {
+    let broker = Signer::address_of(sender);
+    assert!(!exists<EventHandleWrapper<EventT>>(broker), Errors::invalid_state(ERR_INIT_REPEATE));
+    move_to(sender, EventHandleWrapper<EventT> {
+        handle: Event::new_event_handle<EventT>(sender)
+    });
+}
+
+ + + +
+ + + +## Function `uninit_event` + + + +
public fun uninit_event<EventT: drop, store>(sender: &signer)
+
+ + + +
+Implementation + + +
public fun uninit_event<EventT: store + drop>(sender: &signer) acquires EventHandleWrapper {
+    let broker = Signer::address_of(sender);
+    assert!(exists<EventHandleWrapper<EventT>>(broker), Errors::invalid_state(ERR_RESOURCE_NOT_EXISTS));
+    let EventHandleWrapper<EventT> { handle } = move_from<EventHandleWrapper<EventT>>(broker);
+    Event::destroy_handle<EventT>(handle);
+}
+
+ + + +
+ + + +## Function `emit_event` + + + +
public fun emit_event<EventT: drop, store>(broker: address, event: EventT)
+
+ + + +
+Implementation + + +
public fun emit_event<EventT: store + drop>(broker: address, event: EventT) acquires EventHandleWrapper {
+    let event_handle = borrow_global_mut<EventHandleWrapper<EventT>>(broker);
+    Event::emit_event(&mut event_handle.handle, event);
+}
+
+ + + +
+ + + +## Function `exist_event` + + + +
public fun exist_event<EventT: drop, store>(broker: address): bool
+
+ + + +
+Implementation + + +
public fun exist_event<EventT: store + drop>(broker: address): bool {
+    exists<EventHandleWrapper<EventT>>(broker)
+}
+
+ + + +
diff --git a/release/v13/docs/FixedPoint32.md b/release/v13/docs/FixedPoint32.md new file mode 100644 index 00000000..16bc13d8 --- /dev/null +++ b/release/v13/docs/FixedPoint32.md @@ -0,0 +1,439 @@ + + + +# Module `0x1::FixedPoint32` + +The module provide operations for FixedPoint32. + + +- [Struct `FixedPoint32`](#0x1_FixedPoint32_FixedPoint32) +- [Constants](#@Constants_0) +- [Function `multiply_u64`](#0x1_FixedPoint32_multiply_u64) +- [Function `divide_u64`](#0x1_FixedPoint32_divide_u64) +- [Function `create_from_rational`](#0x1_FixedPoint32_create_from_rational) +- [Function `create_from_raw_value`](#0x1_FixedPoint32_create_from_raw_value) +- [Function `get_raw_value`](#0x1_FixedPoint32_get_raw_value) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+
+ + + + + +## Struct `FixedPoint32` + +Define a fixed-point numeric type with 32 fractional bits. +This is just a u64 integer but it is wrapped in a struct to +make a unique type. + + +
struct FixedPoint32 has copy, drop, store
+
+ + + +
+Fields + + +
+
+value: u64 +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const MAX_U64: u128 = 18446744073709551615;
+
+ + + + + +The denominator provided was zero + + +
const EDENOMINATOR: u64 = 101;
+
+ + + + + +The quotient value would be too large to be held in a u64 + + +
const EDIVISION: u64 = 102;
+
+ + + + + +A division by zero was encountered + + +
const EDIVISION_BY_ZERO: u64 = 104;
+
+ + + + + +The multiplied value would be too large to be held in a u64 + + +
const EMULTIPLICATION: u64 = 103;
+
+ + + + + +The computed ratio when converting to a FixedPoint32 would be unrepresentable + + +
const ERATIO_OUT_OF_RANGE: u64 = 105;
+
+ + + + + +## Function `multiply_u64` + +Multiply a u64 integer by a fixed-point number, truncating any +fractional part of the product. This will abort if the product +overflows. + + +
public fun multiply_u64(val: u64, multiplier: FixedPoint32::FixedPoint32): u64
+
+ + + +
+Implementation + + +
public fun multiply_u64(val: u64, multiplier: FixedPoint32): u64 {
+    // The product of two 64 bit values has 128 bits, so perform the
+    // multiplication with u128 types and keep the full 128 bit product
+    // to avoid losing accuracy.
+    let unscaled_product = (val as u128) * (multiplier.value as u128);
+    // The unscaled product has 32 fractional bits (from the multiplier)
+    // so rescale it by shifting away the low bits.
+    let product = unscaled_product >> 32;
+    // Check whether the value is too large.
+    assert!(product <= MAX_U64, Errors::limit_exceeded(EMULTIPLICATION));
+    (product as u64)
+}
+
+ + + +
+ +
+Specification + + +Currently, we ignore the actual implementation of this function in verification +and treat it as uninterpreted, which simplifies the verification problem significantly. +This way we avoid the non-linear arithmetic problem presented by this function. + +Abstracting this and related functions is possible because the correctness of currency +conversion (where FixedPoint32 is used for) is not relevant for the rest of the contract +control flow, so we can assume some arbitrary (but fixed) behavior here. + + +
pragma opaque = true;
+include MultiplyAbortsIf;
+ensures result == spec_multiply_u64(val, multiplier);
+
+ + + + + + + +
schema MultiplyAbortsIf {
+    val: num;
+    multiplier: FixedPoint32;
+    aborts_if spec_multiply_u64(val, multiplier) > MAX_U64 with Errors::LIMIT_EXCEEDED;
+}
+
+ + + + + + + +
fun spec_multiply_u64(val: num, multiplier: FixedPoint32): num {
+   (val * multiplier.value) >> 32
+}
+
+ + + +
+ + + +## Function `divide_u64` + +Divide a u64 integer by a fixed-point number, truncating any +fractional part of the quotient. This will abort if the divisor +is zero or if the quotient overflows. + + +
public fun divide_u64(val: u64, divisor: FixedPoint32::FixedPoint32): u64
+
+ + + +
+Implementation + + +
public fun divide_u64(val: u64, divisor: FixedPoint32): u64 {
+    // Check for division by zero.
+    assert!(divisor.value != 0, Errors::invalid_argument(EDIVISION_BY_ZERO));
+    // First convert to 128 bits and then shift left to
+    // add 32 fractional zero bits to the dividend.
+    let scaled_value = (val as u128) << 32;
+    let quotient = scaled_value / (divisor.value as u128);
+    // Check whether the value is too large.
+    assert!(quotient <= MAX_U64, Errors::limit_exceeded(EDIVISION));
+    // the value may be too large, which will cause the cast to fail
+    // with an arithmetic error.
+    (quotient as u64)
+}
+
+ + + +
+ +
+Specification + + +See comment at Self::multiply_64. + + +
pragma opaque = true;
+include DivideAbortsIf;
+ensures result == spec_divide_u64(val, divisor);
+
+ + + + + + + +
schema DivideAbortsIf {
+    val: num;
+    divisor: FixedPoint32;
+    aborts_if divisor.value == 0 with Errors::INVALID_ARGUMENT;
+    aborts_if spec_divide_u64(val, divisor) > MAX_U64 with Errors::LIMIT_EXCEEDED;
+}
+
+ + + + + + + +
fun spec_divide_u64(val: num, divisor: FixedPoint32): num {
+   (val << 32) / divisor.value
+}
+
+ + + +
+ + + +## Function `create_from_rational` + +Create a fixed-point value from a rational number specified by its +numerator and denominator. This function is for convenience; it is also +perfectly fine to create a fixed-point value by directly specifying the +raw value. This will abort if the denominator is zero or if the ratio is +not in the range 2^-32 .. 2^32-1. + + +
public fun create_from_rational(numerator: u64, denominator: u64): FixedPoint32::FixedPoint32
+
+ + + +
+Implementation + + +
public fun create_from_rational(numerator: u64, denominator: u64): FixedPoint32 {
+    // If the denominator is zero, this will abort.
+    // Scale the numerator to have 64 fractional bits and the denominator
+    // to have 32 fractional bits, so that the quotient will have 32
+    // fractional bits.
+    let scaled_numerator = (numerator as u128) << 64;
+    let scaled_denominator = (denominator as u128) << 32;
+    assert!(scaled_denominator != 0, Errors::invalid_argument(EDENOMINATOR));
+    let quotient = scaled_numerator / scaled_denominator;
+    assert!(quotient != 0 || numerator == 0, Errors::invalid_argument(ERATIO_OUT_OF_RANGE));
+    // Return the quotient as a fixed-point number. We first need to check whether the cast
+    // can succeed.
+    assert!(quotient <= MAX_U64, Errors::limit_exceeded(ERATIO_OUT_OF_RANGE));
+    FixedPoint32 { value: (quotient as u64) }
+}
+
+ + + +
+ +
+Specification + + +See comment at Self::multiply_64. + + +
pragma verify = false;
+pragma opaque = true;
+include CreateFromRationalAbortsIf;
+ensures result == spec_create_from_rational(numerator, denominator);
+
+ + + + + + + +
schema CreateFromRationalAbortsIf {
+    numerator: u64;
+    denominator: u64;
+    let scaled_numerator = numerator << 64;
+    let scaled_denominator = denominator << 32;
+    let quotient = scaled_numerator / scaled_denominator;
+    aborts_if scaled_denominator == 0 with Errors::INVALID_ARGUMENT;
+    aborts_if quotient == 0 && scaled_numerator != 0 with Errors::INVALID_ARGUMENT;
+    aborts_if quotient > MAX_U64 with Errors::LIMIT_EXCEEDED;
+}
+
+ + + + + + + +
fun spec_create_from_rational(numerator: num, denominator: num): FixedPoint32 {
+   FixedPoint32{value: (numerator << 64) / (denominator << 32)}
+}
+
+ + + +
+ + + +## Function `create_from_raw_value` + +create a fixedpoint 32 from u64. + + +
public fun create_from_raw_value(value: u64): FixedPoint32::FixedPoint32
+
+ + + +
+Implementation + + +
public fun create_from_raw_value(value: u64): FixedPoint32 {
+    FixedPoint32 { value }
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result.value == value;
+
+ + + +
+ + + +## Function `get_raw_value` + +Accessor for the raw u64 value. Other less common operations, such as +adding or subtracting FixedPoint32 values, can be done using the raw +values directly. + + +
public fun get_raw_value(num: FixedPoint32::FixedPoint32): u64
+
+ + + +
+Implementation + + +
public fun get_raw_value(num: FixedPoint32): u64 {
+    num.value
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/FlexiDagConfig.md b/release/v13/docs/FlexiDagConfig.md new file mode 100644 index 00000000..0e7f2888 --- /dev/null +++ b/release/v13/docs/FlexiDagConfig.md @@ -0,0 +1,168 @@ + + + +# Module `0x1::FlexiDagConfig` + + + +- [Struct `FlexiDagConfig`](#0x1_FlexiDagConfig_FlexiDagConfig) +- [Function `new_flexidag_config`](#0x1_FlexiDagConfig_new_flexidag_config) +- [Function `initialize`](#0x1_FlexiDagConfig_initialize) +- [Function `effective_height`](#0x1_FlexiDagConfig_effective_height) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::Config;
+use 0x1::CoreAddresses;
+
+ + + + + +## Struct `FlexiDagConfig` + +The struct to hold all config data needed for Flexidag. + + +
struct FlexiDagConfig has copy, drop, store
+
+ + + +
+Fields + + +
+
+effective_height: u64 +
+
+ +
+
+ + +
+ + + +## Function `new_flexidag_config` + +Create a new configuration for flexidag, mainly used in DAO. + + +
public fun new_flexidag_config(effective_height: u64): FlexiDagConfig::FlexiDagConfig
+
+ + + +
+Implementation + + +
public fun new_flexidag_config(effective_height: u64): FlexiDagConfig {
+    FlexiDagConfig {
+        effective_height,
+    }
+}
+
+ + + +
+ + + +## Function `initialize` + + + +
public fun initialize(account: &signer, effective_height: u64)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, effective_height: u64) {
+    CoreAddresses::assert_genesis_address(account);
+    Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
+aborts_if
+    exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(
+        Signer::address_of(account),
+    );
+ensures exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
+ensures
+    exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(
+        Signer::address_of(account),
+    );
+
+ + + +
+ + + +## Function `effective_height` + + + +
public fun effective_height(account: address): u64
+
+ + + +
+Implementation + + +
public fun effective_height(account: address): u64 {
+    let flexi_dag_config = Config::get_by_address<FlexiDagConfig>(account);
+    flexi_dag_config.effective_height
+}
+
+ + + +
+ +
+Specification + + + +
include Config::AbortsIfConfigNotExist<FlexiDagConfig> { addr: account };
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/FromBCS.md b/release/v13/docs/FromBCS.md new file mode 100644 index 00000000..c9094f7c --- /dev/null +++ b/release/v13/docs/FromBCS.md @@ -0,0 +1,205 @@ + + + +# Module `0x1::FromBCS` + +This module provides a number of functions to convert _primitive_ types from their representation in std::bcs +to values. This is the opposite of bcs::to_bytes. Note that it is not safe to define a generic public from_bytes +function because this can violate implicit struct invariants, therefore only primitive types are offerred. If +a general conversion back-and-force is needed, consider the StarcoinFramework::Any type which preserves invariants. + +Example: +``` +use std::bcs; +use StarcoinFramework::from_bcs; + +assert!(from_bcs::to_address(bcs::to_bytes(&@0xabcdef)) == @0xabcdef, 0); +``` + + +- [Constants](#@Constants_0) +- [Function `to_bool`](#0x1_FromBCS_to_bool) +- [Function `to_u8`](#0x1_FromBCS_to_u8) +- [Function `to_u64`](#0x1_FromBCS_to_u64) +- [Function `to_u128`](#0x1_FromBCS_to_u128) +- [Function `to_address`](#0x1_FromBCS_to_address) +- [Function `from_bytes`](#0x1_FromBCS_from_bytes) + + +
+ + + + + +## Constants + + + + +UTF8 check failed in conversion from bytes to string + + +
const EINVALID_UTF8: u64 = 1;
+
+ + + + + +## Function `to_bool` + + + +
public fun to_bool(v: vector<u8>): bool
+
+ + + +
+Implementation + + +
public fun to_bool(v: vector<u8>): bool {
+    from_bytes<bool>(v)
+}
+
+ + + +
+ + + +## Function `to_u8` + + + +
public fun to_u8(v: vector<u8>): u8
+
+ + + +
+Implementation + + +
public fun to_u8(v: vector<u8>): u8 {
+    from_bytes<u8>(v)
+}
+
+ + + +
+ + + +## Function `to_u64` + + + +
public fun to_u64(v: vector<u8>): u64
+
+ + + +
+Implementation + + +
public fun to_u64(v: vector<u8>): u64 {
+    from_bytes<u64>(v)
+}
+
+ + + +
+ + + +## Function `to_u128` + + + +
public fun to_u128(v: vector<u8>): u128
+
+ + + +
+Implementation + + +
public fun to_u128(v: vector<u8>): u128 {
+    from_bytes<u128>(v)
+}
+
+ + + +
+ + + +## Function `to_address` + + + +
public fun to_address(v: vector<u8>): address
+
+ + + +
+Implementation + + +
public fun to_address(v: vector<u8>): address {
+    from_bytes<address>(v)
+}
+
+ + + +
+ + + +## Function `from_bytes` + +Package private native function to deserialize a type T. + +Note that this function does not put any constraint on T. If code uses this function to +deserialize a linear value, its their responsibility that the data they deserialize is +owned. + + +
public(friend) fun from_bytes<T>(bytes: vector<u8>): T
+
+ + + +
+Implementation + + +
public(friend) native fun from_bytes<T>(bytes: vector<u8>): T;
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+
+ + + +
diff --git a/release/v13/docs/GasSchedule.md b/release/v13/docs/GasSchedule.md new file mode 100644 index 00000000..daab6ac6 --- /dev/null +++ b/release/v13/docs/GasSchedule.md @@ -0,0 +1,540 @@ + + + +# Module `0x1::GasSchedule` + +Gas schedule configuration. + + +- [Struct `GasEntry`](#0x1_GasSchedule_GasEntry) +- [Resource `GasSchedule`](#0x1_GasSchedule_GasSchedule) +- [Function `gas_schedule`](#0x1_GasSchedule_gas_schedule) +- [Function `new_gas_entry`](#0x1_GasSchedule_new_gas_entry) +- [Function `new_constant_entry`](#0x1_GasSchedule_new_constant_entry) +- [Function `initialize`](#0x1_GasSchedule_initialize) +- [Function `new_gas_schedule`](#0x1_GasSchedule_new_gas_schedule) +- [Function `new_gas_schedule_for_test`](#0x1_GasSchedule_new_gas_schedule_for_test) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::ChainId;
+use 0x1::Config;
+use 0x1::CoreAddresses;
+
+ + + + + +## Struct `GasEntry` + + + +
struct GasEntry has copy, drop, store
+
+ + + +
+Fields + + +
+
+key: vector<u8> +
+
+ +
+
+val: u64 +
+
+ +
+
+ + +
+ + + +## Resource `GasSchedule` + + + +
struct GasSchedule has copy, drop, store, key
+
+ + + +
+Fields + + +
+
+entries: vector<GasSchedule::GasEntry> +
+
+ +
+
+ + +
+ + + +## Function `gas_schedule` + +The GasCost tracks: +- instruction cost: how much time/computational power is needed to perform the instruction +- memory cost: how much memory is required for the instruction, and storage overhead + + +
public fun gas_schedule(): vector<GasSchedule::GasEntry>
+
+ + + +
+Implementation + + +
public fun gas_schedule(): vector<GasEntry> {
+    let table = Vector::empty();
+
+    // instruction_schedule
+    // POP
+    Vector::push_back(&mut table, new_gas_entry(b"instr.pop", 1, 1));
+    // RET
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ret", 638, 1));
+    // BR_TRUE
+    Vector::push_back(&mut table, new_gas_entry(b"instr.br_true", 1, 1));
+    // BR_FALSE
+    Vector::push_back(&mut table, new_gas_entry(b"instr.br_false", 1, 1));
+    // BRANCH
+    Vector::push_back(&mut table, new_gas_entry(b"instr.branch", 1, 1));
+    // LD_U64
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ld_u64", 1, 1));
+    // LD_CONST
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ld_const.per_byte", 1, 1));
+    // LD_TRUE
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ld_true", 1, 1));
+    // LD_FALSE
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ld_false", 1, 1));
+    // COPY_LOC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.copy_loc.per_abs_mem_unit", 1, 1));
+    // MOVE_LOC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.move_loc.per_abs_mem_unit", 1, 1));
+    // ST_LOC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.st_loc.per_abs_mem_unit", 1, 1));
+    // MUT_BORROW_LOC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_loc", 2, 1));
+    // IMM_BORROW_LOC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_loc", 1, 1));
+    // MUT_BORROW_FIELD
+    Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_field", 1, 1));
+    // IMM_BORROW_FIELD
+    Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_field", 1, 1));
+    // CALL
+    Vector::push_back(&mut table, new_gas_entry(b"instr.call.per_arg", 1132, 1));
+    // PACK
+    Vector::push_back(&mut table, new_gas_entry(b"instr.pack.per_abs_mem_unit", 2, 1));
+    // UNPACK
+    Vector::push_back(&mut table, new_gas_entry(b"instr.unpack.per_abs_mem_unit", 2, 1));
+    // READ_REF
+    Vector::push_back(&mut table, new_gas_entry(b"instr.read_ref.per_abs_mem_unit", 1, 1));
+    // WRITE_REF
+    Vector::push_back(&mut table, new_gas_entry(b"instr.write_ref.per_abs_mem_unit", 1, 1));
+    // ADD
+    Vector::push_back(&mut table, new_gas_entry(b"instr.add", 1, 1));
+    // SUB
+    Vector::push_back(&mut table, new_gas_entry(b"instr.sub", 1, 1));
+    // MUL
+    Vector::push_back(&mut table, new_gas_entry(b"instr.mul", 1, 1));
+    // MOD
+    Vector::push_back(&mut table, new_gas_entry(b"instr.mod", 1, 1));
+    // DIV
+    Vector::push_back(&mut table, new_gas_entry(b"instr.div", 3, 1));
+    // BIT_OR
+    Vector::push_back(&mut table, new_gas_entry(b"instr.bit_or", 2, 1));
+    // BIT_AND
+    Vector::push_back(&mut table, new_gas_entry(b"instr.bit_and", 2, 1));
+    // XOR
+    Vector::push_back(&mut table, new_gas_entry(b"instr.xor", 1, 1));
+    // OR
+    Vector::push_back(&mut table, new_gas_entry(b"instr.or", 2, 1));
+    // AND
+    Vector::push_back(&mut table, new_gas_entry(b"instr.and", 1, 1));
+    // NOT
+    Vector::push_back(&mut table, new_gas_entry(b"instr.not", 1, 1));
+    // EQ
+    Vector::push_back(&mut table, new_gas_entry(b"instr.eq.per_abs_mem_unit", 1, 1));
+    // NEQ
+    Vector::push_back(&mut table, new_gas_entry(b"instr.neq.per_abs_mem_unit", 1, 1));
+    // LT
+    Vector::push_back(&mut table, new_gas_entry(b"instr.lt", 1, 1));
+    // GT
+    Vector::push_back(&mut table, new_gas_entry(b"instr.gt", 1, 1));
+    // LE
+    Vector::push_back(&mut table, new_gas_entry(b"instr.le", 2, 1));
+    // GE
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ge", 1, 1));
+    // ABORT
+    Vector::push_back(&mut table, new_gas_entry(b"instr.abort", 1, 1));
+    // NOP
+    Vector::push_back(&mut table, new_gas_entry(b"instr.nop", 1, 1));
+    // EXISTS
+    Vector::push_back(&mut table, new_gas_entry(b"instr.exists.per_abs_mem_unit", 41, 1));
+    // MUT_BORROW_GLOBAL
+    Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_global.per_abs_mem_unit", 21, 1));
+    // IML_BORROW_GLOBAL
+    Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_global.per_abs_mem_unit", 23, 1));
+    // MOVE_FROM
+    Vector::push_back(&mut table, new_gas_entry(b"instr.move_from.per_abs_mem_unit", 459, 1));
+    // MOVE_TO
+    Vector::push_back(&mut table, new_gas_entry(b"instr.move_to.per_abs_mem_unit", 13, 1));
+    // FREEZE_REF
+    Vector::push_back(&mut table, new_gas_entry(b"instr.freeze_ref", 1, 1));
+    // SHL
+    Vector::push_back(&mut table, new_gas_entry(b"instr.shl", 2, 1));
+    // SHR
+    Vector::push_back(&mut table, new_gas_entry(b"instr.shr", 1, 1));
+    // LD_U8
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ld_u8", 1, 1));
+    // LD_U128
+    Vector::push_back(&mut table, new_gas_entry(b"instr.ld_u128", 1, 1));
+
+    // CAST_U8
+    Vector::push_back(&mut table, new_gas_entry(b"instr.cast_u8", 2, 1));
+    // CAST_U64
+    Vector::push_back(&mut table, new_gas_entry(b"instr.cast_u64", 1, 1));
+    // CAST_U128
+    Vector::push_back(&mut table, new_gas_entry(b"instr.cast_u128", 1, 1));
+    // MUT_BORORW_FIELD_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_field_generic.base", 1, 1));
+    // IMM_BORORW_FIELD_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_field_generic.base", 1, 1));
+    // CALL_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.call_generic.per_arg", 582, 1));
+    // PACK_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.pack_generic.per_abs_mem_unit", 2, 1));
+    // UNPACK_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.unpack_generic.per_abs_mem_unit", 2, 1));
+    // EXISTS_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.exists_generic.per_abs_mem_unit", 34, 1));
+    // MUT_BORROW_GLOBAL_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_global_generic.per_abs_mem_unit", 15, 1));
+    // IMM_BORROW_GLOBAL_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_global_generic.per_abs_mem_unit", 14, 1));
+    // MOVE_FROM_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.move_from_generic.per_abs_mem_unit", 13, 1));
+    // MOVE_TO_GENERIC
+    Vector::push_back(&mut table, new_gas_entry(b"instr.move_to_generic.per_abs_mem_unit", 27, 1));
+
+    // VEC_PACK
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_pack.per_elem", 84, 1));
+    // VEC_LEN
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_len.base", 98, 1));
+    // VEC_IMM_BORROW
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_imm_borrow.base", 1334, 1));
+    // VEC_MUT_BORROW
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_mut_borrow.base", 1902, 1));
+    // VEC_PUSH_BACK
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_push_back.per_abs_mem_unit", 53, 1));
+    // VEC_POP_BACK
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_pop_back.base", 227, 1));
+    // VEC_UNPACK
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_unpack.per_expected_elem", 572, 1));
+    // VEC_SWAP
+    Vector::push_back(&mut table, new_gas_entry(b"instr.vec_swap.base", 1436, 1));
+
+    Vector::push_back(&mut table, new_constant_entry(b"instr.ld_u16", 3));
+    Vector::push_back(&mut table, new_constant_entry(b"instr.ld_u32", 2));
+    Vector::push_back(&mut table, new_constant_entry(b"instr.ld_u256", 3));
+    Vector::push_back(&mut table, new_constant_entry(b"instr.cast_u16", 3));
+    Vector::push_back(&mut table, new_constant_entry(b"instr.cast_u32", 2));
+    Vector::push_back(&mut table, new_constant_entry(b"instr.cast_u256", 3));
+
+    // native_schedule
+    //Hash::sha2_256 0
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.hash.sha2_256.per_byte", 21, 1));
+    //Hash::sha3_256 1
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.hash.sha3_256.per_byte", 64, 1));
+    //Signature::ed25519_verify 2
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.signature.ed25519_verify.per_byte", 61, 1));
+    //ED25519_THRESHOLD_VERIFY 3 this native funciton is deprecated
+    //Vector::push_back(&mut table, new_gas_entry(b"", 3351, 1));
+    //BSC::to_bytes 4
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.bcs.to_bytes.per_byte_serialized", 181, 1));
+    //Vector::length 5
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.length.base", 98, 1));
+    //Vector::empty 6
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.empty.base", 84, 1));
+    //Vector::borrow 7
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.borrow.base", 1334, 1));
+    //Vector::borrow_mut 8
+    //Vector::push_back(&mut table, new_gas_entry(b"", 1902, 1));
+    //Vector::push_back 9
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.push_back.legacy_per_abstract_memory_unit", 53, 1));
+    //Vector::pop_back 10
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.pop_back.base", 227, 1));
+    //Vector::destory_empty 11
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.destroy_empty.base", 572, 1));
+    //Vector::swap 12
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.swap.base", 1436, 1));
+    //Signature::ed25519_validate_pubkey 13
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.signature.ed25519_validate_key.per_byte", 26, 1));
+    //Signer::borrow_address 14
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.signer.borrow_address.base", 353, 1));
+    //Account::creator_signer 15
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.account.create_signer.base", 24, 1));
+    //Account::destroy_signer 16
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.account.destroy_signer.base", 212, 1));
+    //Event::emit_event 17
+    Vector::push_back(&mut table, new_gas_entry(b"nursery.event.write_to_event_store.unit_cost", 52, 1));
+    //BCS::to_address 18
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.bcs.to_address.per_byte", 26, 1));
+    //Token::name_of 19
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.token.name_of.base", 2002, 1));
+    //Hash::keccak_256 20
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.hash.keccak256.per_byte", 64, 1));
+    //Hash::ripemd160 21
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.hash.ripemd160.per_byte", 64, 1));
+    //Signature::native_ecrecover 22
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.signature.ec_recover.per_byte", 128, 1));
+    //U256::from_bytes 23
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.from_bytes.per_byte", 2, 1));
+    //U256::add 24
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.add.base", 4, 1));
+    //U256::sub 25
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.sub.base", 4, 1));
+    //U256::mul 26
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.mul.base", 4, 1));
+    //U256::div 27
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.div.base", 10, 1));
+    // U256::rem 28
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.rem.base", 4, 1));
+    // U256::pow 29
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.pow.base", 8, 1));
+    // TODO: settle down the gas cost
+    // Vector::append 30
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.append.legacy_per_abstract_memory_unit", 40, 1));
+    // Vector::remove 31
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.remove.legacy_per_abstract_memory_unit", 20, 1));
+    // Vector::reverse 32
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.reverse.legacy_per_abstract_memory_unit", 10, 1));
+    // Table::new_table_handle 33
+    Vector::push_back(&mut table, new_gas_entry(b"table.new_table_handle.base", 4, 1));
+    // Table::add_box 34
+    Vector::push_back(&mut table, new_gas_entry(b"table.add_box.per_byte_serialized", 4, 1));
+    // Table::borrow_box 35
+    Vector::push_back(&mut table, new_gas_entry(b"table.borrow_box.per_byte_serialized", 10, 1));
+    // Table::remove_box 36
+    Vector::push_back(&mut table, new_gas_entry(b"table.remove_box.per_byte_serialized", 8, 1));
+    // Table::contains_box 37
+    Vector::push_back(&mut table, new_gas_entry(b"table.contains_box.per_byte_serialized", 40, 1));
+    // Table::destroy_empty_box 38
+    Vector::push_back(&mut table, new_gas_entry(b"table.destroy_empty_box.base", 20, 1));
+    // Table::drop_unchecked_box 39
+    Vector::push_back(&mut table, new_gas_entry(b"table.drop_unchecked_box.base", 73, 1));
+    // string.check_utf8 40
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.check_utf8.per_byte", 4, 1));
+    // string.sub_str 41
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.sub_string.per_byte", 4, 1));
+    // string.is_char_boundary 42
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.is_char_boundary.base", 4, 1));
+    // Table::string.index_of 43
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.index_of.per_byte_searched", 4, 1));
+    // Table::string.index_of 44
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.frombcs.base", 4, 1));
+    // Table::string.index_of 45
+    Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.secp256k1.base", 4, 1));
+    // Table::string.index_of 46
+    Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.spawn_from.legacy_per_abstract_memory_unit", 4, 1));
+
+    Vector::push_back(&mut table, new_constant_entry(b"nursery.debug.print.base_cost", 1));
+    Vector::push_back(&mut table, new_constant_entry(b"nursery.debug.print_stack_trace.base_cost", 1));
+    Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.hash.sha2_256.legacy_min_input_len", 1));
+    Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.hash.sha3_256.legacy_min_input_len", 1));
+    Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.bcs.to_bytes.failure", 182));
+    Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.bcs.to_bytes.legacy_min_output_size", 1));
+
+    // constant config values
+    Vector::push_back(&mut table, new_constant_entry(b"txn.global_memory_per_byte_cost", 4));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.global_memory_per_byte_write_cost", 9));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.min_transaction_gas_units", 600));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.large_transaction_cutoff", 600));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.intrinsic_gas_per_byte", 8));
+    let maximum_number_of_gas_units: u64 = 40000000;//must less than base_block_gas_limit
+    if (ChainId::is_test() || ChainId::is_dev() || ChainId::is_halley()) {
+        maximum_number_of_gas_units = maximum_number_of_gas_units * 10
+    };
+    Vector::push_back(&mut table, new_constant_entry(b"txn.maximum_number_of_gas_units", maximum_number_of_gas_units));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.min_price_per_gas_unit", if (ChainId::is_test()) { 0 }  else { 1 }));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.max_price_per_gas_unit", 10000));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.max_transaction_size_in_bytes", 1024 * 128));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.gas_unit_scaling_factor", 1));
+    Vector::push_back(&mut table, new_constant_entry(b"txn.default_account_size", 800));
+
+    table
+}
+
+ + + +
+ + + +## Function `new_gas_entry` + + + +
public fun new_gas_entry(key: vector<u8>, instr_gas: u64, mem_gas: u64): GasSchedule::GasEntry
+
+ + + +
+Implementation + + +
public fun new_gas_entry(key: vector<u8>, instr_gas: u64, mem_gas: u64): GasEntry {
+    GasEntry {
+        key,
+        val: instr_gas + mem_gas,
+    }
+}
+
+ + + +
+ + + +## Function `new_constant_entry` + + + +
fun new_constant_entry(key: vector<u8>, val: u64): GasSchedule::GasEntry
+
+ + + +
+Implementation + + +
fun new_constant_entry(key: vector<u8>, val: u64): GasEntry {
+    GasEntry {
+        key,
+        val,
+    }
+}
+
+ + + +
+ + + +## Function `initialize` + +Initialize the gas schedule under the genesis account + + +
public fun initialize(account: &signer, gas_schedule: GasSchedule::GasSchedule)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, gas_schedule: GasSchedule) {
+    CoreAddresses::assert_genesis_address(account);
+    Config::publish_new_config<GasSchedule>(
+        account,
+        gas_schedule,
+    );
+}
+
+ + + +
+ + + +## Function `new_gas_schedule` + + + +
public fun new_gas_schedule(): GasSchedule::GasSchedule
+
+ + + +
+Implementation + + +
public fun new_gas_schedule(): GasSchedule {
+    GasSchedule {
+        entries: gas_schedule(),
+    }
+}
+
+ + + +
+ + + +## Function `new_gas_schedule_for_test` + + + +
public fun new_gas_schedule_for_test(): GasSchedule::GasSchedule
+
+ + + +
+Implementation + + +
public fun new_gas_schedule_for_test(): GasSchedule {
+    let entry = GasEntry {
+        key: Vector::empty(),
+        val: 1,
+    };
+    let entries = Vector::empty();
+    Vector::push_back(&mut entries, entry);
+
+    GasSchedule {
+        entries,
+    }
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Genesis.md b/release/v13/docs/Genesis.md new file mode 100644 index 00000000..6d449dab --- /dev/null +++ b/release/v13/docs/Genesis.md @@ -0,0 +1,656 @@ + + + +# Module `0x1::Genesis` + +The module for init Genesis + + +- [Function `initialize`](#0x1_Genesis_initialize) +- [Function `initialize_v2`](#0x1_Genesis_initialize_v2) +- [Function `do_initialize`](#0x1_Genesis_do_initialize) +- [Function `initialize_for_unit_tests`](#0x1_Genesis_initialize_for_unit_tests) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::Account;
+use 0x1::Block;
+use 0x1::BlockReward;
+use 0x1::ChainId;
+use 0x1::Collection;
+use 0x1::Config;
+use 0x1::ConsensusConfig;
+use 0x1::ConsensusStrategy;
+use 0x1::CoreAddresses;
+use 0x1::DummyToken;
+use 0x1::Epoch;
+use 0x1::GenesisNFT;
+use 0x1::GenesisSignerCapability;
+use 0x1::Option;
+use 0x1::PackageTxnManager;
+use 0x1::STC;
+use 0x1::STCUSDOracle;
+use 0x1::Signer;
+use 0x1::StdlibUpgradeScripts;
+use 0x1::Timestamp;
+use 0x1::Token;
+use 0x1::TransactionFee;
+use 0x1::TransactionPublishOption;
+use 0x1::TransactionTimeoutConfig;
+use 0x1::Treasury;
+use 0x1::TreasuryWithdrawDaoProposal;
+use 0x1::VMConfig;
+use 0x1::Vector;
+use 0x1::Version;
+
+ + + + + +## Function `initialize` + + + +
public entry fun initialize(stdlib_version: u64, reward_delay: u64, pre_mine_stc_amount: u128, time_mint_stc_amount: u128, time_mint_stc_period: u64, parent_hash: vector<u8>, association_auth_key: vector<u8>, genesis_auth_key: vector<u8>, chain_id: u8, genesis_timestamp: u64, uncle_rate_target: u64, epoch_block_count: u64, base_block_time_target: u64, base_block_difficulty_window: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8, script_allowed: bool, module_publishing_allowed: bool, instruction_schedule: vector<u8>, native_schedule: vector<u8>, global_memory_per_byte_cost: u64, global_memory_per_byte_write_cost: u64, min_transaction_gas_units: u64, large_transaction_cutoff: u64, instrinsic_gas_per_byte: u64, maximum_number_of_gas_units: u64, min_price_per_gas_unit: u64, max_price_per_gas_unit: u64, max_transaction_size_in_bytes: u64, gas_unit_scaling_factor: u64, default_account_size: u64, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64, transaction_timeout: u64)
+
+ + + +
+Implementation + + +
public entry fun initialize(
+    stdlib_version: u64,
+
+    // block reward config
+    reward_delay: u64,
+
+    pre_mine_stc_amount: u128,
+    time_mint_stc_amount: u128,
+    time_mint_stc_period: u64,
+    parent_hash: vector<u8>,
+    association_auth_key: vector<u8>,
+    genesis_auth_key: vector<u8>,
+    chain_id: u8,
+    genesis_timestamp: u64,
+
+    //consensus config
+    uncle_rate_target: u64,
+    epoch_block_count: u64,
+    base_block_time_target: u64,
+    base_block_difficulty_window: u64,
+    base_reward_per_block: u128,
+    base_reward_per_uncle_percent: u64,
+    min_block_time_target: u64,
+    max_block_time_target: u64,
+    base_max_uncles_per_block: u64,
+    base_block_gas_limit: u64,
+    strategy: u8,
+
+    //vm config
+    script_allowed: bool,
+    module_publishing_allowed: bool,
+    instruction_schedule: vector<u8>,
+    native_schedule: vector<u8>,
+
+    //gas constants
+    global_memory_per_byte_cost: u64,
+    global_memory_per_byte_write_cost: u64,
+    min_transaction_gas_units: u64,
+    large_transaction_cutoff: u64,
+    instrinsic_gas_per_byte: u64,
+    maximum_number_of_gas_units: u64,
+    min_price_per_gas_unit: u64,
+    max_price_per_gas_unit: u64,
+    max_transaction_size_in_bytes: u64,
+    gas_unit_scaling_factor: u64,
+    default_account_size: u64,
+
+    // dao config
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+
+    // transaction timeout config
+    transaction_timeout: u64,
+) {
+    assert!(Timestamp::is_genesis(), 1);
+    // create genesis account
+    let genesis_account = Account::create_genesis_account(CoreAddresses::GENESIS_ADDRESS());
+    //Init global time
+    Timestamp::initialize(&genesis_account, genesis_timestamp);
+    ChainId::initialize(&genesis_account, chain_id);
+    ConsensusStrategy::initialize(&genesis_account, strategy);
+    Block::initialize(&genesis_account, parent_hash);
+    TransactionPublishOption::initialize(
+        &genesis_account,
+        script_allowed,
+        module_publishing_allowed,
+    );
+    // init config
+    VMConfig::initialize(
+        &genesis_account,
+        instruction_schedule,
+        native_schedule,
+        global_memory_per_byte_cost,
+        global_memory_per_byte_write_cost,
+        min_transaction_gas_units,
+        large_transaction_cutoff,
+        instrinsic_gas_per_byte,
+        maximum_number_of_gas_units,
+        min_price_per_gas_unit,
+        max_price_per_gas_unit,
+        max_transaction_size_in_bytes,
+        gas_unit_scaling_factor,
+        default_account_size,
+    );
+    TransactionTimeoutConfig::initialize(&genesis_account, transaction_timeout);
+    ConsensusConfig::initialize(
+        &genesis_account,
+        uncle_rate_target,
+        epoch_block_count,
+        base_block_time_target,
+        base_block_difficulty_window,
+        base_reward_per_block,
+        base_reward_per_uncle_percent,
+        min_block_time_target,
+        max_block_time_target,
+        base_max_uncles_per_block,
+        base_block_gas_limit,
+        strategy,
+    );
+    Epoch::initialize(&genesis_account);
+    BlockReward::initialize(&genesis_account, reward_delay);
+    TransactionFee::initialize(&genesis_account);
+    let association = Account::create_genesis_account(
+        CoreAddresses::ASSOCIATION_ROOT_ADDRESS(),
+    );
+    Config::publish_new_config<Version::Version>(&genesis_account, Version::new_version(stdlib_version));
+    // stdlib use two phase upgrade strategy.
+    PackageTxnManager::update_module_upgrade_strategy(
+        &genesis_account,
+        PackageTxnManager::get_strategy_two_phase(),
+        Option::some(0u64),
+    );
+    // stc should be initialized after genesis_account's module upgrade strategy set.
+    {
+        STC::initialize(&genesis_account, voting_delay, voting_period, voting_quorum_rate, min_action_delay);
+        Account::do_accept_token<STC>(&genesis_account);
+        DummyToken::initialize(&genesis_account);
+        Account::do_accept_token<STC>(&association);
+    };
+    if (pre_mine_stc_amount > 0) {
+        let stc = Token::mint<STC>(&genesis_account, pre_mine_stc_amount);
+        Account::deposit(Signer::address_of(&association), stc);
+    };
+    if (time_mint_stc_amount > 0) {
+        let cap = Token::remove_mint_capability<STC>(&genesis_account);
+        let key = Token::issue_linear_mint_key<STC>(&cap, time_mint_stc_amount, time_mint_stc_period);
+        Token::add_mint_capability(&genesis_account, cap);
+        Collection::put(&association, key);
+    };
+    // only dev network set genesis auth key.
+    if (!Vector::is_empty(&genesis_auth_key)) {
+        let genesis_rotate_key_cap = Account::extract_key_rotation_capability(&genesis_account);
+        Account::rotate_authentication_key_with_capability(&genesis_rotate_key_cap, genesis_auth_key);
+        Account::restore_key_rotation_capability(genesis_rotate_key_cap);
+    };
+    let assoc_rotate_key_cap = Account::extract_key_rotation_capability(&association);
+    Account::rotate_authentication_key_with_capability(&assoc_rotate_key_cap, association_auth_key);
+    Account::restore_key_rotation_capability(assoc_rotate_key_cap);
+    //Start time, Timestamp::is_genesis() will return false. this call should at the end of genesis init.
+    Timestamp::set_time_has_started(&genesis_account);
+    Account::release_genesis_signer(genesis_account);
+    Account::release_genesis_signer(association);
+}
+
+ + + +
+ + + +## Function `initialize_v2` + + + +
public entry fun initialize_v2(stdlib_version: u64, reward_delay: u64, total_stc_amount: u128, pre_mine_stc_amount: u128, time_mint_stc_amount: u128, time_mint_stc_period: u64, parent_hash: vector<u8>, association_auth_key: vector<u8>, genesis_auth_key: vector<u8>, chain_id: u8, genesis_timestamp: u64, uncle_rate_target: u64, epoch_block_count: u64, base_block_time_target: u64, base_block_difficulty_window: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8, script_allowed: bool, module_publishing_allowed: bool, instruction_schedule: vector<u8>, native_schedule: vector<u8>, global_memory_per_byte_cost: u64, global_memory_per_byte_write_cost: u64, min_transaction_gas_units: u64, large_transaction_cutoff: u64, instrinsic_gas_per_byte: u64, maximum_number_of_gas_units: u64, min_price_per_gas_unit: u64, max_price_per_gas_unit: u64, max_transaction_size_in_bytes: u64, gas_unit_scaling_factor: u64, default_account_size: u64, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64, transaction_timeout: u64)
+
+ + + +
+Implementation + + +
public entry fun initialize_v2(
+    stdlib_version: u64,
+
+    // block reward and stc config
+    reward_delay: u64,
+    total_stc_amount: u128,
+    pre_mine_stc_amount: u128,
+    time_mint_stc_amount: u128,
+    time_mint_stc_period: u64,
+
+    parent_hash: vector<u8>,
+    association_auth_key: vector<u8>,
+    genesis_auth_key: vector<u8>,
+    chain_id: u8,
+    genesis_timestamp: u64,
+
+    //consensus config
+    uncle_rate_target: u64,
+    epoch_block_count: u64,
+    base_block_time_target: u64,
+    base_block_difficulty_window: u64,
+    base_reward_per_block: u128,
+    base_reward_per_uncle_percent: u64,
+    min_block_time_target: u64,
+    max_block_time_target: u64,
+    base_max_uncles_per_block: u64,
+    base_block_gas_limit: u64,
+    strategy: u8,
+
+    //vm config
+    script_allowed: bool,
+    module_publishing_allowed: bool,
+    instruction_schedule: vector<u8>,
+    native_schedule: vector<u8>,
+
+    //gas constants
+    global_memory_per_byte_cost: u64,
+    global_memory_per_byte_write_cost: u64,
+    min_transaction_gas_units: u64,
+    large_transaction_cutoff: u64,
+    instrinsic_gas_per_byte: u64,
+    maximum_number_of_gas_units: u64,
+    min_price_per_gas_unit: u64,
+    max_price_per_gas_unit: u64,
+    max_transaction_size_in_bytes: u64,
+    gas_unit_scaling_factor: u64,
+    default_account_size: u64,
+
+    // dao config
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+
+    // transaction timeout config
+    transaction_timeout: u64,
+) {
+    Self::do_initialize(
+    stdlib_version,
+    reward_delay,
+    total_stc_amount,
+    pre_mine_stc_amount,
+    time_mint_stc_amount,
+    time_mint_stc_period,
+    parent_hash,
+    association_auth_key,
+    genesis_auth_key,
+    chain_id,
+    genesis_timestamp,
+    uncle_rate_target,
+    epoch_block_count,
+    base_block_time_target,
+    base_block_difficulty_window,
+    base_reward_per_block,
+    base_reward_per_uncle_percent,
+    min_block_time_target,
+    max_block_time_target,
+    base_max_uncles_per_block,
+    base_block_gas_limit,
+    strategy,
+    script_allowed,
+    module_publishing_allowed,
+    instruction_schedule,
+    native_schedule,
+    global_memory_per_byte_cost,
+    global_memory_per_byte_write_cost,
+    min_transaction_gas_units,
+    large_transaction_cutoff,
+    instrinsic_gas_per_byte,
+    maximum_number_of_gas_units,
+    min_price_per_gas_unit,
+    max_price_per_gas_unit,
+    max_transaction_size_in_bytes,
+    gas_unit_scaling_factor,
+    default_account_size,
+    voting_delay,
+    voting_period,
+    voting_quorum_rate,
+    min_action_delay,
+    transaction_timeout,
+    );
+}
+
+ + + +
+ + + +## Function `do_initialize` + + + +
fun do_initialize(stdlib_version: u64, reward_delay: u64, total_stc_amount: u128, pre_mine_stc_amount: u128, time_mint_stc_amount: u128, time_mint_stc_period: u64, parent_hash: vector<u8>, association_auth_key: vector<u8>, genesis_auth_key: vector<u8>, chain_id: u8, genesis_timestamp: u64, uncle_rate_target: u64, epoch_block_count: u64, base_block_time_target: u64, base_block_difficulty_window: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8, script_allowed: bool, module_publishing_allowed: bool, instruction_schedule: vector<u8>, native_schedule: vector<u8>, global_memory_per_byte_cost: u64, global_memory_per_byte_write_cost: u64, min_transaction_gas_units: u64, large_transaction_cutoff: u64, instrinsic_gas_per_byte: u64, maximum_number_of_gas_units: u64, min_price_per_gas_unit: u64, max_price_per_gas_unit: u64, max_transaction_size_in_bytes: u64, gas_unit_scaling_factor: u64, default_account_size: u64, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64, transaction_timeout: u64)
+
+ + + +
+Implementation + + +
fun do_initialize(
+    stdlib_version: u64,
+
+    // block reward and stc config
+    reward_delay: u64,
+    total_stc_amount: u128,
+    pre_mine_stc_amount: u128,
+    time_mint_stc_amount: u128,
+    time_mint_stc_period: u64,
+
+    parent_hash: vector<u8>,
+    association_auth_key: vector<u8>,
+    genesis_auth_key: vector<u8>,
+    chain_id: u8,
+    genesis_timestamp: u64,
+
+    //consensus config
+    uncle_rate_target: u64,
+    epoch_block_count: u64,
+    base_block_time_target: u64,
+    base_block_difficulty_window: u64,
+    base_reward_per_block: u128,
+    base_reward_per_uncle_percent: u64,
+    min_block_time_target: u64,
+    max_block_time_target: u64,
+    base_max_uncles_per_block: u64,
+    base_block_gas_limit: u64,
+    strategy: u8,
+
+    //vm config
+    script_allowed: bool,
+    module_publishing_allowed: bool,
+    instruction_schedule: vector<u8>,
+    native_schedule: vector<u8>,
+
+    //gas constants
+    global_memory_per_byte_cost: u64,
+    global_memory_per_byte_write_cost: u64,
+    min_transaction_gas_units: u64,
+    large_transaction_cutoff: u64,
+    instrinsic_gas_per_byte: u64,
+    maximum_number_of_gas_units: u64,
+    min_price_per_gas_unit: u64,
+    max_price_per_gas_unit: u64,
+    max_transaction_size_in_bytes: u64,
+    gas_unit_scaling_factor: u64,
+    default_account_size: u64,
+
+    // dao config
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+
+    // transaction timeout config
+    transaction_timeout: u64,
+){
+    Timestamp::assert_genesis();
+    // create genesis account
+    let genesis_account = Account::create_genesis_account(CoreAddresses::GENESIS_ADDRESS());
+    //Init global time
+    Timestamp::initialize(&genesis_account, genesis_timestamp);
+    ChainId::initialize(&genesis_account, chain_id);
+    ConsensusStrategy::initialize(&genesis_account, strategy);
+    Block::initialize(&genesis_account, parent_hash);
+    TransactionPublishOption::initialize(
+        &genesis_account,
+        script_allowed,
+        module_publishing_allowed,
+    );
+    // init config
+    VMConfig::initialize(
+        &genesis_account,
+        instruction_schedule,
+        native_schedule,
+        global_memory_per_byte_cost,
+        global_memory_per_byte_write_cost,
+        min_transaction_gas_units,
+        large_transaction_cutoff,
+        instrinsic_gas_per_byte,
+        maximum_number_of_gas_units,
+        min_price_per_gas_unit,
+        max_price_per_gas_unit,
+        max_transaction_size_in_bytes,
+        gas_unit_scaling_factor,
+        default_account_size,
+    );
+    TransactionTimeoutConfig::initialize(&genesis_account, transaction_timeout);
+    ConsensusConfig::initialize(
+        &genesis_account,
+        uncle_rate_target,
+        epoch_block_count,
+        base_block_time_target,
+        base_block_difficulty_window,
+        base_reward_per_block,
+        base_reward_per_uncle_percent,
+        min_block_time_target,
+        max_block_time_target,
+        base_max_uncles_per_block,
+        base_block_gas_limit,
+        strategy,
+    );
+    Epoch::initialize(&genesis_account);
+    let association = Account::create_genesis_account(
+        CoreAddresses::ASSOCIATION_ROOT_ADDRESS(),
+    );
+    Config::publish_new_config<Version::Version>(&genesis_account, Version::new_version(stdlib_version));
+    // stdlib use two phase upgrade strategy.
+    PackageTxnManager::update_module_upgrade_strategy(
+        &genesis_account,
+        PackageTxnManager::get_strategy_two_phase(),
+        Option::some(0u64),
+    );
+    BlockReward::initialize(&genesis_account, reward_delay);
+
+    // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init.
+    let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay);
+    Account::do_accept_token<STC>(&genesis_account);
+    Account::do_accept_token<STC>(&association);
+
+    DummyToken::initialize(&genesis_account);
+
+    if (pre_mine_stc_amount > 0) {
+        let stc = Treasury::withdraw_with_capability<STC>(&mut withdraw_cap, pre_mine_stc_amount);
+        Account::deposit(Signer::address_of(&association), stc);
+    };
+    if (time_mint_stc_amount > 0) {
+        let liner_withdraw_cap = Treasury::issue_linear_withdraw_capability<STC>(&mut withdraw_cap, time_mint_stc_amount, time_mint_stc_period);
+        Treasury::add_linear_withdraw_capability(&association, liner_withdraw_cap);
+    };
+
+    // Lock the TreasuryWithdrawCapability to Dao
+    TreasuryWithdrawDaoProposal::plugin(&genesis_account, withdraw_cap);
+
+    TransactionFee::initialize(&genesis_account);
+
+    // only test/dev network set genesis auth key.
+    if (!Vector::is_empty(&genesis_auth_key)) {
+        let genesis_rotate_key_cap = Account::extract_key_rotation_capability(&genesis_account);
+        Account::rotate_authentication_key_with_capability(&genesis_rotate_key_cap, genesis_auth_key);
+        Account::restore_key_rotation_capability(genesis_rotate_key_cap);
+    };
+
+    let assoc_rotate_key_cap = Account::extract_key_rotation_capability(&association);
+    Account::rotate_authentication_key_with_capability(&assoc_rotate_key_cap, association_auth_key);
+    Account::restore_key_rotation_capability(assoc_rotate_key_cap);
+
+    // v5 -> v6
+    {
+        let cap = Account::remove_signer_capability(&genesis_account);
+        GenesisSignerCapability::initialize(&genesis_account, cap);
+        //register oracle
+        STCUSDOracle::register(&genesis_account);
+        let merkle_root = x"5969f0e8e19f8769276fb638e6060d5c02e40088f5fde70a6778dd69d659ee6d";
+        let image = b"ipfs://QmSPcvcXgdtHHiVTAAarzTeubk5X3iWymPAoKBfiRFjPMY";
+        GenesisNFT::initialize(&genesis_account, merkle_root, 1639u64, image);
+    };
+    StdlibUpgradeScripts::do_upgrade_from_v6_to_v7_with_language_version(&genesis_account, 6);
+    StdlibUpgradeScripts::do_upgrade_from_v11_to_v12(&genesis_account);
+    StdlibUpgradeScripts::do_upgrade_from_v12_to_v13(&genesis_account);
+    //Start time, Timestamp::is_genesis() will return false. this call should at the end of genesis init.
+    Timestamp::set_time_has_started(&genesis_account);
+    Account::release_genesis_signer(genesis_account);
+    Account::release_genesis_signer(association);
+}
+
+ + + +
+ + + +## Function `initialize_for_unit_tests` + +Init the genesis for unit tests + + +
public fun initialize_for_unit_tests()
+
+ + + +
+Implementation + + +
public fun initialize_for_unit_tests(){
+    let stdlib_version: u64 = 6;
+    let reward_delay: u64 = 7;
+    let total_stc_amount: u128 = 3185136000000000000u128;
+    let pre_mine_stc_amount: u128 = 159256800000000000u128;
+    let time_mint_stc_amount: u128 = (85043130u128 * 3u128 + 74213670u128 * 3u128)*1000000000u128;
+    let time_mint_stc_period: u64 = 1000000000;
+
+    let parent_hash: vector<u8> = x"0000000000000000000000000000000000000000000000000000000000000000";
+    let association_auth_key: vector<u8> = x"0000000000000000000000000000000000000000000000000000000000000000";
+    let genesis_auth_key: vector<u8> = x"0000000000000000000000000000000000000000000000000000000000000000";
+    let chain_id: u8 = 255;
+    let genesis_timestamp: u64 =0;
+
+    //consensus config
+    let uncle_rate_target: u64 = 80;
+    let epoch_block_count: u64 = 240;
+    let base_block_time_target: u64 = 10000;
+    let base_block_difficulty_window: u64 = 24;
+    let base_reward_per_block: u128 = 1000000000;
+    let base_reward_per_uncle_percent: u64 = 10;
+    let min_block_time_target: u64 = 1000;
+    let max_block_time_target: u64 = 20000;
+    let base_max_uncles_per_block: u64 = 2;
+    let base_block_gas_limit: u64 = 500000000;
+    let strategy: u8 = 0;
+
+    //vm config
+    let script_allowed: bool = true;
+    let module_publishing_allowed: bool = true;
+    //TODO init the gas table.
+    let instruction_schedule: vector<u8> = Vector::empty();
+    let native_schedule: vector<u8> = Vector::empty();
+
+    //gas constants
+    let global_memory_per_byte_cost: u64 = 1;
+    let global_memory_per_byte_write_cost: u64 = 1;
+    let min_transaction_gas_units: u64 = 1;
+    let large_transaction_cutoff: u64 = 1;
+    let instrinsic_gas_per_byte: u64 = 1;
+    let maximum_number_of_gas_units: u64 = 1;
+    let min_price_per_gas_unit: u64 = 1;
+    let max_price_per_gas_unit: u64 = 10000;
+    let max_transaction_size_in_bytes: u64 = 1024*1024;
+    let gas_unit_scaling_factor: u64 = 1;
+    let default_account_size: u64 = 600;
+
+    // dao config
+    let voting_delay: u64 = 1000;
+    let voting_period: u64 =  6000;
+    let voting_quorum_rate: u8 = 4;
+    let min_action_delay: u64 = 1000;
+
+    // transaction timeout config
+    let transaction_timeout: u64 = 10000;
+
+    Self::do_initialize(
+        stdlib_version,
+        reward_delay,
+        total_stc_amount,
+        pre_mine_stc_amount,
+        time_mint_stc_amount,
+        time_mint_stc_period,
+        parent_hash,
+        association_auth_key,
+        genesis_auth_key,
+        chain_id,
+        genesis_timestamp,
+        uncle_rate_target,
+        epoch_block_count,
+        base_block_time_target,
+        base_block_difficulty_window,
+        base_reward_per_block,
+        base_reward_per_uncle_percent,
+        min_block_time_target,
+        max_block_time_target,
+        base_max_uncles_per_block,
+        base_block_gas_limit,
+        strategy,
+        script_allowed,
+        module_publishing_allowed,
+        instruction_schedule,
+        native_schedule,
+        global_memory_per_byte_cost,
+        global_memory_per_byte_write_cost,
+        min_transaction_gas_units,
+        large_transaction_cutoff,
+        instrinsic_gas_per_byte,
+        maximum_number_of_gas_units,
+        min_price_per_gas_unit,
+        max_price_per_gas_unit,
+        max_transaction_size_in_bytes,
+        gas_unit_scaling_factor,
+        default_account_size,
+        voting_delay,
+        voting_period,
+        voting_quorum_rate,
+        min_action_delay,
+        transaction_timeout,
+    );
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_partial = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/GenesisNFT.md b/release/v13/docs/GenesisNFT.md new file mode 100644 index 00000000..5f4ab2de --- /dev/null +++ b/release/v13/docs/GenesisNFT.md @@ -0,0 +1,49 @@ + + + +# Module `0x1::GenesisNFTScripts` + + + +- [Function `mint`](#0x1_GenesisNFTScripts_mint) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::GenesisNFT;
+
+ + + + + +## Function `mint` + +Mint a GenesisNFT + + +
public entry fun mint(sender: signer, index: u64, merkle_proof: vector<vector<u8>>)
+
+ + + +
+Implementation + + +
public entry fun mint(sender: signer, index: u64, merkle_proof:vector<vector<u8>>) {
+    GenesisNFT::mint_entry(sender, index, merkle_proof);
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+
diff --git a/release/v13/docs/GenesisSignerCapability.md b/release/v13/docs/GenesisSignerCapability.md new file mode 100644 index 00000000..5ffea8c8 --- /dev/null +++ b/release/v13/docs/GenesisSignerCapability.md @@ -0,0 +1,114 @@ + + + +# Module `0x1::GenesisSignerCapability` + + + +- [Resource `GenesisSignerCapability`](#0x1_GenesisSignerCapability_GenesisSignerCapability) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_GenesisSignerCapability_initialize) +- [Function `get_genesis_signer`](#0x1_GenesisSignerCapability_get_genesis_signer) + + +
use 0x1::Account;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+
+ + + + + +## Resource `GenesisSignerCapability` + + + +
struct GenesisSignerCapability has key
+
+ + + +
+Fields + + +
+
+cap: Account::SignerCapability +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ENOT_GENESIS_ACCOUNT: u64 = 11;
+
+ + + + + +## Function `initialize` + + + +
public(friend) fun initialize(signer: &signer, cap: Account::SignerCapability)
+
+ + + +
+Implementation + + +
public(friend) fun initialize(signer: &signer, cap: Account::SignerCapability) {
+    CoreAddresses::assert_genesis_address(signer);
+    assert!(
+        Account::signer_address(&cap) == CoreAddresses::GENESIS_ADDRESS(),
+        Errors::invalid_argument(ENOT_GENESIS_ACCOUNT)
+    );
+    move_to(signer, GenesisSignerCapability{cap});
+}
+
+ + + +
+ + + +## Function `get_genesis_signer` + + + +
public(friend) fun get_genesis_signer(): signer
+
+ + + +
+Implementation + + +
public(friend) fun get_genesis_signer(): signer acquires GenesisSignerCapability {
+    let cap = borrow_global<GenesisSignerCapability>(CoreAddresses::GENESIS_ADDRESS());
+    Account::create_signer_with_cap(&cap.cap)
+}
+
+ + + +
diff --git a/release/v13/docs/Hash.md b/release/v13/docs/Hash.md new file mode 100644 index 00000000..47f83022 --- /dev/null +++ b/release/v13/docs/Hash.md @@ -0,0 +1,116 @@ + + + +# Module `0x1::Hash` + +The module provide sha-hash functionality for Move. + + +- [Function `sha2_256`](#0x1_Hash_sha2_256) +- [Function `sha3_256`](#0x1_Hash_sha3_256) +- [Function `keccak_256`](#0x1_Hash_keccak_256) +- [Function `ripemd160`](#0x1_Hash_ripemd160) +- [Module Specification](#@Module_Specification_0) + + +
+ + + + + +## Function `sha2_256` + + + +
public fun sha2_256(data: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
native public fun sha2_256(data: vector<u8>): vector<u8>;
+
+ + + +
+ + + +## Function `sha3_256` + + + +
public fun sha3_256(data: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
native public fun sha3_256(data: vector<u8>): vector<u8>;
+
+ + + +
+ + + +## Function `keccak_256` + + + +
public fun keccak_256(data: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
native public fun keccak_256(data: vector<u8>): vector<u8>;
+
+ + + +
+ + + +## Function `ripemd160` + + + +
public fun ripemd160(data: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
native public fun ripemd160(data: vector<u8>): vector<u8>;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/LanguageVersion.md b/release/v13/docs/LanguageVersion.md new file mode 100644 index 00000000..1c8bb89d --- /dev/null +++ b/release/v13/docs/LanguageVersion.md @@ -0,0 +1,114 @@ + + + +# Module `0x1::LanguageVersion` + + + +- [Struct `LanguageVersion`](#0x1_LanguageVersion_LanguageVersion) +- [Function `new`](#0x1_LanguageVersion_new) +- [Function `version`](#0x1_LanguageVersion_version) + + +
+ + + + + +## Struct `LanguageVersion` + + + +
struct LanguageVersion has copy, drop, store
+
+ + + +
+Fields + + +
+
+major: u64 +
+
+ +
+
+ + +
+ + + +## Function `new` + + + +
public fun new(version: u64): LanguageVersion::LanguageVersion
+
+ + + +
+Implementation + + +
public fun new(version: u64): LanguageVersion {
+    LanguageVersion {major: version}
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `version` + + + +
public fun version(version: &LanguageVersion::LanguageVersion): u64
+
+ + + +
+Implementation + + +
public fun version(version: &LanguageVersion): u64 {
+    version.major
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
diff --git a/release/v13/docs/Math.md b/release/v13/docs/Math.md new file mode 100644 index 00000000..73b4eab0 --- /dev/null +++ b/release/v13/docs/Math.md @@ -0,0 +1,377 @@ + + + +# Module `0x1::Math` + +The module provide some improved math calculations. + + +- [Constants](#@Constants_0) +- [Function `u64_max`](#0x1_Math_u64_max) +- [Function `u128_max`](#0x1_Math_u128_max) +- [Function `sqrt`](#0x1_Math_sqrt) +- [Function `pow`](#0x1_Math_pow) +- [Function `mul_div`](#0x1_Math_mul_div) +- [Function `sum`](#0x1_Math_sum) +- [Function `avg`](#0x1_Math_avg) +- [Module Specification](#@Module_Specification_1) + + +
+ + + + + +## Constants + + + + + + +
const U128_MAX: u128 = 340282366920938463463374607431768211455;
+
+ + + + + + + +
const U64_MAX: u64 = 18446744073709551615;
+
+ + + + + +## Function `u64_max` + +u64::MAX + + +
public fun u64_max(): u64
+
+ + + +
+Implementation + + +
public fun u64_max(): u64 {
+    U64_MAX
+}
+
+ + + +
+ + + +## Function `u128_max` + +u128::MAX + + +
public fun u128_max(): u128
+
+ + + +
+Implementation + + +
public fun u128_max(): u128 {
+    U128_MAX
+}
+
+ + + +
+ + + +## Function `sqrt` + +babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) + + +
public fun sqrt(y: u128): u64
+
+ + + +
+Implementation + + +
public fun sqrt(y: u128): u64 {
+    if (y < 4) {
+        if (y == 0) {
+            0u64
+        } else {
+            1u64
+        }
+    } else {
+        let z = y;
+        let x = y / 2 + 1;
+        while (x < z) {
+            z = x;
+            x = (y / x + x) / 2;
+        };
+        (z as u64)
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+pragma verify = false;
+aborts_if [abstract] false;
+ensures [abstract] result == spec_sqrt();
+
+ + +We use an uninterpreted function to represent the result of sqrt. The actual value +does not matter for the verification of callers. + + + + + +
fun spec_sqrt(): u128;
+
+ + + +
+ + + +## Function `pow` + +calculate the y pow of x. + + +
public fun pow(x: u64, y: u64): u128
+
+ + + +
+Implementation + + +
public fun pow(x: u64, y: u64): u128 {
+    let result = 1u128;
+    let z = y;
+    let u = (x as u128);
+    while (z > 0) {
+        if (z % 2 == 1) {
+            result = (u * result as u128);
+        };
+        u = (u * u as u128);
+        z = z / 2;
+    };
+    result
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+pragma verify = false;
+aborts_if [abstract] false;
+ensures [abstract] result == spec_pow();
+
+ + +We use an uninterpreted function to represent the result of pow. The actual value +does not matter for the verification of callers. + + + + + +
fun spec_pow(): u128;
+
+ + + +
+ + + +## Function `mul_div` + +https://medium.com/coinmonks/math-in-solidity-part-3-percents-and-proportions-4db014e080b1 +calculate x * y /z with as little loss of precision as possible and avoid overflow + + +
public fun mul_div(x: u128, y: u128, z: u128): u128
+
+ + + +
+Implementation + + +
public fun mul_div(x: u128, y: u128, z: u128): u128 {
+    if (y == z) {
+        return x
+    };
+    if (x == z) {
+        return y
+    };
+    let a = x / z;
+    let b = x % z;
+    //x = a * z + b;
+    let c = y / z;
+    let d = y % z;
+    //y = c * z + d;
+    a * c * z + a * d + b * c + b * d / z
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+include MulDivAbortsIf;
+aborts_if [abstract] false;
+ensures [abstract] result == spec_mul_div();
+
+ + + + + + + +
schema MulDivAbortsIf {
+    x: u128;
+    y: u128;
+    z: u128;
+    aborts_if y != z && x > z && z == 0;
+    aborts_if y != z && x > z && z!=0 && x/z*y > MAX_U128;
+    aborts_if y != z && x <= z && z == 0;
+    aborts_if y != z && x <= z && x / z * (x % z) > MAX_U128;
+    aborts_if y != z && x <= z && x / z * (x % z) * z > MAX_U128;
+    aborts_if y != z && x <= z && x / z * (y % z) > MAX_U128;
+    aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) > MAX_U128;
+    aborts_if y != z && x <= z && x % z * (y / z) > MAX_U128;
+    aborts_if y != z && x <= z && x % z * (y % z) > MAX_U128;
+    aborts_if y != z && x <= z && x % z * (y % z) / z > MAX_U128;
+    aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) + x % z * (y / z) > MAX_U128;
+    aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) + x % z * (y / z) + x % z * (y % z) / z > MAX_U128;
+}
+
+ + + + + + + +
fun spec_mul_div(): u128;
+
+ + + +
+ + + +## Function `sum` + +calculate sum of nums + + +
public fun sum(nums: &vector<u128>): u128
+
+ + + +
+Implementation + + +
public fun sum(nums: &vector<u128>): u128 {
+    let len = Vector::length(nums);
+    let i = 0;
+    let sum = 0;
+    while (i < len){
+        sum = sum + *Vector::borrow(nums, i);
+        i = i + 1;
+    };
+    sum
+}
+
+ + + +
+ + + +## Function `avg` + +calculate average of nums + + +
public fun avg(nums: &vector<u128>): u128
+
+ + + +
+Implementation + + +
public fun avg(nums: &vector<u128>): u128{
+    let len = Vector::length(nums);
+    let sum = sum(nums);
+    sum/(len as u128)
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/MerkleNFT.md b/release/v13/docs/MerkleNFT.md new file mode 100644 index 00000000..95bae1b9 --- /dev/null +++ b/release/v13/docs/MerkleNFT.md @@ -0,0 +1,330 @@ + + + +# Module `0x1::MerkleNFTDistributor` + + + +- [Resource `MerkleNFTDistribution`](#0x1_MerkleNFTDistributor_MerkleNFTDistribution) +- [Constants](#@Constants_0) +- [Function `register`](#0x1_MerkleNFTDistributor_register) +- [Function `mint_with_cap`](#0x1_MerkleNFTDistributor_mint_with_cap) +- [Function `encode_leaf`](#0x1_MerkleNFTDistributor_encode_leaf) +- [Function `set_minted_`](#0x1_MerkleNFTDistributor_set_minted_) +- [Function `verify_proof`](#0x1_MerkleNFTDistributor_verify_proof) +- [Function `is_minted`](#0x1_MerkleNFTDistributor_is_minted) +- [Function `is_minted_`](#0x1_MerkleNFTDistributor_is_minted_) + + +
use 0x1::BCS;
+use 0x1::Errors;
+use 0x1::Hash;
+use 0x1::MerkleProof;
+use 0x1::NFT;
+use 0x1::Signer;
+use 0x1::Vector;
+
+ + + + + +## Resource `MerkleNFTDistribution` + + + +
struct MerkleNFTDistribution<NFTMeta: copy, drop, store> has key
+
+ + + +
+Fields + + +
+
+merkle_root: vector<u8> +
+
+ +
+
+claimed_bitmap: vector<u128> +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_NO_MINT_CAPABILITY: u64 = 1002;
+
+ + + + + + + +
const ALREADY_MINTED: u64 = 1000;
+
+ + + + + + + +
const INVALID_PROOF: u64 = 1001;
+
+ + + + + +## Function `register` + + + +
public fun register<NFTMeta: copy, drop, store, Info: copy, drop, store>(signer: &signer, merkle_root: vector<u8>, leafs: u64, info: Info, meta: NFT::Metadata): NFT::MintCapability<NFTMeta>
+
+ + + +
+Implementation + + +
public fun register<NFTMeta: copy + store + drop, Info: copy + store + drop>(signer: &signer, merkle_root: vector<u8>, leafs: u64, info: Info, meta: Metadata): MintCapability<NFTMeta> {
+    let bitmap_count = leafs / 128;
+    if (bitmap_count * 128 < leafs) {
+        bitmap_count = bitmap_count + 1;
+    };
+    let claimed_bitmap = Vector::empty();
+    let j = 0;
+    while (j < bitmap_count) {
+        Vector::push_back( &mut claimed_bitmap, 0u128);
+        j = j + 1;
+    };
+    let distribution = MerkleNFTDistribution<NFTMeta>{
+        merkle_root,
+        claimed_bitmap
+    };
+    NFT::register<NFTMeta, Info>(signer, info, meta);
+    move_to(signer, distribution);
+    NFT::remove_mint_capability<NFTMeta>(signer)
+}
+
+ + + +
+ + + +## Function `mint_with_cap` + + + +
public fun mint_with_cap<NFTMeta: copy, drop, store, NFTBody: store, Info: copy, drop, store>(sender: &signer, cap: &mut NFT::MintCapability<NFTMeta>, creator: address, index: u64, base_meta: NFT::Metadata, type_meta: NFTMeta, body: NFTBody, merkle_proof: vector<vector<u8>>): NFT::NFT<NFTMeta, NFTBody>
+
+ + + +
+Implementation + + +
public fun mint_with_cap<NFTMeta: copy + store + drop, NFTBody: store, Info: copy + store + drop>(sender: &signer, cap:&mut MintCapability<NFTMeta>, creator: address, index: u64, base_meta: Metadata, type_meta: NFTMeta, body: NFTBody, merkle_proof:vector<vector<u8>>): NFT<NFTMeta, NFTBody>
+    acquires MerkleNFTDistribution {
+        let addr = Signer::address_of(sender);
+        let distribution = borrow_global_mut<MerkleNFTDistribution<NFTMeta>>(creator);
+        let minted = is_minted_<NFTMeta>(distribution, index);
+        assert!(!minted, Errors::custom(ALREADY_MINTED));
+        let leaf_data = encode_leaf(&index, &addr);
+        let verified = MerkleProof::verify(&merkle_proof, &distribution.merkle_root, Hash::sha3_256(leaf_data));
+        assert!(verified, Errors::custom(INVALID_PROOF));
+        set_minted_(distribution, index);
+        let nft = NFT::mint_with_cap<NFTMeta, NFTBody, Info>(creator, cap, base_meta, type_meta, body);
+        return nft
+    }
+
+ + + +
+ + + +## Function `encode_leaf` + + + +
fun encode_leaf(index: &u64, account: &address): vector<u8>
+
+ + + +
+Implementation + + +
fun encode_leaf(index: &u64, account: &address): vector<u8> {
+    let leaf = Vector::empty();
+    Vector::append(&mut leaf, BCS::to_bytes(index));
+    Vector::append(&mut leaf, BCS::to_bytes(account));
+    leaf
+}
+
+ + + +
+ + + +## Function `set_minted_` + + + +
fun set_minted_<NFTMeta: copy, drop, store>(distribution: &mut MerkleNFTDistributor::MerkleNFTDistribution<NFTMeta>, index: u64)
+
+ + + +
+Implementation + + +
fun set_minted_<NFTMeta: copy + store + drop>(distribution: &mut MerkleNFTDistribution<NFTMeta>, index: u64) {
+    let claimed_word_index = index / 128;
+    let claimed_bit_index = ((index % 128) as u8);
+    let word = Vector::borrow_mut(&mut distribution.claimed_bitmap, claimed_word_index);
+    // word | (1 << bit_index)
+    let mask = 1u128 << claimed_bit_index;
+    *word = (*word | mask);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma opaque;
+
+ + + +
+ + + +## Function `verify_proof` + + + +
public fun verify_proof<NFTMeta: copy, drop, store>(account: address, creator: address, index: u64, merkle_proof: vector<vector<u8>>): bool
+
+ + + +
+Implementation + + +
public fun verify_proof<NFTMeta: copy + store + drop>(account: address, creator: address, index: u64, merkle_proof:vector<vector<u8>>): bool
+    acquires MerkleNFTDistribution {
+        let distribution = borrow_global_mut<MerkleNFTDistribution<NFTMeta>>(creator);
+        let leaf_data = encode_leaf(&index, &account);
+        MerkleProof::verify(&merkle_proof, &distribution.merkle_root, Hash::sha3_256(leaf_data))
+    }
+
+ + + +
+ + + +## Function `is_minted` + + + +
public fun is_minted<NFTMeta: copy, drop, store>(creator: address, index: u64): bool
+
+ + + +
+Implementation + + +
public fun is_minted<NFTMeta: copy + store + drop>(creator: address, index: u64): bool
+    acquires MerkleNFTDistribution {
+        let distribution = borrow_global_mut<MerkleNFTDistribution<NFTMeta>>(creator);
+        is_minted_<NFTMeta>(distribution, index)
+    }
+
+ + + +
+ + + +## Function `is_minted_` + + + +
fun is_minted_<NFTMeta: copy, drop, store>(distribution: &MerkleNFTDistributor::MerkleNFTDistribution<NFTMeta>, index: u64): bool
+
+ + + +
+Implementation + + +
fun is_minted_<NFTMeta: copy + store + drop>(distribution: &MerkleNFTDistribution<NFTMeta>, index: u64): bool {
+    let claimed_word_index = index / 128;
+    let claimed_bit_index = ((index % 128) as u8);
+    let word = Vector::borrow( &distribution.claimed_bitmap, claimed_word_index);
+    let mask = 1u128 << claimed_bit_index;
+    (*word & mask) == mask
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma opaque;
+
+ + + +
diff --git a/release/v13/docs/MintDaoProposal.md b/release/v13/docs/MintDaoProposal.md new file mode 100644 index 00000000..7bf5a984 --- /dev/null +++ b/release/v13/docs/MintDaoProposal.md @@ -0,0 +1,258 @@ + + + +# Module `0x1::MintDaoProposal` + +MintDaoProposal is a dao proposal for mint extra tokens. + + +- [Resource `WrappedMintCapability`](#0x1_MintDaoProposal_WrappedMintCapability) +- [Struct `MintToken`](#0x1_MintDaoProposal_MintToken) +- [Constants](#@Constants_0) +- [Function `plugin`](#0x1_MintDaoProposal_plugin) +- [Function `propose_mint_to`](#0x1_MintDaoProposal_propose_mint_to) +- [Function `execute_mint_proposal`](#0x1_MintDaoProposal_execute_mint_proposal) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Account;
+use 0x1::Dao;
+use 0x1::Errors;
+use 0x1::Signer;
+use 0x1::Token;
+
+ + + + + +## Resource `WrappedMintCapability` + +A wrapper of Token MintCapability. + + +
struct WrappedMintCapability<TokenType> has key
+
+ + + +
+Fields + + +
+
+cap: Token::MintCapability<TokenType> +
+
+ +
+
+ + +
+ + + +## Struct `MintToken` + +MintToken request. + + +
struct MintToken has copy, drop, store
+
+ + + +
+Fields + + +
+
+receiver: address +
+
+ the receiver of minted tokens. +
+
+amount: u128 +
+
+ how many tokens to mint. +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_NOT_AUTHORIZED: u64 = 401;
+
+ + + + + +## Function `plugin` + +Plugin method of the module. +Should be called by token issuer. + + +
public fun plugin<TokenT: store>(signer: &signer)
+
+ + + +
+Implementation + + +
public fun plugin<TokenT: store>(signer: &signer) {
+    let token_issuer = Token::token_address<TokenT>();
+    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    let mint_cap = Token::remove_mint_capability<TokenT>(signer);
+    move_to(signer, WrappedMintCapability { cap: mint_cap });
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+let sender = Signer::address_of(signer);
+aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS();
+aborts_if !exists<Token::MintCapability<TokenT>>(sender);
+aborts_if exists<WrappedMintCapability<TokenT>>(sender);
+ensures !exists<Token::MintCapability<TokenT>>(sender);
+ensures exists<WrappedMintCapability<TokenT>>(sender);
+
+ + + +
+ + + +## Function `propose_mint_to` + +Entrypoint for the proposal. + + +
public fun propose_mint_to<TokenT: copy, drop, store>(signer: &signer, receiver: address, amount: u128, exec_delay: u64)
+
+ + + +
+Implementation + + +
public fun propose_mint_to<TokenT: copy + drop + store>(signer: &signer, receiver: address, amount: u128, exec_delay: u64) {
+    Dao::propose<TokenT, MintToken>(
+        signer,
+        MintToken { receiver, amount },
+        exec_delay,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+include Dao::AbortIfDaoConfigNotExist<TokenT>;
+include Dao::AbortIfDaoInfoNotExist<TokenT>;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config<TokenT>().min_action_delay;
+include Dao::CheckQuorumVotes<TokenT>;
+let sender = Signer::address_of(signer);
+aborts_if exists<Dao::Proposal<TokenT, MintToken>>(sender);
+
+ + + +
+ + + +## Function `execute_mint_proposal` + +Once the proposal is agreed, anyone can call the method to make the proposal happen. + + +
public fun execute_mint_proposal<TokenT: copy, drop, store>(proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public fun execute_mint_proposal<TokenT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+) acquires WrappedMintCapability {
+    let MintToken { receiver, amount } = Dao::extract_proposal_action<TokenT, MintToken>(
+        proposer_address,
+        proposal_id,
+    );
+    let cap = borrow_global<WrappedMintCapability<TokenT>>(Token::token_address<TokenT>());
+    let tokens = Token::mint_with_capability<TokenT>(&cap.cap, amount);
+    Account::deposit(receiver, tokens);
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = true;
+let expected_states = vec<u8>(6);
+include Dao::CheckProposalStates<TokenT, MintToken>{expected_states};
+let proposal = global<Dao::Proposal<TokenT, MintToken>>(proposer_address);
+aborts_if Option::is_none(proposal.action);
+aborts_if !exists<WrappedMintCapability<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+pragma aborts_if_is_partial;
+
diff --git a/release/v13/docs/MintScripts.md b/release/v13/docs/MintScripts.md new file mode 100644 index 00000000..dbbdd845 --- /dev/null +++ b/release/v13/docs/MintScripts.md @@ -0,0 +1,10 @@ + + + +# Module `0x1::MintScripts` + + + + + +
diff --git a/release/v13/docs/ModifyDaoConfigProposal.md b/release/v13/docs/ModifyDaoConfigProposal.md new file mode 100644 index 00000000..1afc8c43 --- /dev/null +++ b/release/v13/docs/ModifyDaoConfigProposal.md @@ -0,0 +1,300 @@ + + + +# Module `0x1::ModifyDaoConfigProposal` + +A proposal module which is used to modify Token's DAO configuration. + + +- [Resource `DaoConfigModifyCapability`](#0x1_ModifyDaoConfigProposal_DaoConfigModifyCapability) +- [Struct `DaoConfigUpdate`](#0x1_ModifyDaoConfigProposal_DaoConfigUpdate) +- [Constants](#@Constants_0) +- [Function `plugin`](#0x1_ModifyDaoConfigProposal_plugin) +- [Function `propose`](#0x1_ModifyDaoConfigProposal_propose) +- [Function `execute`](#0x1_ModifyDaoConfigProposal_execute) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::Dao;
+use 0x1::Errors;
+use 0x1::Signer;
+use 0x1::Token;
+
+ + + + + +## Resource `DaoConfigModifyCapability` + +A wrapper of Config::ModifyConfigCapability<Dao::DaoConfig<TokenT>>. + + +
struct DaoConfigModifyCapability<TokenT: copy, drop, store> has key
+
+ + + +
+Fields + + +
+
+cap: Config::ModifyConfigCapability<Dao::DaoConfig<TokenT>> +
+
+ +
+
+ + +
+ + + +## Struct `DaoConfigUpdate` + +a proposal action to update dao config. +if any field is 0, that means the proposal want to update. + + +
struct DaoConfigUpdate has copy, drop, store
+
+ + + +
+Fields + + +
+
+voting_delay: u64 +
+
+ new voting delay setting. +
+
+voting_period: u64 +
+
+ new voting period setting. +
+
+voting_quorum_rate: u8 +
+
+ new voting quorum rate setting. +
+
+min_action_delay: u64 +
+
+ new min action delay setting. +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_NOT_AUTHORIZED: u64 = 401;
+
+ + + + + + + +
const ERR_QUORUM_RATE_INVALID: u64 = 402;
+
+ + + + + +## Function `plugin` + +Plugin method of the module. +Should be called by token issuer. + + +
public fun plugin<TokenT: copy, drop, store>(signer: &signer)
+
+ + + +
+Implementation + + +
public fun plugin<TokenT: copy + drop + store>(signer: &signer) {
+    let token_issuer = Token::token_address<TokenT>();
+    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    let dao_config_modify_cap = Config::extract_modify_config_capability<
+        Dao::DaoConfig<TokenT>,
+    >(signer);
+    assert!(Config::account_address(&dao_config_modify_cap) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    let cap = DaoConfigModifyCapability { cap: dao_config_modify_cap };
+    move_to(signer, cap);
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+let sender = Signer::address_of(signer);
+aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS();
+include Config::AbortsIfCapNotExist<Dao::DaoConfig<TokenT>>{address: sender};
+let config_cap = Config::spec_cap<Dao::DaoConfig<TokenT>>(sender);
+aborts_if Option::is_none(config_cap);
+aborts_if Option::borrow(config_cap).account_address != sender;
+aborts_if exists<DaoConfigModifyCapability<TokenT>>(sender);
+ensures exists<DaoConfigModifyCapability<TokenT>>(sender);
+
+ + + +
+ + + +## Function `propose` + +Entrypoint for the proposal. + + +
public entry fun propose<TokenT: copy, drop, store>(signer: signer, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose<TokenT: copy + drop + store>(
+    signer: signer,
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+    exec_delay: u64,
+) {
+    assert!(voting_quorum_rate <= 100, Errors::invalid_argument(ERR_QUORUM_RATE_INVALID));
+    let action = DaoConfigUpdate {
+        voting_delay,
+        voting_period,
+        voting_quorum_rate,
+        min_action_delay,
+    };
+    Dao::propose<TokenT, DaoConfigUpdate>(&signer, action, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+aborts_if voting_quorum_rate > 100;
+include Dao::AbortIfDaoConfigNotExist<TokenT>;
+include Dao::AbortIfDaoInfoNotExist<TokenT>;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config<TokenT>().min_action_delay;
+include Dao::CheckQuorumVotes<TokenT>;
+let sender = Signer::address_of(signer);
+aborts_if exists<Dao::Proposal<TokenT, DaoConfigUpdate>>(sender);
+
+ + + +
+ + + +## Function `execute` + +Once the proposal is agreed, anyone can call the method to make the proposal happen. + + +
public entry fun execute<TokenT: copy, drop, store>(proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun execute<TokenT: copy + drop + store>(proposer_address: address, proposal_id: u64)
+acquires DaoConfigModifyCapability {
+    let DaoConfigUpdate {
+        voting_delay,
+        voting_period,
+        voting_quorum_rate,
+        min_action_delay,
+    } = Dao::extract_proposal_action<TokenT, DaoConfigUpdate>(proposer_address, proposal_id);
+    let cap = borrow_global_mut<DaoConfigModifyCapability<TokenT>>(
+        Token::token_address<TokenT>(),
+    );
+    Dao::modify_dao_config(
+        &mut cap.cap,
+        voting_delay,
+        voting_period,
+        voting_quorum_rate,
+        min_action_delay,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = true;
+aborts_if !exists<DaoConfigModifyCapability<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+pragma aborts_if_is_partial;
+
diff --git a/release/v13/docs/ModuleUpgradeScripts.md b/release/v13/docs/ModuleUpgradeScripts.md new file mode 100644 index 00000000..4ac2a7f2 --- /dev/null +++ b/release/v13/docs/ModuleUpgradeScripts.md @@ -0,0 +1,314 @@ + + + +# Module `0x1::ModuleUpgradeScripts` + + + +- [Constants](#@Constants_0) +- [Function `propose_module_upgrade_v2`](#0x1_ModuleUpgradeScripts_propose_module_upgrade_v2) +- [Function `update_module_upgrade_strategy`](#0x1_ModuleUpgradeScripts_update_module_upgrade_strategy) +- [Function `update_module_upgrade_strategy_with_min_time`](#0x1_ModuleUpgradeScripts_update_module_upgrade_strategy_with_min_time) +- [Function `submit_module_upgrade_plan`](#0x1_ModuleUpgradeScripts_submit_module_upgrade_plan) +- [Function `execute_module_upgrade_plan_propose`](#0x1_ModuleUpgradeScripts_execute_module_upgrade_plan_propose) +- [Function `submit_upgrade_plan`](#0x1_ModuleUpgradeScripts_submit_upgrade_plan) +- [Function `cancel_upgrade_plan`](#0x1_ModuleUpgradeScripts_cancel_upgrade_plan) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::Errors;
+use 0x1::Option;
+use 0x1::PackageTxnManager;
+use 0x1::Signer;
+use 0x1::UpgradeModuleDaoProposal;
+use 0x1::Version;
+
+ + + + + +## Constants + + + + + + +
const ERR_WRONG_UPGRADE_STRATEGY: u64 = 100;
+
+ + + + + +## Function `propose_module_upgrade_v2` + + + +
public entry fun propose_module_upgrade_v2<Token: copy, drop, store>(signer: signer, module_address: address, package_hash: vector<u8>, version: u64, exec_delay: u64, enforced: bool)
+
+ + + +
+Implementation + + +
public entry fun propose_module_upgrade_v2<Token: copy + drop + store>(
+    signer: signer,
+    module_address: address,
+    package_hash: vector<u8>,
+    version: u64,
+    exec_delay: u64,
+    enforced: bool,
+) {
+    UpgradeModuleDaoProposal::propose_module_upgrade_v2<Token>(
+        &signer,
+        module_address,
+        package_hash,
+        version,
+        exec_delay,
+        enforced
+    );
+}
+
+ + + +
+ + + +## Function `update_module_upgrade_strategy` + +Update sender's module upgrade strategy to strategy + + +
public entry fun update_module_upgrade_strategy(sender: signer, strategy: u8)
+
+ + + +
+Implementation + + +
public entry fun update_module_upgrade_strategy(
+    sender: signer,
+    strategy: u8,
+) {
+    // 1. check version
+    if (strategy == PackageTxnManager::get_strategy_two_phase()) {
+        if (!Config::config_exist_by_address<Version::Version>(Signer::address_of(&sender))) {
+            Config::publish_new_config<Version::Version>(&sender, Version::new_version(1));
+        }
+    };
+
+    // 2. update strategy
+    PackageTxnManager::update_module_upgrade_strategy(
+        &sender,
+        strategy,
+        Option::none<u64>(),
+    );
+}
+
+ + + +
+ + + +## Function `update_module_upgrade_strategy_with_min_time` + +Update sender's module upgrade strategy to strategy with min_time_limit. +This can only be invoked when strategy is STRATEGY_TWO_PHASE. + + +
public entry fun update_module_upgrade_strategy_with_min_time(sender: signer, strategy: u8, min_time_limit: u64)
+
+ + + +
+Implementation + + +
public entry fun update_module_upgrade_strategy_with_min_time(
+    sender: signer,
+    strategy: u8,
+    min_time_limit: u64,
+){
+    // 1. check version
+    assert!(strategy == PackageTxnManager::get_strategy_two_phase(), Errors::invalid_argument(ERR_WRONG_UPGRADE_STRATEGY));
+    // 2. update strategy
+    PackageTxnManager::update_module_upgrade_strategy(
+        &sender,
+        strategy,
+        Option::some<u64>(min_time_limit),
+    );
+}
+
+ + + +
+ + + +## Function `submit_module_upgrade_plan` + +a alias of execute_module_upgrade_plan_propose, will deprecated in the future. + + +
public entry fun submit_module_upgrade_plan<Token: copy, drop, store>(sender: signer, proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun submit_module_upgrade_plan<Token: copy + drop + store>(
+    sender: signer,
+    proposer_address: address,
+    proposal_id: u64,
+) {
+    Self::execute_module_upgrade_plan_propose<Token>(sender, proposer_address, proposal_id);
+}
+
+ + + +
+ + + +## Function `execute_module_upgrade_plan_propose` + +Execute module upgrade plan propose by submit module upgrade plan, the propose must been agreed, and anyone can execute this function. + + +
public entry fun execute_module_upgrade_plan_propose<Token: copy, drop, store>(_sender: signer, proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun execute_module_upgrade_plan_propose<Token: copy + drop + store>(
+    _sender: signer,
+    proposer_address: address,
+    proposal_id: u64,
+) {
+    UpgradeModuleDaoProposal::submit_module_upgrade_plan<Token>(proposer_address, proposal_id);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `submit_upgrade_plan` + +Directly submit a upgrade plan, the sender's module upgrade plan must been PackageTxnManager::STRATEGY_TWO_PHASE and have UpgradePlanCapability + + +
public entry fun submit_upgrade_plan(sender: signer, package_hash: vector<u8>, version: u64, enforced: bool)
+
+ + + +
+Implementation + + +
public entry fun submit_upgrade_plan(sender: signer, package_hash: vector<u8>, version:u64, enforced: bool) {
+    PackageTxnManager::submit_upgrade_plan_v2(&sender, package_hash, version, enforced);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `cancel_upgrade_plan` + +Cancel current upgrade plan, the sender must have UpgradePlanCapability. + + +
public entry fun cancel_upgrade_plan(signer: signer)
+
+ + + +
+Implementation + + +
public entry fun cancel_upgrade_plan(
+    signer: signer,
+) {
+    PackageTxnManager::cancel_upgrade_plan(&signer);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_partial = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/NFT.md b/release/v13/docs/NFT.md new file mode 100644 index 00000000..b257544e --- /dev/null +++ b/release/v13/docs/NFT.md @@ -0,0 +1,104 @@ + + + +# Module `0x1::NFTGalleryScripts` + + + +- [Function `accept`](#0x1_NFTGalleryScripts_accept) +- [Function `transfer`](#0x1_NFTGalleryScripts_transfer) +- [Function `remove_empty_gallery`](#0x1_NFTGalleryScripts_remove_empty_gallery) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::NFTGallery;
+
+ + + + + +## Function `accept` + +Init a NFTGallery for accept NFT + + +
public entry fun accept<NFTMeta: copy, drop, store, NFTBody: store>(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun accept<NFTMeta: copy + store + drop, NFTBody: store>(sender: signer) {
+    NFTGallery::accept_entry<NFTMeta, NFTBody>(sender);
+}
+
+ + + +
+ + + +## Function `transfer` + +Transfer NFT with id from sender to receiver + + +
public entry fun transfer<NFTMeta: copy, drop, store, NFTBody: store>(sender: signer, id: u64, receiver: address)
+
+ + + +
+Implementation + + +
public entry fun transfer<NFTMeta: copy + store + drop, NFTBody: store>(
+    sender: signer,
+    id: u64, receiver: address
+) {
+    NFTGallery::transfer_entry<NFTMeta, NFTBody>(sender, id, receiver);
+}
+
+ + + +
+ + + +## Function `remove_empty_gallery` + +Remove empty NFTGallery. + + +
public entry fun remove_empty_gallery<NFTMeta: copy, drop, store, NFTBody: store>(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun remove_empty_gallery<NFTMeta: copy + store + drop, NFTBody: store>(sender: signer) {
+    NFTGallery::remove_empty_gallery_entry<NFTMeta, NFTBody>(sender);
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+
diff --git a/release/v13/docs/Offer.md b/release/v13/docs/Offer.md new file mode 100644 index 00000000..59f75057 --- /dev/null +++ b/release/v13/docs/Offer.md @@ -0,0 +1,305 @@ + + + +# Module `0x1::Offer` + + + +- [Resource `Offer`](#0x1_Offer_Offer) +- [Constants](#@Constants_0) +- [Function `create`](#0x1_Offer_create) +- [Function `redeem`](#0x1_Offer_redeem) +- [Function `exists_at`](#0x1_Offer_exists_at) +- [Function `address_of`](#0x1_Offer_address_of) +- [Function `take_offer`](#0x1_Offer_take_offer) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Collection2;
+use 0x1::Errors;
+use 0x1::Signer;
+use 0x1::Timestamp;
+
+ + + + + +## Resource `Offer` + +A wrapper around value offered that can be claimed by the address stored in for when after lock time. + + +
struct Offer<Offered> has key
+
+ + + +
+Fields + + +
+
+offered: Offered +
+
+ +
+
+for: address +
+
+ +
+
+time_lock: u64 +
+
+ +
+
+ + +
+ + + +## Constants + + + + +An offer of the specified type for the account does not match + + +
const EOFFER_DNE_FOR_ACCOUNT: u64 = 101;
+
+ + + + + +Offer is not unlocked yet. + + +
const EOFFER_NOT_UNLOCKED: u64 = 102;
+
+ + + + + +## Function `create` + +Publish a value of type Offered under the sender's account. The value can be claimed by +either the for address or the transaction sender. + + +
public fun create<Offered: store>(account: &signer, offered: Offered, for: address, lock_period: u64)
+
+ + + +
+Implementation + + +
public fun create<Offered: store>(account: &signer, offered: Offered, for: address, lock_period: u64) {
+    let time_lock = Timestamp::now_seconds() + lock_period;
+    //TODO should support multi Offer?
+    move_to(account, Offer<Offered> { offered, for, time_lock });
+}
+
+ + + +
+ +
+Specification + + + +
include Timestamp::AbortsIfTimestampNotExists;
+aborts_if Timestamp::now_seconds() + lock_period > max_u64();
+aborts_if exists<Offer<Offered>>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `redeem` + +Claim the value of type Offered published at offer_address. +Only succeeds if the sender is the intended recipient stored in for or the original +publisher offer_address, and now >= time_lock +Also fails if no such value exists. + + +
public fun redeem<Offered: store>(account: &signer, offer_address: address): Offered
+
+ + + +
+Implementation + + +
public fun redeem<Offered: store>(account: &signer, offer_address: address): Offered acquires Offer {
+    let Offer<Offered> { offered, for, time_lock } = move_from<Offer<Offered>>(offer_address);
+    let sender = Signer::address_of(account);
+    let now = Timestamp::now_seconds();
+    assert!(sender == for || sender == offer_address, Errors::invalid_argument(EOFFER_DNE_FOR_ACCOUNT));
+    assert!(now >= time_lock, Errors::not_published(EOFFER_NOT_UNLOCKED));
+    offered
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Offer<Offered>>(offer_address);
+aborts_if Signer::address_of(account) != global<Offer<Offered>>(offer_address).for && Signer::address_of(account) != offer_address;
+aborts_if Timestamp::now_seconds() < global<Offer<Offered>>(offer_address).time_lock;
+include Timestamp::AbortsIfTimestampNotExists;
+
+ + + +
+ + + +## Function `exists_at` + +Returns true if an offer of type Offered exists at offer_address. + + +
public fun exists_at<Offered: store>(offer_address: address): bool
+
+ + + +
+Implementation + + +
public fun exists_at<Offered: store>(offer_address: address): bool {
+    exists<Offer<Offered>>(offer_address)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `address_of` + +Returns the address of the Offered type stored at offer_address. +Fails if no such Offer exists. + + +
public fun address_of<Offered: store>(offer_address: address): address
+
+ + + +
+Implementation + + +
public fun address_of<Offered: store>(offer_address: address): address acquires Offer {
+    borrow_global<Offer<Offered>>(offer_address).for
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Offer<Offered>>(offer_address);
+
+ + + +
+ + + +## Function `take_offer` + +Take Offer and put to signer's Collection. + + +
public entry fun take_offer<Offered: store>(signer: signer, offer_address: address)
+
+ + + +
+Implementation + + +
public entry fun take_offer<Offered: store>(
+    signer: signer,
+    offer_address: address,
+) acquires Offer {
+    let offered = redeem<Offered>(&signer, offer_address);
+    Collection2::put(&signer, Signer::address_of(&signer), offered);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = true;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/OnChainConfigDao.md b/release/v13/docs/OnChainConfigDao.md new file mode 100644 index 00000000..1fc075ec --- /dev/null +++ b/release/v13/docs/OnChainConfigDao.md @@ -0,0 +1,257 @@ + + + +# Module `0x1::OnChainConfigDao` + +OnChainConfigDao is a DAO proposal for modify onchain configuration. + + +- [Resource `WrappedConfigModifyCapability`](#0x1_OnChainConfigDao_WrappedConfigModifyCapability) +- [Struct `OnChainConfigUpdate`](#0x1_OnChainConfigDao_OnChainConfigUpdate) +- [Constants](#@Constants_0) +- [Function `plugin`](#0x1_OnChainConfigDao_plugin) +- [Function `propose_update`](#0x1_OnChainConfigDao_propose_update) +- [Function `execute`](#0x1_OnChainConfigDao_execute) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::Dao;
+use 0x1::Errors;
+use 0x1::Signer;
+use 0x1::Token;
+
+ + + + + +## Resource `WrappedConfigModifyCapability` + +A wrapper of Config::ModifyConfigCapability<ConfigT>. + + +
struct WrappedConfigModifyCapability<TokenT, ConfigT: copy, drop, store> has key
+
+ + + +
+Fields + + +
+
+cap: Config::ModifyConfigCapability<ConfigT> +
+
+ +
+
+ + +
+ + + +## Struct `OnChainConfigUpdate` + +request of updating configuration. + + +
struct OnChainConfigUpdate<ConfigT: copy, drop, store> has copy, drop, store
+
+ + + +
+Fields + + +
+
+value: ConfigT +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_NOT_AUTHORIZED: u64 = 401;
+
+ + + + + +## Function `plugin` + +Plugin method of the module. +Should be called by token issuer. + + +
public fun plugin<TokenT: copy, drop, store, ConfigT: copy, drop, store>(signer: &signer)
+
+ + + +
+Implementation + + +
public fun plugin<TokenT: copy + drop + store, ConfigT: copy + drop + store>(signer: &signer) {
+    let token_issuer = Token::token_address<TokenT>();
+    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    let config_modify_cap = Config::extract_modify_config_capability<ConfigT>(signer);
+    let cap = WrappedConfigModifyCapability<TokenT, ConfigT> { cap: config_modify_cap };
+    move_to(signer, cap);
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+let sender = Signer::address_of(signer);
+aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS();
+include Config::AbortsIfCapNotExist<ConfigT>{address: sender};
+aborts_if exists<WrappedConfigModifyCapability<TokenT, ConfigT>>(sender);
+ensures exists<WrappedConfigModifyCapability<TokenT, ConfigT>>(sender);
+
+ + + +
+ + + +## Function `propose_update` + +issue a proposal to update config of ConfigT goved by TokenT + + +
public fun propose_update<TokenT: copy, drop, store, ConfigT: copy, drop, store>(signer: &signer, new_config: ConfigT, exec_delay: u64)
+
+ + + +
+Implementation + + +
public fun propose_update<TokenT: copy + drop + store, ConfigT: copy + drop + store>(
+    signer: &signer,
+    new_config: ConfigT,
+    exec_delay: u64,
+) {
+    Dao::propose<TokenT, OnChainConfigUpdate<ConfigT>>(
+        signer,
+        OnChainConfigUpdate { value: new_config },
+        exec_delay,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+include Dao::AbortIfDaoConfigNotExist<TokenT>;
+include Dao::AbortIfDaoInfoNotExist<TokenT>;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config<TokenT>().min_action_delay;
+include Dao::CheckQuorumVotes<TokenT>;
+let sender = Signer::address_of(signer);
+aborts_if exists<Dao::Proposal<TokenT, OnChainConfigUpdate<ConfigT>>>(sender);
+
+ + + +
+ + + +## Function `execute` + +Once the proposal is agreed, anyone can call the method to make the proposal happen. +Caller need to make sure that the proposal of proposal_id under proposal_address is +the kind of this proposal module. + + +
public fun execute<TokenT: copy, drop, store, ConfigT: copy, drop, store>(proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public fun execute<TokenT: copy + drop + store, ConfigT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+) acquires WrappedConfigModifyCapability {
+    let OnChainConfigUpdate { value } = Dao::extract_proposal_action<
+        TokenT,
+        OnChainConfigUpdate<ConfigT>,
+    >(proposer_address, proposal_id);
+    let cap = borrow_global_mut<WrappedConfigModifyCapability<TokenT, ConfigT>>(
+        Token::token_address<TokenT>(),
+    );
+    Config::set_with_capability(&mut cap.cap, value);
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = true;
+let expected_states = vec<u8>(6);
+include Dao::CheckProposalStates<TokenT, OnChainConfigUpdate<ConfigT>>{expected_states};
+aborts_if !exists<WrappedConfigModifyCapability<TokenT, ConfigT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+pragma aborts_if_is_partial;
+
diff --git a/release/v13/docs/OnChainConfigScripts.md b/release/v13/docs/OnChainConfigScripts.md new file mode 100644 index 00000000..42b2ea89 --- /dev/null +++ b/release/v13/docs/OnChainConfigScripts.md @@ -0,0 +1,417 @@ + + + +# Module `0x1::OnChainConfigScripts` + + + +- [Function `propose_update_consensus_config`](#0x1_OnChainConfigScripts_propose_update_consensus_config) +- [Function `propose_update_reward_config`](#0x1_OnChainConfigScripts_propose_update_reward_config) +- [Function `propose_update_txn_publish_option`](#0x1_OnChainConfigScripts_propose_update_txn_publish_option) +- [Function `propose_update_txn_timeout_config`](#0x1_OnChainConfigScripts_propose_update_txn_timeout_config) +- [Function `propose_update_vm_config`](#0x1_OnChainConfigScripts_propose_update_vm_config) +- [Function `propose_update_move_language_version`](#0x1_OnChainConfigScripts_propose_update_move_language_version) +- [Function `propose_update_flexi_dag_effective_height`](#0x1_OnChainConfigScripts_propose_update_flexi_dag_effective_height) +- [Function `execute_on_chain_config_proposal`](#0x1_OnChainConfigScripts_execute_on_chain_config_proposal) +- [Function `execute_on_chain_config_proposal_v2`](#0x1_OnChainConfigScripts_execute_on_chain_config_proposal_v2) + + +
use 0x1::ConsensusConfig;
+use 0x1::FlexiDagConfig;
+use 0x1::LanguageVersion;
+use 0x1::OnChainConfigDao;
+use 0x1::RewardConfig;
+use 0x1::STC;
+use 0x1::Signer;
+use 0x1::TransactionPublishOption;
+use 0x1::TransactionTimeoutConfig;
+use 0x1::VMConfig;
+
+ + + + + +## Function `propose_update_consensus_config` + + + +
public entry fun propose_update_consensus_config(account: signer, uncle_rate_target: u64, base_block_time_target: u64, base_reward_per_block: u128, base_reward_per_uncle_percent: u64, epoch_block_count: u64, base_block_difficulty_window: u64, min_block_time_target: u64, max_block_time_target: u64, base_max_uncles_per_block: u64, base_block_gas_limit: u64, strategy: u8, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_consensus_config(account: signer,
+                                                      uncle_rate_target: u64,
+                                                      base_block_time_target: u64,
+                                                      base_reward_per_block: u128,
+                                                      base_reward_per_uncle_percent: u64,
+                                                      epoch_block_count: u64,
+                                                      base_block_difficulty_window: u64,
+                                                      min_block_time_target: u64,
+                                                      max_block_time_target: u64,
+                                                      base_max_uncles_per_block: u64,
+                                                      base_block_gas_limit: u64,
+                                                      strategy: u8,
+                                                      exec_delay: u64) {
+    let consensus_config = ConsensusConfig::new_consensus_config(uncle_rate_target,
+        base_block_time_target,
+        base_reward_per_block,
+        base_reward_per_uncle_percent,
+        epoch_block_count,
+        base_block_difficulty_window,
+        min_block_time_target,
+        max_block_time_target,
+        base_max_uncles_per_block,
+        base_block_gas_limit,
+        strategy);
+    OnChainConfigDao::propose_update<STC::STC, ConsensusConfig::ConsensusConfig>(&account, consensus_config, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `propose_update_reward_config` + + + +
public entry fun propose_update_reward_config(account: signer, reward_delay: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_reward_config(account: signer,
+                                                   reward_delay: u64,
+                                                   exec_delay: u64) {
+    let reward_config = RewardConfig::new_reward_config(reward_delay);
+    OnChainConfigDao::propose_update<STC::STC, RewardConfig::RewardConfig>(&account, reward_config, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `propose_update_txn_publish_option` + + + +
public entry fun propose_update_txn_publish_option(account: signer, script_allowed: bool, module_publishing_allowed: bool, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_txn_publish_option(account: signer,
+                                                        script_allowed: bool,
+                                                        module_publishing_allowed: bool,
+                                                        exec_delay: u64) {
+    let txn_publish_option = TransactionPublishOption::new_transaction_publish_option(script_allowed, module_publishing_allowed);
+    OnChainConfigDao::propose_update<STC::STC, TransactionPublishOption::TransactionPublishOption>(&account, txn_publish_option, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `propose_update_txn_timeout_config` + + + +
public entry fun propose_update_txn_timeout_config(account: signer, duration_seconds: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_txn_timeout_config(account: signer,
+                                                        duration_seconds: u64,
+                                                        exec_delay: u64) {
+    let txn_timeout_config = TransactionTimeoutConfig::new_transaction_timeout_config(duration_seconds);
+    OnChainConfigDao::propose_update<STC::STC, TransactionTimeoutConfig::TransactionTimeoutConfig>(&account, txn_timeout_config, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `propose_update_vm_config` + + + +
public entry fun propose_update_vm_config(account: signer, instruction_schedule: vector<u8>, native_schedule: vector<u8>, global_memory_per_byte_cost: u64, global_memory_per_byte_write_cost: u64, min_transaction_gas_units: u64, large_transaction_cutoff: u64, instrinsic_gas_per_byte: u64, maximum_number_of_gas_units: u64, min_price_per_gas_unit: u64, max_price_per_gas_unit: u64, max_transaction_size_in_bytes: u64, gas_unit_scaling_factor: u64, default_account_size: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_vm_config(account: signer,
+                                               instruction_schedule: vector<u8>,
+                                               native_schedule: vector<u8>,
+                                               global_memory_per_byte_cost: u64,
+                                               global_memory_per_byte_write_cost: u64,
+                                               min_transaction_gas_units: u64,
+                                               large_transaction_cutoff: u64,
+                                               instrinsic_gas_per_byte: u64,
+                                               maximum_number_of_gas_units: u64,
+                                               min_price_per_gas_unit: u64,
+                                               max_price_per_gas_unit: u64,
+                                               max_transaction_size_in_bytes: u64,
+                                               gas_unit_scaling_factor: u64,
+                                               default_account_size: u64,
+                                               exec_delay: u64, ) {
+    let vm_config = VMConfig::new_vm_config(instruction_schedule,
+        native_schedule,
+        global_memory_per_byte_cost,
+        global_memory_per_byte_write_cost,
+        min_transaction_gas_units,
+        large_transaction_cutoff,
+        instrinsic_gas_per_byte,
+        maximum_number_of_gas_units,
+        min_price_per_gas_unit,
+        max_price_per_gas_unit,
+        max_transaction_size_in_bytes,
+        gas_unit_scaling_factor,
+        default_account_size);
+    OnChainConfigDao::propose_update<STC::STC, VMConfig::VMConfig>(&account, vm_config, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `propose_update_move_language_version` + + + +
public entry fun propose_update_move_language_version(account: signer, new_version: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_move_language_version(account: signer, new_version: u64, exec_delay: u64) {
+    let lang_version = LanguageVersion::new(new_version);
+    OnChainConfigDao::propose_update<STC::STC, LanguageVersion::LanguageVersion>(&account, lang_version, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `propose_update_flexi_dag_effective_height` + + + +
public entry fun propose_update_flexi_dag_effective_height(account: signer, new_height: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_update_flexi_dag_effective_height(account: signer, new_height: u64, exec_delay: u64) {
+    let config = FlexiDagConfig::new_flexidag_config(new_height);
+    OnChainConfigDao::propose_update<STC::STC, FlexiDagConfig::FlexiDagConfig>(&account, config, exec_delay);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `execute_on_chain_config_proposal` + + + +
public entry fun execute_on_chain_config_proposal<ConfigT: copy, drop, store>(account: signer, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun execute_on_chain_config_proposal<ConfigT: copy + drop + store>(account: signer, proposal_id: u64) {
+    OnChainConfigDao::execute<STC::STC, ConfigT>(Signer::address_of(&account), proposal_id);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `execute_on_chain_config_proposal_v2` + + + +
public entry fun execute_on_chain_config_proposal_v2<TokenType: copy, drop, store, ConfigT: copy, drop, store>(proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun execute_on_chain_config_proposal_v2<TokenType: copy + drop + store, ConfigT: copy + drop + store>(proposer_address: address, proposal_id: u64) {
+    OnChainConfigDao::execute<TokenType, ConfigT>(proposer_address, proposal_id);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
diff --git a/release/v13/docs/Option.md b/release/v13/docs/Option.md new file mode 100644 index 00000000..4f518c53 --- /dev/null +++ b/release/v13/docs/Option.md @@ -0,0 +1,787 @@ + + + +# Module `0x1::Option` + +This module defines the Option type and its methods to represent and handle an optional value. + + +- [Struct `Option`](#0x1_Option_Option) +- [Constants](#@Constants_0) +- [Function `none`](#0x1_Option_none) +- [Function `some`](#0x1_Option_some) +- [Function `is_none`](#0x1_Option_is_none) +- [Function `is_some`](#0x1_Option_is_some) +- [Function `contains`](#0x1_Option_contains) +- [Function `borrow`](#0x1_Option_borrow) +- [Function `borrow_with_default`](#0x1_Option_borrow_with_default) +- [Function `get_with_default`](#0x1_Option_get_with_default) +- [Function `fill`](#0x1_Option_fill) +- [Function `extract`](#0x1_Option_extract) +- [Function `borrow_mut`](#0x1_Option_borrow_mut) +- [Function `swap`](#0x1_Option_swap) +- [Function `destroy_with_default`](#0x1_Option_destroy_with_default) +- [Function `destroy_some`](#0x1_Option_destroy_some) +- [Function `destroy_none`](#0x1_Option_destroy_none) +- [Module Specification](#@Module_Specification_1) + - [Helper Schema](#@Helper_Schema_2) + + +
use 0x1::Errors;
+use 0x1::Vector;
+
+ + + + + +## Struct `Option` + +Abstraction of a value that may or may not be present. Implemented with a vector of size +zero or one because Move bytecode does not have ADTs. + + +
struct Option<Element> has copy, drop, store
+
+ + + +
+Fields + + +
+
+vec: vector<Element> +
+
+ +
+
+ + +
+ +
+Specification + + +The size of vector is always less than equal to 1 +because it's 0 for "none" or 1 for "some". + + +
invariant len(vec) <= 1;
+
+ + + +
+ + + +## Constants + + + + +The Option is in an invalid state for the operation attempted. +The Option is Some while it should be None. + + +
const EOPTION_IS_SET: u64 = 0;
+
+ + + + + +The Option is in an invalid state for the operation attempted. +The Option is None while it should be Some. + + +
const EOPTION_NOT_SET: u64 = 1;
+
+ + + + + +## Function `none` + +Return an empty Option + + +
public fun none<Element>(): Option::Option<Element>
+
+ + + +
+Implementation + + +
public fun none<Element>(): Option<Element> {
+    Option { vec: Vector::empty() }
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == spec_none<Element>();
+
+ + + + + + + +
fun spec_none<Element>(): Option<Element> {
+   Option{ vec: vec() }
+}
+
+ + + +
+ + + +## Function `some` + +Return an Option containing e + + +
public fun some<Element>(e: Element): Option::Option<Element>
+
+ + + +
+Implementation + + +
public fun some<Element>(e: Element): Option<Element> {
+    Option { vec: Vector::singleton(e) }
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == spec_some(e);
+
+ + + + + + + +
fun spec_some<Element>(e: Element): Option<Element> {
+   Option{ vec: vec(e) }
+}
+
+ + + +
+ + + +## Function `is_none` + +Return true if t does not hold a value + + +
public fun is_none<Element>(t: &Option::Option<Element>): bool
+
+ + + +
+Implementation + + +
public fun is_none<Element>(t: &Option<Element>): bool {
+    Vector::is_empty(&t.vec)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == is_none(t);
+
+ + + +
+ + + +## Function `is_some` + +Return true if t holds a value + + +
public fun is_some<Element>(t: &Option::Option<Element>): bool
+
+ + + +
+Implementation + + +
public fun is_some<Element>(t: &Option<Element>): bool {
+    !Vector::is_empty(&t.vec)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == is_some(t);
+
+ + + +
+ + + +## Function `contains` + +Return true if the value in t is equal to e_ref +Always returns false if t does not hold a value + + +
public fun contains<Element>(t: &Option::Option<Element>, e_ref: &Element): bool
+
+ + + +
+Implementation + + +
public fun contains<Element>(t: &Option<Element>, e_ref: &Element): bool {
+    Vector::contains(&t.vec, e_ref)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == spec_contains(t, e_ref);
+
+ + + + + + + +
fun spec_contains<Element>(t: Option<Element>, e: Element): bool {
+   is_some(t) && borrow(t) == e
+}
+
+ + + +
+ + + +## Function `borrow` + +Return an immutable reference to the value inside t +Aborts if t does not hold a value + + +
public fun borrow<Element>(t: &Option::Option<Element>): &Element
+
+ + + +
+Implementation + + +
public fun borrow<Element>(t: &Option<Element>): &Element {
+    assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET));
+    Vector::borrow(&t.vec, 0)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+include AbortsIfNone<Element>;
+ensures result == borrow(t);
+
+ + + +
+ + + +## Function `borrow_with_default` + +Return a reference to the value inside t if it holds one +Return default_ref if t does not hold a value + + +
public fun borrow_with_default<Element>(t: &Option::Option<Element>, default_ref: &Element): &Element
+
+ + + +
+Implementation + + +
public fun borrow_with_default<Element>(t: &Option<Element>, default_ref: &Element): &Element {
+    let vec_ref = &t.vec;
+    if (Vector::is_empty(vec_ref)) default_ref
+    else Vector::borrow(vec_ref, 0)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == (if (is_some(t)) borrow(t) else default_ref);
+
+ + + +
+ + + +## Function `get_with_default` + +Return the value inside t if it holds one +Return default if t does not hold a value + + +
public fun get_with_default<Element: copy, drop>(t: &Option::Option<Element>, default: Element): Element
+
+ + + +
+Implementation + + +
public fun get_with_default<Element: copy + drop>(
+    t: &Option<Element>,
+    default: Element,
+): Element {
+    let vec_ref = &t.vec;
+    if (Vector::is_empty(vec_ref)) default
+    else *Vector::borrow(vec_ref, 0)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == (if (is_some(t)) borrow(t) else default);
+
+ + + +
+ + + +## Function `fill` + +Convert the none option t to a some option by adding e. +Aborts if t already holds a value + + +
public fun fill<Element>(t: &mut Option::Option<Element>, e: Element)
+
+ + + +
+Implementation + + +
public fun fill<Element>(t: &mut Option<Element>, e: Element) {
+    let vec_ref = &mut t.vec;
+    if (Vector::is_empty(vec_ref)) Vector::push_back(vec_ref, e)
+    else abort Errors::invalid_argument(EOPTION_IS_SET)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if is_some(t) with Errors::INVALID_ARGUMENT;
+ensures is_some(t);
+ensures borrow(t) == e;
+
+ + + +
+ + + +## Function `extract` + +Convert a some option to a none by removing and returning the value stored inside t +Aborts if t does not hold a value + + +
public fun extract<Element>(t: &mut Option::Option<Element>): Element
+
+ + + +
+Implementation + + +
public fun extract<Element>(t: &mut Option<Element>): Element {
+    assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET));
+    Vector::pop_back(&mut t.vec)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+include AbortsIfNone<Element>;
+ensures result == borrow(old(t));
+ensures is_none(t);
+
+ + + +
+ + + +## Function `borrow_mut` + +Return a mutable reference to the value inside t +Aborts if t does not hold a value + + +
public fun borrow_mut<Element>(t: &mut Option::Option<Element>): &mut Element
+
+ + + +
+Implementation + + +
public fun borrow_mut<Element>(t: &mut Option<Element>): &mut Element {
+    assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET));
+    Vector::borrow_mut(&mut t.vec, 0)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+include AbortsIfNone<Element>;
+ensures result == borrow(t);
+
+ + + +
+ + + +## Function `swap` + +Swap the old value inside t with e and return the old value +Aborts if t does not hold a value + + +
public fun swap<Element>(t: &mut Option::Option<Element>, e: Element): Element
+
+ + + +
+Implementation + + +
public fun swap<Element>(t: &mut Option<Element>, e: Element): Element {
+    assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET));
+    let vec_ref = &mut t.vec;
+    let old_value = Vector::pop_back(vec_ref);
+    Vector::push_back(vec_ref, e);
+    old_value
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+include AbortsIfNone<Element>;
+ensures result == borrow(old(t));
+ensures is_some(t);
+ensures borrow(t) == e;
+
+ + + +
+ + + +## Function `destroy_with_default` + +Destroys t. If t holds a value, return it. Returns default otherwise + + +
public fun destroy_with_default<Element: drop>(t: Option::Option<Element>, default: Element): Element
+
+ + + +
+Implementation + + +
public fun destroy_with_default<Element: drop>(t: Option<Element>, default: Element): Element {
+    let Option { vec } = t;
+    if (Vector::is_empty(&mut vec)) default
+    else Vector::pop_back(&mut vec)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if false;
+ensures result == (if (is_some(t)) borrow(t) else default);
+
+ + + +
+ + + +## Function `destroy_some` + +Unpack t and return its contents +Aborts if t does not hold a value + + +
public fun destroy_some<Element>(t: Option::Option<Element>): Element
+
+ + + +
+Implementation + + +
public fun destroy_some<Element>(t: Option<Element>): Element {
+    assert!(is_some(&t), Errors::invalid_argument(EOPTION_NOT_SET));
+    let Option { vec } = t;
+    let elem = Vector::pop_back(&mut vec);
+    Vector::destroy_empty(vec);
+    elem
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+include AbortsIfNone<Element>;
+ensures result == borrow(t);
+
+ + + +
+ + + +## Function `destroy_none` + +Unpack t +Aborts if t holds a value + + +
public fun destroy_none<Element>(t: Option::Option<Element>)
+
+ + + +
+Implementation + + +
public fun destroy_none<Element>(t: Option<Element>) {
+    assert!(is_none(&t), Errors::invalid_argument(EOPTION_IS_SET));
+    let Option { vec } = t;
+    Vector::destroy_empty(vec)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if is_some(t) with Errors::INVALID_ARGUMENT;
+
+ + + +
+ + + +## Module Specification + + + + +
pragma aborts_if_is_strict;
+
+ + + + + +### Helper Schema + + + + + + +
schema AbortsIfNone<Element> {
+    t: Option<Element>;
+    aborts_if is_none(t) with Errors::INVALID_ARGUMENT;
+}
+
diff --git a/release/v13/docs/Oracle.md b/release/v13/docs/Oracle.md new file mode 100644 index 00000000..b3dcdb3b --- /dev/null +++ b/release/v13/docs/Oracle.md @@ -0,0 +1,88 @@ + + + +# Module `0x1::PriceOracleScripts` + + + +- [Function `register_oracle`](#0x1_PriceOracleScripts_register_oracle) +- [Function `init_data_source`](#0x1_PriceOracleScripts_init_data_source) +- [Function `update`](#0x1_PriceOracleScripts_update) + + +
use 0x1::PriceOracle;
+
+ + + + + +## Function `register_oracle` + + + +
public entry fun register_oracle<OracleT: copy, drop, store>(sender: signer, precision: u8)
+
+ + + +
+Implementation + + +
public entry fun register_oracle<OracleT: copy+store+drop>(sender: signer, precision: u8){
+    PriceOracle::register_oracle_entry<OracleT>(sender, precision);
+}
+
+ + + +
+ + + +## Function `init_data_source` + + + +
public entry fun init_data_source<OracleT: copy, drop, store>(sender: signer, init_value: u128)
+
+ + + +
+Implementation + + +
public entry fun init_data_source<OracleT: copy+store+drop>(sender: signer, init_value: u128){
+    PriceOracle::init_data_source_entry<OracleT>(sender, init_value);
+}
+
+ + + +
+ + + +## Function `update` + + + +
public entry fun update<OracleT: copy, drop, store>(sender: signer, value: u128)
+
+ + + +
+Implementation + + +
public entry fun update<OracleT: copy+store+drop>(sender: signer, value: u128){
+    PriceOracle::update_entry<OracleT>(sender, value);
+}
+
+ + + +
diff --git a/release/v13/docs/PackageTxnManager.md b/release/v13/docs/PackageTxnManager.md new file mode 100644 index 00000000..328505ed --- /dev/null +++ b/release/v13/docs/PackageTxnManager.md @@ -0,0 +1,1454 @@ + + + +# Module `0x1::PackageTxnManager` + +The module provides strategies for module upgrading. + + +- [Struct `UpgradePlan`](#0x1_PackageTxnManager_UpgradePlan) +- [Resource `UpgradePlanCapability`](#0x1_PackageTxnManager_UpgradePlanCapability) +- [Struct `UpgradePlanV2`](#0x1_PackageTxnManager_UpgradePlanV2) +- [Resource `ModuleUpgradeStrategy`](#0x1_PackageTxnManager_ModuleUpgradeStrategy) +- [Resource `TwoPhaseUpgrade`](#0x1_PackageTxnManager_TwoPhaseUpgrade) +- [Struct `TwoPhaseUpgradeConfig`](#0x1_PackageTxnManager_TwoPhaseUpgradeConfig) +- [Resource `TwoPhaseUpgradeV2`](#0x1_PackageTxnManager_TwoPhaseUpgradeV2) +- [Struct `UpgradeEvent`](#0x1_PackageTxnManager_UpgradeEvent) +- [Constants](#@Constants_0) +- [Function `get_strategy_arbitrary`](#0x1_PackageTxnManager_get_strategy_arbitrary) +- [Function `get_strategy_two_phase`](#0x1_PackageTxnManager_get_strategy_two_phase) +- [Function `get_strategy_new_module`](#0x1_PackageTxnManager_get_strategy_new_module) +- [Function `get_strategy_freeze`](#0x1_PackageTxnManager_get_strategy_freeze) +- [Function `get_default_min_time_limit`](#0x1_PackageTxnManager_get_default_min_time_limit) +- [Function `update_module_upgrade_strategy`](#0x1_PackageTxnManager_update_module_upgrade_strategy) +- [Function `account_address`](#0x1_PackageTxnManager_account_address) +- [Function `destroy_upgrade_plan_cap`](#0x1_PackageTxnManager_destroy_upgrade_plan_cap) +- [Function `extract_submit_upgrade_plan_cap`](#0x1_PackageTxnManager_extract_submit_upgrade_plan_cap) +- [Function `convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2`](#0x1_PackageTxnManager_convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2) +- [Function `submit_upgrade_plan_v2`](#0x1_PackageTxnManager_submit_upgrade_plan_v2) +- [Function `submit_upgrade_plan_with_cap_v2`](#0x1_PackageTxnManager_submit_upgrade_plan_with_cap_v2) +- [Function `cancel_upgrade_plan`](#0x1_PackageTxnManager_cancel_upgrade_plan) +- [Function `cancel_upgrade_plan_with_cap`](#0x1_PackageTxnManager_cancel_upgrade_plan_with_cap) +- [Function `get_module_upgrade_strategy`](#0x1_PackageTxnManager_get_module_upgrade_strategy) +- [Function `get_upgrade_plan`](#0x1_PackageTxnManager_get_upgrade_plan) +- [Function `get_upgrade_plan_v2`](#0x1_PackageTxnManager_get_upgrade_plan_v2) +- [Function `check_package_txn`](#0x1_PackageTxnManager_check_package_txn) +- [Function `check_package_txn_v2`](#0x1_PackageTxnManager_check_package_txn_v2) +- [Function `finish_upgrade_plan`](#0x1_PackageTxnManager_finish_upgrade_plan) +- [Function `package_txn_prologue`](#0x1_PackageTxnManager_package_txn_prologue) +- [Function `package_txn_prologue_v2`](#0x1_PackageTxnManager_package_txn_prologue_v2) +- [Function `package_txn_epilogue`](#0x1_PackageTxnManager_package_txn_epilogue) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Option;
+use 0x1::Signer;
+use 0x1::Timestamp;
+use 0x1::Version;
+
+ + + + + +## Struct `UpgradePlan` + +module upgrade plan + + +
struct UpgradePlan has copy, drop, store
+
+ + + +
+Fields + + +
+
+package_hash: vector<u8> +
+
+ +
+
+active_after_time: u64 +
+
+ +
+
+version: u64 +
+
+ +
+
+ + +
+ + + +## Resource `UpgradePlanCapability` + +The holder of UpgradePlanCapability for account_address can submit UpgradePlan for account_address. + + +
struct UpgradePlanCapability has store, key
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+ + +
+ + + +## Struct `UpgradePlanV2` + + + +
struct UpgradePlanV2 has copy, drop, store
+
+ + + +
+Fields + + +
+
+package_hash: vector<u8> +
+
+ +
+
+active_after_time: u64 +
+
+ +
+
+version: u64 +
+
+ +
+
+enforced: bool +
+
+ +
+
+ + +
+ + + +## Resource `ModuleUpgradeStrategy` + +module upgrade strategy + + +
struct ModuleUpgradeStrategy has store, key
+
+ + + +
+Fields + + +
+
+strategy: u8 +
+
+ 0 arbitrary + 1 two phase upgrade + 2 only new module + 3 freeze +
+
+ + +
+ + + +## Resource `TwoPhaseUpgrade` + +data of two phase upgrade strategy. + + +
struct TwoPhaseUpgrade has key
+
+ + + +
+Fields + + +
+
+config: PackageTxnManager::TwoPhaseUpgradeConfig +
+
+ +
+
+plan: Option::Option<PackageTxnManager::UpgradePlan> +
+
+ +
+
+version_cap: Config::ModifyConfigCapability<Version::Version> +
+
+ +
+
+upgrade_event: Event::EventHandle<PackageTxnManager::UpgradeEvent> +
+
+ +
+
+ + +
+ + + +## Struct `TwoPhaseUpgradeConfig` + +config of two phase upgrade strategy. + + +
struct TwoPhaseUpgradeConfig has copy, drop, store
+
+ + + +
+Fields + + +
+
+min_time_limit: u64 +
+
+ +
+
+ + +
+ + + +## Resource `TwoPhaseUpgradeV2` + +data of two phase upgrade strategy. + + +
struct TwoPhaseUpgradeV2 has key
+
+ + + +
+Fields + + +
+
+config: PackageTxnManager::TwoPhaseUpgradeConfig +
+
+ +
+
+plan: Option::Option<PackageTxnManager::UpgradePlanV2> +
+
+ +
+
+version_cap: Config::ModifyConfigCapability<Version::Version> +
+
+ +
+
+upgrade_event: Event::EventHandle<PackageTxnManager::UpgradeEvent> +
+
+ +
+
+ + +
+ + + +## Struct `UpgradeEvent` + +module upgrade event. + + +
struct UpgradeEvent has drop, store
+
+ + + +
+Fields + + +
+
+package_address: address +
+
+ +
+
+package_hash: vector<u8> +
+
+ +
+
+version: u64 +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const DEFAULT_MIN_TIME_LIMIT: u64 = 86400000;
+
+ + + + + + + +
const EACTIVE_TIME_INCORRECT: u64 = 104;
+
+ + + + + + + +
const EPACKAGE_HASH_INCORRECT: u64 = 103;
+
+ + + + + + + +
const ESENDER_AND_PACKAGE_ADDRESS_MISMATCH: u64 = 109;
+
+ + + + + + + +
const ESTRATEGY_FREEZED: u64 = 105;
+
+ + + + + + + +
const ESTRATEGY_INCORRECT: u64 = 106;
+
+ + + + + + + +
const ESTRATEGY_NOT_TWO_PHASE: u64 = 107;
+
+ + + + + + + +
const EUNKNOWN_STRATEGY: u64 = 108;
+
+ + + + + + + +
const EUPGRADE_PLAN_IS_NONE: u64 = 102;
+
+ + + + + + + +
const STRATEGY_ARBITRARY: u8 = 0;
+
+ + + + + + + +
const STRATEGY_FREEZE: u8 = 3;
+
+ + + + + + + +
const STRATEGY_NEW_MODULE: u8 = 2;
+
+ + + + + + + +
const STRATEGY_TWO_PHASE: u8 = 1;
+
+ + + + + +## Function `get_strategy_arbitrary` + +arbitary stragegy + + +
public fun get_strategy_arbitrary(): u8
+
+ + + +
+Implementation + + +
public fun get_strategy_arbitrary(): u8 { STRATEGY_ARBITRARY }
+
+ + + +
+ + + +## Function `get_strategy_two_phase` + +two phase stragegy + + +
public fun get_strategy_two_phase(): u8
+
+ + + +
+Implementation + + +
public fun get_strategy_two_phase(): u8 { STRATEGY_TWO_PHASE }
+
+ + + +
+ + + +## Function `get_strategy_new_module` + +new module strategy + + +
public fun get_strategy_new_module(): u8
+
+ + + +
+Implementation + + +
public fun get_strategy_new_module(): u8 { STRATEGY_NEW_MODULE }
+
+ + + +
+ + + +## Function `get_strategy_freeze` + +freezed strategy + + +
public fun get_strategy_freeze(): u8
+
+ + + +
+Implementation + + +
public fun get_strategy_freeze(): u8 { STRATEGY_FREEZE }
+
+ + + +
+ + + +## Function `get_default_min_time_limit` + +default min time limit + + +
public fun get_default_min_time_limit(): u64
+
+ + + +
+Implementation + + +
public fun get_default_min_time_limit(): u64 { DEFAULT_MIN_TIME_LIMIT }
+
+ + + +
+ + + +## Function `update_module_upgrade_strategy` + +Update account's ModuleUpgradeStrategy + + +
public fun update_module_upgrade_strategy(account: &signer, strategy: u8, min_time: Option::Option<u64>)
+
+ + + +
+Implementation + + +
public fun update_module_upgrade_strategy(account: &signer, strategy: u8, min_time: Option<u64>) acquires ModuleUpgradeStrategy, TwoPhaseUpgrade, TwoPhaseUpgradeV2, UpgradePlanCapability{
+    assert!(strategy == STRATEGY_ARBITRARY || strategy == STRATEGY_TWO_PHASE || strategy == STRATEGY_NEW_MODULE || strategy == STRATEGY_FREEZE, Errors::invalid_argument(EUNKNOWN_STRATEGY));
+    let account_address = Signer::address_of(account);
+    let previous_strategy = get_module_upgrade_strategy(account_address);
+    assert!(strategy > previous_strategy, Errors::invalid_argument(ESTRATEGY_INCORRECT));
+    if (exists<ModuleUpgradeStrategy>(account_address)) {
+        borrow_global_mut<ModuleUpgradeStrategy>(account_address).strategy = strategy;
+    }else{
+        move_to(account, ModuleUpgradeStrategy{ strategy: strategy});
+    };
+    if (strategy == STRATEGY_TWO_PHASE){
+        let version_cap = Config::extract_modify_config_capability<Version::Version>(account);
+        let min_time_limit = Option::get_with_default(&min_time, DEFAULT_MIN_TIME_LIMIT);
+        move_to(account, UpgradePlanCapability{ account_address: account_address});
+        move_to(account, TwoPhaseUpgradeV2{
+            config: TwoPhaseUpgradeConfig{min_time_limit: min_time_limit},
+            plan: Option::none<UpgradePlanV2>(),
+            version_cap: version_cap,
+            upgrade_event: Event::new_event_handle<Self::UpgradeEvent>(account)}
+        );
+    };
+    //clean two phase upgrade resource
+    if (previous_strategy == STRATEGY_TWO_PHASE){
+        if (exists<TwoPhaseUpgrade>(account_address)) {
+            let tpu = move_from<TwoPhaseUpgrade>(account_address);
+            let TwoPhaseUpgrade{plan:_, version_cap, upgrade_event, config: _} = tpu;
+            Event::destroy_handle<Self::UpgradeEvent>(upgrade_event);
+            Config::destroy_modify_config_capability<Version::Version>(version_cap);
+        };
+        if (exists<TwoPhaseUpgradeV2>(account_address)) {
+            let tpu = move_from<TwoPhaseUpgradeV2>(account_address);
+            let TwoPhaseUpgradeV2{plan:_, version_cap, upgrade_event, config: _} = tpu;
+            Event::destroy_handle<Self::UpgradeEvent>(upgrade_event);
+            Config::destroy_modify_config_capability<Version::Version>(version_cap);
+        };
+        // UpgradePlanCapability may be extracted
+        if (exists<UpgradePlanCapability>(account_address)) {
+            let cap = move_from<UpgradePlanCapability>(account_address);
+            destroy_upgrade_plan_cap(cap);
+        };
+    };
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+aborts_if strategy != 0 && strategy != 1 && strategy != 2 && strategy != 3;
+aborts_if exists<ModuleUpgradeStrategy>(Signer::address_of(account)) && strategy <= global<ModuleUpgradeStrategy>(Signer::address_of(account)).strategy;
+aborts_if !exists<ModuleUpgradeStrategy>(Signer::address_of(account)) && strategy == 0;
+aborts_if strategy == 1 && exists<UpgradePlanCapability>(Signer::address_of(account));
+aborts_if strategy == 1 && !exists<Config::ModifyConfigCapabilityHolder<Version::Version>>(Signer::address_of(account));
+let holder = global<Config::ModifyConfigCapabilityHolder<Version::Version>>(Signer::address_of(account));
+aborts_if strategy == 1 && Option::is_none<Config::ModifyConfigCapability<Version::Version>>(holder.cap);
+aborts_if strategy == 1 && exists<TwoPhaseUpgrade>(Signer::address_of(account));
+aborts_if exists<ModuleUpgradeStrategy>(Signer::address_of(account)) && global<ModuleUpgradeStrategy>(Signer::address_of(account)).strategy == 1
+    && !exists<TwoPhaseUpgrade>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `account_address` + +Get account address of UpgradePlanCapability + + +
public fun account_address(cap: &PackageTxnManager::UpgradePlanCapability): address
+
+ + + +
+Implementation + + +
public fun account_address(cap: &UpgradePlanCapability): address {
+    cap.account_address
+}
+
+ + + +
+ + + +## Function `destroy_upgrade_plan_cap` + +destroy the given UpgradePlanCapability + + +
public fun destroy_upgrade_plan_cap(cap: PackageTxnManager::UpgradePlanCapability)
+
+ + + +
+Implementation + + +
public fun destroy_upgrade_plan_cap(cap: UpgradePlanCapability){
+    let UpgradePlanCapability{account_address:_} = cap;
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `extract_submit_upgrade_plan_cap` + +extract out UpgradePlanCapability from signer. + + +
public fun extract_submit_upgrade_plan_cap(account: &signer): PackageTxnManager::UpgradePlanCapability
+
+ + + +
+Implementation + + +
public fun extract_submit_upgrade_plan_cap(account: &signer): UpgradePlanCapability acquires ModuleUpgradeStrategy, UpgradePlanCapability{
+    let account_address = Signer::address_of(account);
+    assert!(get_module_upgrade_strategy(account_address) == STRATEGY_TWO_PHASE, Errors::invalid_argument(ESTRATEGY_NOT_TWO_PHASE));
+    move_from<UpgradePlanCapability>(account_address)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<ModuleUpgradeStrategy>(Signer::address_of(account));
+aborts_if global<ModuleUpgradeStrategy>(Signer::address_of(account)).strategy != 1;
+aborts_if !exists<UpgradePlanCapability>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2` + + + +
public entry fun convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2(account: signer, package_address: address)
+
+ + + +
+Implementation + + +
public entry fun convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2(account: signer, package_address: address) acquires TwoPhaseUpgrade {
+    let account_address = Signer::address_of(&account);
+    // sender should be package owner
+    assert!(account_address == package_address, Errors::requires_address(ESENDER_AND_PACKAGE_ADDRESS_MISMATCH));
+    let tpu = move_from<TwoPhaseUpgrade>(account_address);
+    let TwoPhaseUpgrade{config, plan, version_cap, upgrade_event} = tpu;
+    if (Option::is_some(&plan)) {
+        let old_plan = Option::borrow(&plan);
+        move_to(&account, TwoPhaseUpgradeV2{
+            config: config,
+            plan: Option::some(UpgradePlanV2 {
+                package_hash: *&old_plan.package_hash,
+                active_after_time: old_plan.active_after_time,
+                version: old_plan.version,
+                enforced: false }),
+            version_cap: version_cap,
+            upgrade_event: upgrade_event
+        });
+    } else {
+        move_to(&account, TwoPhaseUpgradeV2{
+            config: config,
+            plan: Option::none<UpgradePlanV2>(),
+            version_cap: version_cap,
+            upgrade_event: upgrade_event
+        });
+    };
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `submit_upgrade_plan_v2` + + + +
public fun submit_upgrade_plan_v2(account: &signer, package_hash: vector<u8>, version: u64, enforced: bool)
+
+ + + +
+Implementation + + +
public fun submit_upgrade_plan_v2(account: &signer, package_hash: vector<u8>, version:u64, enforced: bool) acquires TwoPhaseUpgradeV2,UpgradePlanCapability,ModuleUpgradeStrategy{
+    let account_address = Signer::address_of(account);
+    let cap = borrow_global<UpgradePlanCapability>(account_address);
+    submit_upgrade_plan_with_cap_v2(cap, package_hash, version, enforced);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+aborts_if !exists<UpgradePlanCapability>(Signer::address_of(account));
+include SubmitUpgradePlanWithCapAbortsIf{account: global<UpgradePlanCapability>(Signer::address_of(account)).account_address};
+ensures Option::is_some(global<TwoPhaseUpgrade>(global<UpgradePlanCapability>(Signer::address_of(account)).account_address).plan);
+
+ + + +
+ + + +## Function `submit_upgrade_plan_with_cap_v2` + + + +
public fun submit_upgrade_plan_with_cap_v2(cap: &PackageTxnManager::UpgradePlanCapability, package_hash: vector<u8>, version: u64, enforced: bool)
+
+ + + +
+Implementation + + +
public fun submit_upgrade_plan_with_cap_v2(cap: &UpgradePlanCapability, package_hash: vector<u8>, version: u64, enforced: bool) acquires TwoPhaseUpgradeV2,ModuleUpgradeStrategy{
+    let package_address = cap.account_address;
+    assert!(get_module_upgrade_strategy(package_address) == STRATEGY_TWO_PHASE, Errors::invalid_argument(ESTRATEGY_NOT_TWO_PHASE));
+    let tpu = borrow_global_mut<TwoPhaseUpgradeV2>(package_address);
+    let active_after_time = Timestamp::now_milliseconds() + tpu.config.min_time_limit;
+    tpu.plan = Option::some(UpgradePlanV2 { package_hash, active_after_time, version, enforced });
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+include SubmitUpgradePlanWithCapAbortsIf{account: cap.account_address};
+ensures Option::is_some(global<TwoPhaseUpgrade>(cap.account_address).plan);
+
+ + + + + + + +
schema SubmitUpgradePlanWithCapAbortsIf {
+    account: address;
+    aborts_if !exists<ModuleUpgradeStrategy>(account);
+    aborts_if global<ModuleUpgradeStrategy>(account).strategy != 1;
+    aborts_if !exists<TwoPhaseUpgrade>(account);
+    aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if Timestamp::now_milliseconds() + global<TwoPhaseUpgrade>(account).config.min_time_limit > max_u64();
+}
+
+ + + +
+ + + +## Function `cancel_upgrade_plan` + +Cancel a module upgrade plan. + + +
public fun cancel_upgrade_plan(account: &signer)
+
+ + + +
+Implementation + + +
public fun cancel_upgrade_plan(account: &signer) acquires TwoPhaseUpgradeV2,UpgradePlanCapability,ModuleUpgradeStrategy{
+    let account_address = Signer::address_of(account);
+    let cap = borrow_global<UpgradePlanCapability>(account_address);
+    cancel_upgrade_plan_with_cap(cap);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<UpgradePlanCapability>(Signer::address_of(account));
+include CancelUpgradePlanWithCapAbortsIf{account: global<UpgradePlanCapability>(Signer::address_of(account)).account_address};
+ensures Option::is_none(global<TwoPhaseUpgrade>(global<UpgradePlanCapability>(Signer::address_of(account)).account_address).plan);
+
+ + + +
+ + + +## Function `cancel_upgrade_plan_with_cap` + +Cancel a module upgrade plan with given cap. + + +
public fun cancel_upgrade_plan_with_cap(cap: &PackageTxnManager::UpgradePlanCapability)
+
+ + + +
+Implementation + + +
public fun cancel_upgrade_plan_with_cap(cap: &UpgradePlanCapability) acquires TwoPhaseUpgradeV2,ModuleUpgradeStrategy{
+    let package_address = cap.account_address;
+    assert!(get_module_upgrade_strategy(package_address) == STRATEGY_TWO_PHASE, Errors::invalid_argument(ESTRATEGY_NOT_TWO_PHASE));
+    let tpu = borrow_global_mut<TwoPhaseUpgradeV2>(package_address);
+    assert!(Option::is_some(&tpu.plan), Errors::invalid_state(EUPGRADE_PLAN_IS_NONE));
+    tpu.plan = Option::none<UpgradePlanV2>();
+}
+
+ + + +
+ +
+Specification + + + +
include CancelUpgradePlanWithCapAbortsIf{account: cap.account_address};
+ensures Option::is_none(global<TwoPhaseUpgrade>(cap.account_address).plan);
+
+ + + + + + + +
schema CancelUpgradePlanWithCapAbortsIf {
+    account: address;
+    aborts_if !exists<ModuleUpgradeStrategy>(account);
+    aborts_if global<ModuleUpgradeStrategy>(account).strategy != 1;
+    aborts_if !exists<TwoPhaseUpgrade>(account);
+    aborts_if !Option::is_some(global<TwoPhaseUpgrade>(account).plan);
+}
+
+ + + +
+ + + +## Function `get_module_upgrade_strategy` + +Get module upgrade strategy of an module address. + + +
public fun get_module_upgrade_strategy(module_address: address): u8
+
+ + + +
+Implementation + + +
public fun get_module_upgrade_strategy(module_address: address): u8 acquires ModuleUpgradeStrategy {
+    if (exists<ModuleUpgradeStrategy>(module_address)) {
+        borrow_global<ModuleUpgradeStrategy>(module_address).strategy
+    }else{
+        0
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + + + + + +
fun spec_get_module_upgrade_strategy(module_address: address): u8 {
+   if (exists<ModuleUpgradeStrategy>(module_address)) {
+       global<ModuleUpgradeStrategy>(module_address).strategy
+   }else{
+       0
+   }
+}
+
+ + + +
+ + + +## Function `get_upgrade_plan` + +Get module upgrade plan of an address. + + +
public fun get_upgrade_plan(_module_address: address): Option::Option<PackageTxnManager::UpgradePlan>
+
+ + + +
+Implementation + + +
public fun get_upgrade_plan(_module_address: address): Option<UpgradePlan> {
+    // DEPRECATED_CODE
+    Option::none<UpgradePlan>()
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `get_upgrade_plan_v2` + +Get module upgrade plan of an address. + + +
public fun get_upgrade_plan_v2(module_address: address): Option::Option<PackageTxnManager::UpgradePlanV2>
+
+ + + +
+Implementation + + +
public fun get_upgrade_plan_v2(module_address: address): Option<UpgradePlanV2> acquires TwoPhaseUpgradeV2 {
+    if (exists<TwoPhaseUpgradeV2>(module_address)) {
+        *&borrow_global<TwoPhaseUpgradeV2>(module_address).plan
+    } else {
+        Option::none<UpgradePlanV2>()
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+aborts_if false;
+
+ + + + + + + +
fun spec_get_upgrade_plan_v2(module_address: address): Option<UpgradePlan> {
+   if (exists<TwoPhaseUpgrade>(module_address)) {
+       global<TwoPhaseUpgrade>(module_address).plan
+   }else{
+       Option::spec_none<UpgradePlan>()
+   }
+}
+
+ + + +
+ + + +## Function `check_package_txn` + +Check againest on the given package data. + + +
public fun check_package_txn(package_address: address, package_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun check_package_txn(package_address: address, package_hash: vector<u8>) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy{
+    let strategy = get_module_upgrade_strategy(package_address);
+    if (strategy == STRATEGY_ARBITRARY){
+        //do nothing
+    }else if(strategy == STRATEGY_TWO_PHASE){
+        let plan_opt = get_upgrade_plan_v2(package_address);
+        assert!(Option::is_some(&plan_opt), Errors::invalid_argument(EUPGRADE_PLAN_IS_NONE));
+        let plan = Option::borrow(&plan_opt);
+        assert!(*&plan.package_hash == package_hash, Errors::invalid_argument(EPACKAGE_HASH_INCORRECT));
+        assert!(plan.active_after_time <= Timestamp::now_milliseconds(), Errors::invalid_argument(EACTIVE_TIME_INCORRECT));
+    }else if(strategy == STRATEGY_NEW_MODULE){
+        //do check at VM runtime.
+    }else if(strategy == STRATEGY_FREEZE){
+        Errors::invalid_argument(ESTRATEGY_FREEZED);
+    };
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+include CheckPackageTxnAbortsIf;
+
+ + + +
+ + + +## Function `check_package_txn_v2` + + + +
public fun check_package_txn_v2(txn_sender: address, package_address: address, package_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun check_package_txn_v2(txn_sender: address, package_address: address, package_hash: vector<u8>) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy{
+    let strategy = get_module_upgrade_strategy(package_address);
+    if (strategy == STRATEGY_ARBITRARY){
+        assert!(txn_sender == package_address, Errors::requires_address(ESENDER_AND_PACKAGE_ADDRESS_MISMATCH));
+    }else if(strategy == STRATEGY_TWO_PHASE){
+        let plan_opt = get_upgrade_plan_v2(package_address);
+        assert!(Option::is_some(&plan_opt), Errors::invalid_argument(EUPGRADE_PLAN_IS_NONE));
+        let plan = Option::borrow(&plan_opt);
+        assert!(*&plan.package_hash == package_hash, Errors::invalid_argument(EPACKAGE_HASH_INCORRECT));
+        assert!(plan.active_after_time <= Timestamp::now_milliseconds(), Errors::invalid_argument(EACTIVE_TIME_INCORRECT));
+    }else if(strategy == STRATEGY_NEW_MODULE){
+        //do check at VM runtime.
+        assert!(txn_sender == package_address, Errors::requires_address(ESENDER_AND_PACKAGE_ADDRESS_MISMATCH));
+    }else if(strategy == STRATEGY_FREEZE){
+        Errors::invalid_argument(ESTRATEGY_FREEZED);
+    };
+}
+
+ + + +
+ + + +## Function `finish_upgrade_plan` + + + +
fun finish_upgrade_plan(package_address: address)
+
+ + + +
+Implementation + + +
fun finish_upgrade_plan(package_address: address) acquires TwoPhaseUpgradeV2 {
+    let tpu = borrow_global_mut<TwoPhaseUpgradeV2>(package_address);
+    if (Option::is_some(&tpu.plan)) {
+        let plan = Option::borrow(&tpu.plan);
+        Config::set_with_capability<Version::Version>(&mut tpu.version_cap, Version::new_version(plan.version));
+        Event::emit_event<Self::UpgradeEvent>(&mut tpu.upgrade_event, UpgradeEvent {
+            package_address: package_address,
+            package_hash: *&plan.package_hash,
+            version: plan.version});
+    };
+    tpu.plan = Option::none<UpgradePlanV2>();
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+aborts_if !exists<TwoPhaseUpgrade>(package_address);
+let tpu = global<TwoPhaseUpgrade>(package_address);
+aborts_if Option::is_some(tpu.plan) && !exists<Config::Config<Version::Version>>(tpu.version_cap.account_address);
+
+ + + +
+ + + +## Function `package_txn_prologue` + +Prologue of package transaction. + + +
public fun package_txn_prologue(account: &signer, package_address: address, package_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun package_txn_prologue(account: &signer, package_address: address, package_hash: vector<u8>) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy {
+    // Can only be invoked by genesis account
+    CoreAddresses::assert_genesis_address(account);
+    check_package_txn(package_address, package_hash);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+include CheckPackageTxnAbortsIf{};
+
+ + + +
+ + + +## Function `package_txn_prologue_v2` + + + +
public fun package_txn_prologue_v2(account: &signer, txn_sender: address, package_address: address, package_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun package_txn_prologue_v2(account: &signer, txn_sender: address, package_address: address, package_hash: vector<u8>) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy {
+    // Can only be invoked by genesis account
+    CoreAddresses::assert_genesis_address(account);
+    check_package_txn_v2(txn_sender, package_address, package_hash);
+}
+
+ + + +
+ + + +## Function `package_txn_epilogue` + +Package txn finished, and clean UpgradePlan + + +
public fun package_txn_epilogue(account: &signer, _txn_sender: address, package_address: address, success: bool)
+
+ + + +
+Implementation + + +
public fun package_txn_epilogue(account: &signer, _txn_sender: address, package_address: address, success: bool) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy {
+    // Can only be invoked by genesis account
+    CoreAddresses::assert_genesis_address(account);
+    let strategy = get_module_upgrade_strategy(package_address);
+    if(strategy == STRATEGY_TWO_PHASE){
+        if (success) {
+            finish_upgrade_plan(package_address);
+        };
+    };
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if spec_get_module_upgrade_strategy(package_address) == 1
+    && success && !exists<TwoPhaseUpgrade>(package_address);
+aborts_if spec_get_module_upgrade_strategy(package_address) == 1
+    && success && Option::is_some(global<TwoPhaseUpgrade>(package_address).plan)
+    && !exists<Config::Config<Version::Version>>(global<TwoPhaseUpgrade>(package_address).version_cap.account_address);
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/README.md b/release/v13/docs/README.md new file mode 100644 index 00000000..abbf5f43 --- /dev/null +++ b/release/v13/docs/README.md @@ -0,0 +1,111 @@ + + + +# Move StarcoinFramework Modules + + +This is the root document for the Move StarcoinFramework module documentation. The Move StarcoinFramework provides modules that can be used to access or interact with Starcoin blockchain. + + + + +## Index + + +- [`0x1::ACL`](ACL.md#0x1_ACL) +- [`0x1::Account`](Account.md#0x1_Account) +- [`0x1::AccountScripts`](AccountScripts.md#0x1_AccountScripts) +- [`0x1::Arith`](U256.md#0x1_Arith) +- [`0x1::Authenticator`](Authenticator.md#0x1_Authenticator) +- [`0x1::BCS`](BCS.md#0x1_BCS) +- [`0x1::BitOperators`](Bitwise.md#0x1_BitOperators) +- [`0x1::Block`](Block.md#0x1_Block) +- [`0x1::BlockReward`](BlockReward.md#0x1_BlockReward) +- [`0x1::ChainId`](ChainId.md#0x1_ChainId) +- [`0x1::Collection`](Collection.md#0x1_Collection) +- [`0x1::Collection2`](Collection2.md#0x1_Collection2) +- [`0x1::Compare`](Compare.md#0x1_Compare) +- [`0x1::Config`](Config.md#0x1_Config) +- [`0x1::ConsensusConfig`](ConsensusConfig.md#0x1_ConsensusConfig) +- [`0x1::ConsensusStrategy`](ConsensusStrategy.md#0x1_ConsensusStrategy) +- [`0x1::CoreAddresses`](CoreAddresses.md#0x1_CoreAddresses) +- [`0x1::Dao`](Dao.md#0x1_Dao) +- [`0x1::DaoVoteScripts`](DaoVoteScripts.md#0x1_DaoVoteScripts) +- [`0x1::Debug`](Debug.md#0x1_Debug) +- [`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) +- [`0x1::Event`](Event.md#0x1_Event) +- [`0x1::EventUtil`](EventUtil.md#0x1_EventUtil) +- [`0x1::FixedPoint32`](FixedPoint32.md#0x1_FixedPoint32) +- [`0x1::FlexiDagConfig`](FlexiDagConfig.md#0x1_FlexiDagConfig) +- [`0x1::FromBCS`](FromBCS.md#0x1_FromBCS) +- [`0x1::GasSchedule`](GasSchedule.md#0x1_GasSchedule) +- [`0x1::Genesis`](Genesis.md#0x1_Genesis) +- [`0x1::GenesisNFT`](GenesisNFT.md#0x1_GenesisNFT) +- [`0x1::GenesisNFTScripts`](GenesisNFT.md#0x1_GenesisNFTScripts) +- [`0x1::GenesisSignerCapability`](GenesisSignerCapability.md#0x1_GenesisSignerCapability) +- [`0x1::Hash`](Hash.md#0x1_Hash) +- [`0x1::IdentifierNFT`](NFT.md#0x1_IdentifierNFT) +- [`0x1::IdentifierNFTScripts`](NFT.md#0x1_IdentifierNFTScripts) +- [`0x1::LanguageVersion`](LanguageVersion.md#0x1_LanguageVersion) +- [`0x1::Math`](Math.md#0x1_Math) +- [`0x1::MerkleNFTDistributor`](MerkleNFT.md#0x1_MerkleNFTDistributor) +- [`0x1::MerkleProof`](MerkleNFT.md#0x1_MerkleProof) +- [`0x1::MintDaoProposal`](MintDaoProposal.md#0x1_MintDaoProposal) +- [`0x1::MintScripts`](MintScripts.md#0x1_MintScripts) +- [`0x1::ModifyDaoConfigProposal`](ModifyDaoConfigProposal.md#0x1_ModifyDaoConfigProposal) +- [`0x1::ModuleUpgradeScripts`](ModuleUpgradeScripts.md#0x1_ModuleUpgradeScripts) +- [`0x1::NFT`](NFT.md#0x1_NFT) +- [`0x1::NFTGallery`](NFT.md#0x1_NFTGallery) +- [`0x1::NFTGalleryScripts`](NFT.md#0x1_NFTGalleryScripts) +- [`0x1::Offer`](Offer.md#0x1_Offer) +- [`0x1::OnChainConfigDao`](OnChainConfigDao.md#0x1_OnChainConfigDao) +- [`0x1::OnChainConfigScripts`](OnChainConfigScripts.md#0x1_OnChainConfigScripts) +- [`0x1::Option`](Option.md#0x1_Option) +- [`0x1::Oracle`](Oracle.md#0x1_Oracle) +- [`0x1::PackageTxnManager`](PackageTxnManager.md#0x1_PackageTxnManager) +- [`0x1::PriceOracle`](Oracle.md#0x1_PriceOracle) +- [`0x1::PriceOracleAggregator`](Oracle.md#0x1_PriceOracleAggregator) +- [`0x1::PriceOracleScripts`](Oracle.md#0x1_PriceOracleScripts) +- [`0x1::RewardConfig`](RewardConfig.md#0x1_RewardConfig) +- [`0x1::Ring`](Ring.md#0x1_Ring) +- [`0x1::SIP_2`](SIPs.md#0x1_SIP_2) +- [`0x1::SIP_3`](SIPs.md#0x1_SIP_3) +- [`0x1::STC`](STC.md#0x1_STC) +- [`0x1::STCUSDOracle`](Oracle.md#0x1_STCUSDOracle) +- [`0x1::Secp256k1`](Secp256k1.md#0x1_Secp256k1) +- [`0x1::SharedEd25519PublicKey`](SharedEd25519PublicKey.md#0x1_SharedEd25519PublicKey) +- [`0x1::Signature`](Signature.md#0x1_Signature) +- [`0x1::SignedInteger64`](SignedInteger64.md#0x1_SignedInteger64) +- [`0x1::Signer`](Signer.md#0x1_Signer) +- [`0x1::SimpleMap`](SimpleMap.md#0x1_SimpleMap) +- [`0x1::StarcoinVerifier`](StarcoinVerifier.md#0x1_StarcoinVerifier) +- [`0x1::StdlibUpgradeScripts`](StdlibUpgradeScripts.md#0x1_StdlibUpgradeScripts) +- [`0x1::String`](String.md#0x1_String) +- [`0x1::StructuredHash`](StarcoinVerifier.md#0x1_StructuredHash) +- [`0x1::Table`](Table.md#0x1_Table) +- [`0x1::Timestamp`](Timestamp.md#0x1_Timestamp) +- [`0x1::Token`](Token.md#0x1_Token) +- [`0x1::TransactionFee`](TransactionFee.md#0x1_TransactionFee) +- [`0x1::TransactionManager`](TransactionManager.md#0x1_TransactionManager) +- [`0x1::TransactionPublishOption`](TransactionPublishOption.md#0x1_TransactionPublishOption) +- [`0x1::TransactionTimeout`](TransactionTimeout.md#0x1_TransactionTimeout) +- [`0x1::TransactionTimeoutConfig`](TransactionTimeoutConfig.md#0x1_TransactionTimeoutConfig) +- [`0x1::TransferScripts`](TransferScripts.md#0x1_TransferScripts) +- [`0x1::Treasury`](Treasury.md#0x1_Treasury) +- [`0x1::TreasuryScripts`](TreasuryScripts.md#0x1_TreasuryScripts) +- [`0x1::TreasuryWithdrawDaoProposal`](TreasuryWithdrawDaoProposal.md#0x1_TreasuryWithdrawDaoProposal) +- [`0x1::TypeInfo`](TypeInfo.md#0x1_TypeInfo) +- [`0x1::U256`](U256.md#0x1_U256) +- [`0x1::UpgradeModuleDaoProposal`](UpgradeModuleDaoProposal.md#0x1_UpgradeModuleDaoProposal) +- [`0x1::VMConfig`](VMConfig.md#0x1_VMConfig) +- [`0x1::Vector`](Vector.md#0x1_Vector) +- [`0x1::Version`](Version.md#0x1_Version) +- [`0x1::YieldFarming`](YieldFarming.md#0x1_YieldFarming) +- [`0x1::YieldFarmingV2`](YieldFarmingV2.md#0x1_YieldFarmingV2) diff --git a/release/v13/docs/RewardConfig.md b/release/v13/docs/RewardConfig.md new file mode 100644 index 00000000..4c300f5d --- /dev/null +++ b/release/v13/docs/RewardConfig.md @@ -0,0 +1,240 @@ + + + +# Module `0x1::RewardConfig` + +The module provide configuration for block reward. + + +- [Struct `RewardConfig`](#0x1_RewardConfig_RewardConfig) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_RewardConfig_initialize) +- [Function `new_reward_config`](#0x1_RewardConfig_new_reward_config) +- [Function `get_reward_config`](#0x1_RewardConfig_get_reward_config) +- [Function `reward_delay`](#0x1_RewardConfig_reward_delay) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::Timestamp;
+
+ + + + + +## Struct `RewardConfig` + +Reward configuration + + +
struct RewardConfig has copy, drop, store
+
+ + + +
+Fields + + +
+
+reward_delay: u64 +
+
+ how many blocks delay reward distribution. +
+
+ + +
+ + + +## Constants + + + + + + +
const EINVALID_ARGUMENT: u64 = 18;
+
+ + + + + +## Function `initialize` + +Module initialization. + + +
public fun initialize(account: &signer, reward_delay: u64)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, reward_delay: u64) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+
+    Config::publish_new_config<Self::RewardConfig>(
+        account,
+        new_reward_config(reward_delay)
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<Config::Config<RewardConfig>>(Signer::address_of(account));
+include Config::PublishNewConfigAbortsIf<RewardConfig>;
+include Config::PublishNewConfigEnsures<RewardConfig>;
+
+ + + +
+ + + +## Function `new_reward_config` + +Create a new reward config mainly used in DAO. + + +
public fun new_reward_config(reward_delay: u64): RewardConfig::RewardConfig
+
+ + + +
+Implementation + + +
public fun new_reward_config(reward_delay: u64) : RewardConfig {
+    RewardConfig {reward_delay: reward_delay}
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Function `get_reward_config` + +Get reward configuration. + + +
public fun get_reward_config(): RewardConfig::RewardConfig
+
+ + + +
+Implementation + + +
public fun get_reward_config(): RewardConfig {
+    Config::get_by_address<RewardConfig>(CoreAddresses::GENESIS_ADDRESS())
+}
+
+ + + +
+ +
+Specification + + + +
include GetRewardConfigAbortsIf;
+
+ + + + + + + +
schema GetRewardConfigAbortsIf {
+    aborts_if !exists<Config::Config<RewardConfig>>(CoreAddresses::GENESIS_ADDRESS());
+}
+
+ + + +
+ + + +## Function `reward_delay` + +Get reward delay. + + +
public fun reward_delay(): u64
+
+ + + +
+Implementation + + +
public fun reward_delay() :u64 {
+    let reward_config = get_reward_config();
+    reward_config.reward_delay
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Config::Config<RewardConfig>>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/Ring.md b/release/v13/docs/Ring.md new file mode 100644 index 00000000..074de19a --- /dev/null +++ b/release/v13/docs/Ring.md @@ -0,0 +1,426 @@ + + + +# Module `0x1::Ring` + +A ring-shaped container that can hold any type, indexed from 0 +The capacity is fixed at creation time, and the accessible index is constantly growing + + +- [Struct `Ring`](#0x1_Ring_Ring) +- [Constants](#@Constants_0) +- [Function `create_with_capacity`](#0x1_Ring_create_with_capacity) +- [Function `is_full`](#0x1_Ring_is_full) +- [Function `capacity`](#0x1_Ring_capacity) +- [Function `push`](#0x1_Ring_push) +- [Function `borrow`](#0x1_Ring_borrow) +- [Function `borrow_mut`](#0x1_Ring_borrow_mut) +- [Function `index_of`](#0x1_Ring_index_of) +- [Function `destroy`](#0x1_Ring_destroy) + + +
use 0x1::Errors;
+use 0x1::Option;
+
+ + + + + +## Struct `Ring` + + + +
struct Ring<Element> has store
+
+ + + +
+Fields + + +
+
+data: vector<Option::Option<Element>> +
+
+ +
+
+insertion_index: u64 +
+
+ +
+
+external_index: u64 +
+
+ +
+
+ + +
+ + + +## Constants + + + + +The index into the vector is out of bounds + + +
const ERROR_RING_INDEX_OUT_OF_BOUNDS: u64 = 101;
+
+ + + + + +## Function `create_with_capacity` + +Create a Ring with capacity. + + +
public fun create_with_capacity<Element>(len: u64): Ring::Ring<Element>
+
+ + + +
+Implementation + + +
public fun create_with_capacity<Element>( len: u64 ):Ring<Element>{
+    let data = Vector::empty<Option::Option<Element>>();
+    let i = 0;
+    while(i < len){
+        Vector::push_back(&mut data , Option::none<Element>());
+        i = i + 1;
+    };
+    Ring {
+        data             : data,
+        insertion_index  : 0,
+        external_index   : 0,
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `is_full` + +is Ring full + + +
public fun is_full<Element>(r: &Ring::Ring<Element>): bool
+
+ + + +
+Implementation + + +
public fun is_full<Element>(r: &Ring<Element>):bool{
+    Option::is_some(Vector::borrow(&r.data, r.insertion_index))
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `capacity` + +Return the capacity of the Ring. + + +
public fun capacity<Element>(r: &Ring::Ring<Element>): u64
+
+ + + +
+Implementation + + +
public fun capacity<Element>(r: &Ring<Element>): u64{
+    Vector::length( &r.data )
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Function `push` + +Add element e to the insertion_index of the Ring r. + + +
public fun push<Element>(r: &mut Ring::Ring<Element>, e: Element): Option::Option<Element>
+
+ + + +
+Implementation + + +
public fun push<Element> (r: &mut Ring<Element> , e: Element):Option::Option<Element>{
+    let op_e = Vector::borrow_mut<Option::Option<Element>>(&mut r.data, r.insertion_index);
+    let res = if(  Option::is_none<Element>(op_e) ){
+        Option::fill( op_e, e);
+        Option::none<Element>()
+    }else{
+       Option::some<Element>( Option::swap( op_e, e) )
+    };
+    r.insertion_index = ( r.insertion_index + 1 ) % Vector::length(&r.data);
+    r.external_index = r.external_index + 1;
+    res
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `borrow` + +Return a reference to the ith element in the Ring r. + + +
public fun borrow<Element>(r: &Ring::Ring<Element>, i: u64): &Option::Option<Element>
+
+ + + +
+Implementation + + +
public fun borrow<Element>(r:& Ring<Element>, i: u64):&Option::Option<Element>{
+    let len = capacity<Element>(r);
+    if( r.external_index > len - 1) {
+        assert!( i >= r.external_index - len && i < r.external_index , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS));
+        Vector::borrow(&r.data, i % len)
+    }else {
+        assert!( i < len , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS));
+        Vector::borrow(&r.data, i )
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `borrow_mut` + +Return a mutable reference to the ith element in the Ring r. + + +
public fun borrow_mut<Element>(r: &mut Ring::Ring<Element>, i: u64): &mut Option::Option<Element>
+
+ + + +
+Implementation + + +
public fun borrow_mut<Element>(r: &mut Ring<Element>, i: u64):&mut Option::Option<Element>{
+    let len = capacity<Element>(r);
+    if( r.external_index > len - 1) {
+        assert!( i >= r.external_index - len && i < r.external_index , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS));
+        Vector::borrow_mut(&mut r.data, i % len)
+    }else {
+        assert!( i < len , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS));
+        Vector::borrow_mut(&mut r.data, i )
+    }
+
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Function `index_of` + +Return Option::Option<u64> if e is in the Ring r at index i. +Otherwise, returns Option::none<u64>. + + +
public fun index_of<Element>(r: &Ring::Ring<Element>, e: &Element): Option::Option<u64>
+
+ + + +
+Implementation + + +
public fun index_of<Element>(r: &Ring<Element>, e: &Element):Option::Option<u64>{
+    let i = 0;
+    let len = capacity<Element>(r);
+    while ( i < len ) {
+        if ( Option::borrow(Vector::borrow( &r.data, i )) == e) return Option::some(i + r.external_index - len);
+        i = i + 1;
+    };
+    Option::none<u64>()
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `destroy` + +Destroy the Ring r. +Returns the vector saved by ring + + +
public fun destroy<Element>(r: Ring::Ring<Element>): vector<Element>
+
+ + + +
+Implementation + + +
public fun destroy<Element>(r: Ring<Element>):vector<Element>{
+    let Ring {
+        data            : data ,
+        insertion_index : _,
+        external_index  : _,
+    } = r ;
+    let len = Vector::length(&data);
+    let i = 0;
+    let vec = Vector::empty<Element>();
+    while ( i < len ) {
+        let op_e = Vector::pop_back( &mut data );
+        if ( Option::is_some(&op_e) ) {
+            Vector::push_back(&mut vec, Option::destroy_some(op_e))
+        }else {
+           Option::destroy_none(op_e)
+        };
+        i = i + 1;
+    };
+    Vector::destroy_empty(data);
+    vec
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
diff --git a/release/v13/docs/SIPs.md b/release/v13/docs/SIPs.md new file mode 100644 index 00000000..b466bfe7 --- /dev/null +++ b/release/v13/docs/SIPs.md @@ -0,0 +1,11 @@ + + + +# Module `0x1::SIP_3` + +https://github.com/starcoinorg/SIPs/tree/master/sip-3 + + + + +
diff --git a/release/v13/docs/STC.md b/release/v13/docs/STC.md new file mode 100644 index 00000000..9abaa8ef --- /dev/null +++ b/release/v13/docs/STC.md @@ -0,0 +1,405 @@ + + + +# Module `0x1::STC` + +STC is the token of Starcoin blockchain. +It uses apis defined in the Token module. + + +- [Struct `STC`](#0x1_STC_STC) +- [Resource `SharedBurnCapability`](#0x1_STC_SharedBurnCapability) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_STC_initialize) +- [Function `upgrade_from_v1_to_v2`](#0x1_STC_upgrade_from_v1_to_v2) +- [Function `initialize_v2`](#0x1_STC_initialize_v2) +- [Function `is_stc`](#0x1_STC_is_stc) +- [Function `burn`](#0x1_STC_burn) +- [Function `token_address`](#0x1_STC_token_address) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::ConsensusConfig;
+use 0x1::CoreAddresses;
+use 0x1::Dao;
+use 0x1::FlexiDagConfig;
+use 0x1::ModifyDaoConfigProposal;
+use 0x1::OnChainConfigDao;
+use 0x1::PackageTxnManager;
+use 0x1::RewardConfig;
+use 0x1::Token;
+use 0x1::TransactionPublishOption;
+use 0x1::TransactionTimeoutConfig;
+use 0x1::Treasury;
+use 0x1::UpgradeModuleDaoProposal;
+use 0x1::VMConfig;
+
+ + + + + +## Struct `STC` + +STC token marker. + + +
struct STC has copy, drop, store
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Resource `SharedBurnCapability` + +Burn capability of STC. + + +
struct SharedBurnCapability has store, key
+
+ + + +
+Fields + + +
+
+cap: Token::BurnCapability<STC::STC> +
+
+ +
+
+ + +
+ + + +## Constants + + + + +precision of STC token. + + +
const PRECISION: u8 = 9;
+
+ + + + + +## Function `initialize` + +STC initialization. + + +
public fun initialize(account: &signer, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64)
+
+ + + +
+Implementation + + +
public fun initialize(
+    account: &signer,
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+) {
+    Token::register_token<STC>(account, PRECISION);
+    let burn_cap = Token::remove_burn_capability<STC>(account);
+    move_to(account, SharedBurnCapability { cap: burn_cap });
+    Dao::plugin<STC>(
+        account,
+        voting_delay,
+        voting_period,
+        voting_quorum_rate,
+        min_action_delay,
+    );
+    ModifyDaoConfigProposal::plugin<STC>(account);
+    let upgrade_plan_cap = PackageTxnManager::extract_submit_upgrade_plan_cap(account);
+    UpgradeModuleDaoProposal::plugin<STC>(
+        account,
+        upgrade_plan_cap,
+    );
+    // the following configurations are gov-ed by Dao.
+    OnChainConfigDao::plugin<STC, TransactionPublishOption::TransactionPublishOption>(account);
+    OnChainConfigDao::plugin<STC, VMConfig::VMConfig>(account);
+    OnChainConfigDao::plugin<STC, ConsensusConfig::ConsensusConfig>(account);
+    OnChainConfigDao::plugin<STC, RewardConfig::RewardConfig>(account);
+    OnChainConfigDao::plugin<STC, TransactionTimeoutConfig::TransactionTimeoutConfig>(account);
+}
+
+ + + +
+ +
+Specification + + + +
include Token::RegisterTokenAbortsIf<STC>{precision: PRECISION};
+
+ + + +
+ + + +## Function `upgrade_from_v1_to_v2` + + + +
public fun upgrade_from_v1_to_v2(account: &signer, total_amount: u128): Treasury::WithdrawCapability<STC::STC>
+
+ + + +
+Implementation + + +
public fun upgrade_from_v1_to_v2(account: &signer,total_amount: u128,): Treasury::WithdrawCapability<STC> {
+    CoreAddresses::assert_genesis_address(account);
+
+    // Mint all stc, and destroy mint capability
+    let total_stc = Token::mint<STC>(account, total_amount-Token::market_cap<STC>());
+    let withdraw_cap = Treasury::initialize(account, total_stc);
+    let mint_cap = Token::remove_mint_capability<STC>(account);
+    Token::destroy_mint_capability(mint_cap);
+    withdraw_cap
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `initialize_v2` + +STC initialization. + + +
public fun initialize_v2(account: &signer, total_amount: u128, voting_delay: u64, voting_period: u64, voting_quorum_rate: u8, min_action_delay: u64): Treasury::WithdrawCapability<STC::STC>
+
+ + + +
+Implementation + + +
public fun initialize_v2(
+    account: &signer,
+    total_amount: u128,
+    voting_delay: u64,
+    voting_period: u64,
+    voting_quorum_rate: u8,
+    min_action_delay: u64,
+): Treasury::WithdrawCapability<STC> {
+    Token::register_token<STC>(account, PRECISION);
+
+    // Mint all stc, and destroy mint capability
+
+    let total_stc = Token::mint<STC>(account, total_amount);
+    let withdraw_cap = Treasury::initialize(account, total_stc);
+    let mint_cap = Token::remove_mint_capability<STC>(account);
+    Token::destroy_mint_capability(mint_cap);
+
+    let burn_cap = Token::remove_burn_capability<STC>(account);
+    move_to(account, SharedBurnCapability { cap: burn_cap });
+    Dao::plugin<STC>(
+        account,
+        voting_delay,
+        voting_period,
+        voting_quorum_rate,
+        min_action_delay,
+    );
+    ModifyDaoConfigProposal::plugin<STC>(account);
+    let upgrade_plan_cap = PackageTxnManager::extract_submit_upgrade_plan_cap(account);
+    UpgradeModuleDaoProposal::plugin<STC>(
+        account,
+        upgrade_plan_cap,
+    );
+    // the following configurations are gov-ed by Dao.
+    OnChainConfigDao::plugin<STC, TransactionPublishOption::TransactionPublishOption>(account);
+    OnChainConfigDao::plugin<STC, VMConfig::VMConfig>(account);
+    OnChainConfigDao::plugin<STC, ConsensusConfig::ConsensusConfig>(account);
+    OnChainConfigDao::plugin<STC, RewardConfig::RewardConfig>(account);
+    OnChainConfigDao::plugin<STC, TransactionTimeoutConfig::TransactionTimeoutConfig>(account);
+    OnChainConfigDao::plugin<STC, FlexiDagConfig::FlexiDagConfig>(account);
+    withdraw_cap
+}
+
+ + + +
+ +
+Specification + + + +
include Token::RegisterTokenAbortsIf<STC>{precision: PRECISION};
+
+ + + +
+ + + +## Function `is_stc` + +Returns true if TokenType is STC::STC + + +
public fun is_stc<TokenType: store>(): bool
+
+ + + +
+Implementation + + +
public fun is_stc<TokenType: store>(): bool {
+    Token::is_same_token<STC, TokenType>()
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Function `burn` + +Burn STC tokens. +It can be called by anyone. + + +
public fun burn(token: Token::Token<STC::STC>)
+
+ + + +
+Implementation + + +
public fun burn(token: Token<STC>) acquires SharedBurnCapability {
+    let cap = borrow_global<SharedBurnCapability>(token_address());
+    Token::burn_with_capability(&cap.cap, token);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Token::spec_abstract_total_value<STC>() - token.value < 0;
+aborts_if !exists<SharedBurnCapability>(Token::SPEC_TOKEN_TEST_ADDRESS());
+
+ + + +
+ + + +## Function `token_address` + +Return STC token address. + + +
public fun token_address(): address
+
+ + + +
+Implementation + + +
public fun token_address(): address {
+    Token::token_address<STC>()
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/Secp256k1.md b/release/v13/docs/Secp256k1.md new file mode 100644 index 00000000..bb6b5bbb --- /dev/null +++ b/release/v13/docs/Secp256k1.md @@ -0,0 +1,296 @@ + + + +# Module `0x1::Secp256k1` + +This module implements ECDSA signatures based on the prime-order secp256k1 ellptic curve (i.e., cofactor is 1). + + +- [Struct `ECDSARawPublicKey`](#0x1_Secp256k1_ECDSARawPublicKey) +- [Struct `ECDSASignature`](#0x1_Secp256k1_ECDSASignature) +- [Constants](#@Constants_0) +- [Function `ecdsa_signature_from_bytes`](#0x1_Secp256k1_ecdsa_signature_from_bytes) +- [Function `ecdsa_raw_public_key_from_64_bytes`](#0x1_Secp256k1_ecdsa_raw_public_key_from_64_bytes) +- [Function `ecdsa_raw_public_key_to_bytes`](#0x1_Secp256k1_ecdsa_raw_public_key_to_bytes) +- [Function `ecdsa_signature_to_bytes`](#0x1_Secp256k1_ecdsa_signature_to_bytes) +- [Function `ecdsa_recover`](#0x1_Secp256k1_ecdsa_recover) +- [Function `ecdsa_recover_internal`](#0x1_Secp256k1_ecdsa_recover_internal) + + +
use 0x1::Errors;
+use 0x1::Option;
+
+ + + + + +## Struct `ECDSARawPublicKey` + +A 64-byte ECDSA public key. + + +
struct ECDSARawPublicKey has copy, drop, store
+
+ + + +
+Fields + + +
+
+bytes: vector<u8> +
+
+ +
+
+ + +
+ + + +## Struct `ECDSASignature` + +A 64-byte ECDSA signature. + + +
struct ECDSASignature has copy, drop, store
+
+ + + +
+Fields + + +
+
+bytes: vector<u8> +
+
+ +
+
+ + +
+ + + +## Constants + + + + +An error occurred while deserializing, for example due to wrong input size. + + +
const E_DESERIALIZE: u64 = 1;
+
+ + + + + +The size of a secp256k1-based ECDSA public key, in bytes. + + +
const RAW_PUBLIC_KEY_NUM_BYTES: u64 = 64;
+
+ + + + + +The size of a secp256k1-based ECDSA signature, in bytes. + + +
const SIGNATURE_NUM_BYTES: u64 = 64;
+
+ + + + + +## Function `ecdsa_signature_from_bytes` + +Constructs an ECDSASignature struct from the given 64 bytes. + + +
public fun ecdsa_signature_from_bytes(bytes: vector<u8>): Secp256k1::ECDSASignature
+
+ + + +
+Implementation + + +
public fun ecdsa_signature_from_bytes(bytes: vector<u8>): ECDSASignature {
+    assert!(Vector::length(&bytes) == SIGNATURE_NUM_BYTES, Errors::invalid_argument(E_DESERIALIZE));
+    ECDSASignature { bytes }
+}
+
+ + + +
+ + + +## Function `ecdsa_raw_public_key_from_64_bytes` + +Constructs an ECDSARawPublicKey struct, given a 64-byte raw representation. + + +
public fun ecdsa_raw_public_key_from_64_bytes(bytes: vector<u8>): Secp256k1::ECDSARawPublicKey
+
+ + + +
+Implementation + + +
public fun ecdsa_raw_public_key_from_64_bytes(bytes: vector<u8>): ECDSARawPublicKey {
+    assert!(Vector::length(&bytes) == RAW_PUBLIC_KEY_NUM_BYTES, Errors::invalid_argument(E_DESERIALIZE));
+    ECDSARawPublicKey { bytes }
+}
+
+ + + +
+ + + +## Function `ecdsa_raw_public_key_to_bytes` + +Serializes an ECDSARawPublicKey struct to 64-bytes. + + +
public fun ecdsa_raw_public_key_to_bytes(pk: &Secp256k1::ECDSARawPublicKey): vector<u8>
+
+ + + +
+Implementation + + +
public fun ecdsa_raw_public_key_to_bytes(pk: &ECDSARawPublicKey): vector<u8> {
+    *&pk.bytes
+}
+
+ + + +
+ + + +## Function `ecdsa_signature_to_bytes` + +Serializes an ECDSASignature struct to 64-bytes. + + +
public fun ecdsa_signature_to_bytes(sig: &Secp256k1::ECDSASignature): vector<u8>
+
+ + + +
+Implementation + + +
public fun ecdsa_signature_to_bytes(sig: &ECDSASignature): vector<u8> {
+    *&sig.bytes
+}
+
+ + + +
+ + + +## Function `ecdsa_recover` + +Recovers the signer's raw (64-byte) public key from a secp256k1 ECDSA signature given the recovery_id and the signed +message (32 byte digest). + +Note that an invalid signature, or a signature from a different message, will result in the recovery of an +incorrect public key. This recovery algorithm can only be used to check validity of a signature if the signer's +public key (or its hash) is known beforehand. + + +
public fun ecdsa_recover(message: vector<u8>, recovery_id: u8, signature: &Secp256k1::ECDSASignature): Option::Option<Secp256k1::ECDSARawPublicKey>
+
+ + + +
+Implementation + + +
public fun ecdsa_recover(
+    message: vector<u8>,
+    recovery_id: u8,
+    signature: &ECDSASignature,
+): Option<ECDSARawPublicKey> {
+    let (pk, success) = ecdsa_recover_internal(message, recovery_id, *&signature.bytes);
+    if (success) {
+        Option::some(ecdsa_raw_public_key_from_64_bytes(pk))
+    } else {
+        Option::none<ECDSARawPublicKey>()
+    }
+}
+
+ + + +
+ + + +## Function `ecdsa_recover_internal` + +Returns (public_key, true) if signature verifies on message under the recovered public_key +and returns ([], false) otherwise. + + +
fun ecdsa_recover_internal(message: vector<u8>, recovery_id: u8, signature: vector<u8>): (vector<u8>, bool)
+
+ + + +
+Implementation + + +
native fun ecdsa_recover_internal(
+    message: vector<u8>,
+    recovery_id: u8,
+    signature: vector<u8>
+): (vector<u8>, bool);
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+
+ + + +
diff --git a/release/v13/docs/SharedEd25519PublicKey.md b/release/v13/docs/SharedEd25519PublicKey.md new file mode 100644 index 00000000..f19c8fb2 --- /dev/null +++ b/release/v13/docs/SharedEd25519PublicKey.md @@ -0,0 +1,309 @@ + + + +# Module `0x1::SharedEd25519PublicKey` + +Each address that holds a SharedEd25519PublicKey resource can rotate the public key stored in +this resource, but the account's authentication key will be updated in lockstep. This ensures +that the two keys always stay in sync. + + +- [Resource `SharedEd25519PublicKey`](#0x1_SharedEd25519PublicKey_SharedEd25519PublicKey) +- [Constants](#@Constants_0) +- [Function `publish`](#0x1_SharedEd25519PublicKey_publish) +- [Function `rotate_key_`](#0x1_SharedEd25519PublicKey_rotate_key_) +- [Function `rotate_key`](#0x1_SharedEd25519PublicKey_rotate_key) +- [Function `key`](#0x1_SharedEd25519PublicKey_key) +- [Function `exists_at`](#0x1_SharedEd25519PublicKey_exists_at) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Account;
+use 0x1::Authenticator;
+use 0x1::Errors;
+use 0x1::Signature;
+use 0x1::Signer;
+
+ + + + + +## Resource `SharedEd25519PublicKey` + +A resource that forces the account associated with rotation_cap to use a ed25519 +authentication key derived from key + + +
struct SharedEd25519PublicKey has key
+
+ + + +
+Fields + + +
+
+key: vector<u8> +
+
+ 32 byte ed25519 public key +
+
+rotation_cap: Account::KeyRotationCapability +
+
+ rotation capability for an account whose authentication key is always derived from key +
+
+ + +
+ + + +## Constants + + + + + + +
const EMALFORMED_PUBLIC_KEY: u64 = 101;
+
+ + + + + +## Function `publish` + +(1) Rotate the authentication key of the sender to key +(2) Publish a resource containing a 32-byte ed25519 public key and the rotation capability +of the sender under the account's address. +Aborts if the sender already has a SharedEd25519PublicKey resource. +Aborts if the length of new_public_key is not 32. + + +
public fun publish(account: &signer, key: vector<u8>)
+
+ + + +
+Implementation + + +
public fun publish(account: &signer, key: vector<u8>) {
+    let t = SharedEd25519PublicKey {
+        key: x"",
+        rotation_cap: Account::extract_key_rotation_capability(account)
+    };
+    rotate_key_(&mut t, key);
+    move_to(account, t);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account::Account>(Signer::address_of(account));
+aborts_if StarcoinFramework::Option::is_none(global<Account::Account>(Signer::address_of(account)).key_rotation_capability);
+aborts_if !exists<Account::Account>(
+          StarcoinFramework::Option::borrow<Account::KeyRotationCapability>(
+              global<Account::Account>(Signer::address_of(account))
+              .key_rotation_capability
+          ).account_address);
+aborts_if !Signature::ed25519_validate_pubkey(key);
+aborts_if exists<SharedEd25519PublicKey>(Signer::address_of(account));
+aborts_if len(Authenticator::spec_ed25519_authentication_key(key)) != 32;
+
+ + + +
+ + + +## Function `rotate_key_` + + + +
fun rotate_key_(shared_key: &mut SharedEd25519PublicKey::SharedEd25519PublicKey, new_public_key: vector<u8>)
+
+ + + +
+Implementation + + +
fun rotate_key_(shared_key: &mut SharedEd25519PublicKey, new_public_key: vector<u8>) {
+    // Cryptographic check of public key validity
+    assert!(
+        Signature::ed25519_validate_pubkey(copy new_public_key),
+        Errors::invalid_argument(EMALFORMED_PUBLIC_KEY)
+    );
+    Account::rotate_authentication_key_with_capability(
+        &shared_key.rotation_cap,
+        Authenticator::ed25519_authentication_key(copy new_public_key)
+    );
+    shared_key.key = new_public_key;
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Account::Account>(shared_key.rotation_cap.account_address);
+aborts_if !Signature::ed25519_validate_pubkey(new_public_key);
+aborts_if len(Authenticator::spec_ed25519_authentication_key(new_public_key)) != 32;
+
+ + + +
+ + + +## Function `rotate_key` + +(1) rotate the public key stored account's SharedEd25519PublicKey resource to +new_public_key +(2) rotate the authentication key using the capability stored in the account's +SharedEd25519PublicKey to a new value derived from new_public_key +Aborts if the sender does not have a SharedEd25519PublicKey resource. +Aborts if the length of new_public_key is not 32. + + +
public fun rotate_key(account: &signer, new_public_key: vector<u8>)
+
+ + + +
+Implementation + + +
public fun rotate_key(account: &signer, new_public_key: vector<u8>) acquires SharedEd25519PublicKey {
+    rotate_key_(borrow_global_mut<SharedEd25519PublicKey>(Signer::address_of(account)), new_public_key);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<SharedEd25519PublicKey>(Signer::address_of(account));
+aborts_if !exists<Account::Account>(global<SharedEd25519PublicKey>(Signer::address_of(account)).rotation_cap.account_address);
+aborts_if !Signature::ed25519_validate_pubkey(new_public_key);
+aborts_if len(Authenticator::spec_ed25519_authentication_key(new_public_key)) != 32;
+
+ + + +
+ + + +## Function `key` + +Return the public key stored under addr. +Aborts if addr does not hold a SharedEd25519PublicKey resource. + + +
public fun key(addr: address): vector<u8>
+
+ + + +
+Implementation + + +
public fun key(addr: address): vector<u8> acquires SharedEd25519PublicKey {
+    *&borrow_global<SharedEd25519PublicKey>(addr).key
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<SharedEd25519PublicKey>(addr);
+
+ + + +
+ + + +## Function `exists_at` + +Returns true if addr holds a SharedEd25519PublicKey resource. + + +
public fun exists_at(addr: address): bool
+
+ + + +
+Implementation + + +
public fun exists_at(addr: address): bool {
+    exists<SharedEd25519PublicKey>(addr)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Signature.md b/release/v13/docs/Signature.md new file mode 100644 index 00000000..e819d8cf --- /dev/null +++ b/release/v13/docs/Signature.md @@ -0,0 +1,154 @@ + + + +# Module `0x1::Signature` + +Contains functions for [ed25519](https://en.wikipedia.org/wiki/EdDSA) digital signatures. + + +- [Function `ed25519_validate_pubkey`](#0x1_Signature_ed25519_validate_pubkey) +- [Function `ed25519_verify`](#0x1_Signature_ed25519_verify) +- [Function `native_ecrecover`](#0x1_Signature_native_ecrecover) +- [Function `ecrecover`](#0x1_Signature_ecrecover) +- [Function `secp256k1_verify`](#0x1_Signature_secp256k1_verify) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::EVMAddress;
+use 0x1::Option;
+use 0x1::Vector;
+
+ + + + + +## Function `ed25519_validate_pubkey` + + + +
public fun ed25519_validate_pubkey(public_key: vector<u8>): bool
+
+ + + +
+Implementation + + +
native public fun ed25519_validate_pubkey(public_key: vector<u8>): bool;
+
+ + + +
+ + + +## Function `ed25519_verify` + + + +
public fun ed25519_verify(signature: vector<u8>, public_key: vector<u8>, message: vector<u8>): bool
+
+ + + +
+Implementation + + +
native public fun ed25519_verify(signature: vector<u8>, public_key: vector<u8>, message: vector<u8>): bool;
+
+ + + +
+ + + +## Function `native_ecrecover` + +recover address from ECDSA signature, if recover fail, return an empty vector + + +
fun native_ecrecover(hash: vector<u8>, signature: vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
native fun native_ecrecover(hash: vector<u8>, signature: vector<u8>): vector<u8>;
+
+ + + +
+ + + +## Function `ecrecover` + +recover address from ECDSA signature, if recover fail, return None + + +
public fun ecrecover(hash: vector<u8>, signature: vector<u8>): Option::Option<EVMAddress::EVMAddress>
+
+ + + +
+Implementation + + +
public fun ecrecover(hash: vector<u8>, signature: vector<u8>):Option<EVMAddress>{
+    let bytes = native_ecrecover(hash, signature);
+    if (Vector::is_empty(&bytes)){
+        Option::none<EVMAddress>()
+    }else{
+        Option::some(EVMAddress::new(bytes))
+    }
+}
+
+ + + +
+ + + +## Function `secp256k1_verify` + + + +
public fun secp256k1_verify(signature: vector<u8>, addr: vector<u8>, message: vector<u8>): bool
+
+ + + +
+Implementation + + +
public fun secp256k1_verify(signature: vector<u8>, addr: vector<u8>, message: vector<u8>) : bool{
+  let receover_address_opt:Option<EVMAddress>  = ecrecover(message, signature);
+  let expect_address =  EVMAddress::new(addr);
+  &Option::destroy_some<EVMAddress>(receover_address_opt) == &expect_address
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma intrinsic = true;
+
diff --git a/release/v13/docs/SignedInteger64.md b/release/v13/docs/SignedInteger64.md new file mode 100644 index 00000000..5d4c8fc2 --- /dev/null +++ b/release/v13/docs/SignedInteger64.md @@ -0,0 +1,352 @@ + + + +# Module `0x1::SignedInteger64` + +Implementation of i64. + + +- [Struct `SignedInteger64`](#0x1_SignedInteger64_SignedInteger64) +- [Function `multiply_u64`](#0x1_SignedInteger64_multiply_u64) +- [Function `divide_u64`](#0x1_SignedInteger64_divide_u64) +- [Function `sub_u64`](#0x1_SignedInteger64_sub_u64) +- [Function `add_u64`](#0x1_SignedInteger64_add_u64) +- [Function `create_from_raw_value`](#0x1_SignedInteger64_create_from_raw_value) +- [Function `get_value`](#0x1_SignedInteger64_get_value) +- [Function `is_negative`](#0x1_SignedInteger64_is_negative) +- [Module Specification](#@Module_Specification_0) + + +
+ + + + + +## Struct `SignedInteger64` + +Define a signed integer type with two 32 bits. + + +
struct SignedInteger64 has copy, drop, store
+
+ + + +
+Fields + + +
+
+value: u64 +
+
+ +
+
+is_negative: bool +
+
+ +
+
+ + +
+ + + +## Function `multiply_u64` + +Multiply a u64 integer by a signed integer number. + + +
public fun multiply_u64(num: u64, multiplier: SignedInteger64::SignedInteger64): SignedInteger64::SignedInteger64
+
+ + + +
+Implementation + + +
public fun multiply_u64(num: u64, multiplier: SignedInteger64): SignedInteger64 {
+    let product = multiplier.value * num;
+    SignedInteger64 { value: product, is_negative: multiplier.is_negative }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if multiplier.value * num > max_u64();
+
+ + + +
+ + + +## Function `divide_u64` + +Divide a u64 integer by a signed integer number. + + +
public fun divide_u64(num: u64, divisor: SignedInteger64::SignedInteger64): SignedInteger64::SignedInteger64
+
+ + + +
+Implementation + + +
public fun divide_u64(num: u64, divisor: SignedInteger64): SignedInteger64 {
+    let quotient = num / divisor.value;
+    SignedInteger64 { value: quotient, is_negative: divisor.is_negative }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if divisor.value == 0;
+
+ + + +
+ + + +## Function `sub_u64` + +Sub: num - minus + + +
public fun sub_u64(num: u64, minus: SignedInteger64::SignedInteger64): SignedInteger64::SignedInteger64
+
+ + + +
+Implementation + + +
public fun sub_u64(num: u64, minus: SignedInteger64): SignedInteger64 {
+    if (minus.is_negative) {
+        let result = num + minus.value;
+        SignedInteger64 { value: result, is_negative: false }
+    } else {
+        if (num >= minus.value) {
+            let result = num - minus.value;
+            SignedInteger64 { value: result, is_negative: false }
+        }else {
+            let result = minus.value - num;
+            SignedInteger64 { value: result, is_negative: true }
+        }
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if minus.is_negative && num + minus.value > max_u64();
+
+ + + +
+ + + +## Function `add_u64` + +Add: num + addend + + +
public fun add_u64(num: u64, addend: SignedInteger64::SignedInteger64): SignedInteger64::SignedInteger64
+
+ + + +
+Implementation + + +
public fun add_u64(num: u64, addend: SignedInteger64): SignedInteger64 {
+    if (addend.is_negative) {
+        if (num >= addend.value) {
+            let result = num - addend.value;
+            SignedInteger64 { value: result, is_negative: false }
+        }else {
+            let result = addend.value - num;
+            SignedInteger64 { value: result, is_negative: true }
+        }
+    } else {
+        let result = num + addend.value;
+        SignedInteger64 { value: result, is_negative: false }
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !addend.is_negative && num + addend.value > max_u64();
+
+ + + +
+ + + +## Function `create_from_raw_value` + +Create a signed integer value from a unsigned integer + + +
public fun create_from_raw_value(value: u64, is_negative: bool): SignedInteger64::SignedInteger64
+
+ + + +
+Implementation + + +
public fun create_from_raw_value(value: u64, is_negative: bool): SignedInteger64 {
+    SignedInteger64 { value, is_negative }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == SignedInteger64 { value, is_negative };
+
+ + + +
+ + + +## Function `get_value` + +Get value part of i64 ignore sign part. + + +
public fun get_value(num: SignedInteger64::SignedInteger64): u64
+
+ + + +
+Implementation + + +
public fun get_value(num: SignedInteger64): u64 {
+    num.value
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == num.value;
+
+ + + +
+ + + +## Function `is_negative` + +Check if the given num is negative. + + +
public fun is_negative(num: SignedInteger64::SignedInteger64): bool
+
+ + + +
+Implementation + + +
public fun is_negative(num: SignedInteger64): bool {
+    num.is_negative
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == num.is_negative;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Signer.md b/release/v13/docs/Signer.md new file mode 100644 index 00000000..8f0f1d8c --- /dev/null +++ b/release/v13/docs/Signer.md @@ -0,0 +1,94 @@ + + + +# Module `0x1::Signer` + +Provide access methods for Signer. + + +- [Function `borrow_address`](#0x1_Signer_borrow_address) +- [Function `address_of`](#0x1_Signer_address_of) +- [Module Specification](#@Module_Specification_0) + + +
+ + + + + +## Function `borrow_address` + +Borrows the address of the signer +Conceptually, you can think of the signer as being a resource struct wrapper around an +address +``` +resource struct Signer has key, store { addr: address } +``` +borrow_address borrows this inner field + + +
public fun borrow_address(s: &signer): &address
+
+ + + +
+Implementation + + +
native public fun borrow_address(s: &signer): &address;
+
+ + + +
+ + + +## Function `address_of` + +Copies the address of the signer + + +
public fun address_of(s: &signer): address
+
+ + + +
+Implementation + + +
public fun address_of(s: &signer): address {
+    *borrow_address(s)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures result == address_of(s);
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/SimpleMap.md b/release/v13/docs/SimpleMap.md new file mode 100644 index 00000000..7e47f32f --- /dev/null +++ b/release/v13/docs/SimpleMap.md @@ -0,0 +1,543 @@ + + + +# Module `0x1::SimpleMap` + +This module provides a solution for sorted maps, that is it has the properties that +1) Keys point to Values +2) Each Key must be unique +3) A Key can be found within O(N) time +4) The keys are unsorted. +5) Adds and removals take O(N) time + + +- [Struct `SimpleMap`](#0x1_SimpleMap_SimpleMap) +- [Struct `Element`](#0x1_SimpleMap_Element) +- [Constants](#@Constants_0) +- [Function `length`](#0x1_SimpleMap_length) +- [Function `create`](#0x1_SimpleMap_create) +- [Function `borrow`](#0x1_SimpleMap_borrow) +- [Function `borrow_mut`](#0x1_SimpleMap_borrow_mut) +- [Function `contains_key`](#0x1_SimpleMap_contains_key) +- [Function `destroy_empty`](#0x1_SimpleMap_destroy_empty) +- [Function `add`](#0x1_SimpleMap_add) +- [Function `upsert`](#0x1_SimpleMap_upsert) +- [Function `remove`](#0x1_SimpleMap_remove) +- [Function `find`](#0x1_SimpleMap_find) + + +
use 0x1::Errors;
+use 0x1::Option;
+use 0x1::Vector;
+
+ + + + + +## Struct `SimpleMap` + + + +
struct SimpleMap<Key, Value> has copy, drop, store
+
+ + + +
+Fields + + +
+
+data: vector<SimpleMap::Element<Key, Value>> +
+
+ +
+
+ + +
+ + + +## Struct `Element` + + + +
struct Element<Key, Value> has copy, drop, store
+
+ + + +
+Fields + + +
+
+key: Key +
+
+ +
+
+value: Value +
+
+ +
+
+ + +
+ + + +## Constants + + + + +Map key already exists + + +
const EKEY_ALREADY_EXISTS: u64 = 1;
+
+ + + + + +Map key is not found + + +
const EKEY_NOT_FOUND: u64 = 2;
+
+ + + + + +## Function `length` + + + +
public fun length<Key: store, Value: store>(map: &SimpleMap::SimpleMap<Key, Value>): u64
+
+ + + +
+Implementation + + +
public fun length<Key: store, Value: store>(map: &SimpleMap<Key, Value>): u64 {
+    Vector::length(&map.data)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `create` + + + +
public fun create<Key: store, Value: store>(): SimpleMap::SimpleMap<Key, Value>
+
+ + + +
+Implementation + + +
public fun create<Key: store, Value: store>(): SimpleMap<Key, Value> {
+    SimpleMap {
+        data: Vector::empty(),
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `borrow` + + + +
public fun borrow<Key: store, Value: store>(map: &SimpleMap::SimpleMap<Key, Value>, key: &Key): &Value
+
+ + + +
+Implementation + + +
public fun borrow<Key: store, Value: store>(
+    map: &SimpleMap<Key, Value>,
+    key: &Key,
+): &Value {
+    let maybe_idx = find(map, key);
+    assert!(Option::is_some(&maybe_idx), Errors::invalid_argument(EKEY_NOT_FOUND));
+    let idx = Option::extract(&mut maybe_idx);
+    &Vector::borrow(&map.data, idx).value
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `borrow_mut` + + + +
public fun borrow_mut<Key: store, Value: store>(map: &mut SimpleMap::SimpleMap<Key, Value>, key: &Key): &mut Value
+
+ + + +
+Implementation + + +
public fun borrow_mut<Key: store, Value: store>(
+    map: &mut SimpleMap<Key, Value>,
+    key: &Key,
+): &mut Value {
+    let maybe_idx = find(map, key);
+    assert!(Option::is_some(&maybe_idx), Errors::invalid_argument(EKEY_NOT_FOUND));
+    let idx = Option::extract(&mut maybe_idx);
+    &mut Vector::borrow_mut(&mut map.data, idx).value
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `contains_key` + + + +
public fun contains_key<Key: store, Value: store>(map: &SimpleMap::SimpleMap<Key, Value>, key: &Key): bool
+
+ + + +
+Implementation + + +
public fun contains_key<Key: store, Value: store>(
+    map: &SimpleMap<Key, Value>,
+    key: &Key,
+): bool {
+    let maybe_idx = find(map, key);
+    Option::is_some(&maybe_idx)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `destroy_empty` + + + +
public fun destroy_empty<Key: store, Value: store>(map: SimpleMap::SimpleMap<Key, Value>)
+
+ + + +
+Implementation + + +
public fun destroy_empty<Key: store, Value: store>(map: SimpleMap<Key, Value>) {
+    let SimpleMap { data } = map;
+    Vector::destroy_empty(data);
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `add` + + + +
public fun add<Key: store, Value: store>(map: &mut SimpleMap::SimpleMap<Key, Value>, key: Key, value: Value)
+
+ + + +
+Implementation + + +
public fun add<Key: store, Value: store>(
+    map: &mut SimpleMap<Key, Value>,
+    key: Key,
+    value: Value,
+) {
+    let maybe_idx = find(map, &key);
+    assert!(Option::is_none(&maybe_idx), Errors::invalid_argument(EKEY_ALREADY_EXISTS));
+
+    Vector::push_back(&mut map.data, Element { key, value });
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `upsert` + +Insert key/value pair or update an existing key to a new value + + +
public fun upsert<Key: store, Value: store>(map: &mut SimpleMap::SimpleMap<Key, Value>, key: Key, value: Value): (Option::Option<Key>, Option::Option<Value>)
+
+ + + +
+Implementation + + +
public fun upsert<Key: store, Value: store>(
+    map: &mut SimpleMap<Key, Value>,
+    key: Key,
+    value: Value
+): (Option::Option<Key>, Option::Option<Value>) {
+    let data = &mut map.data;
+    let len = Vector::length(data);
+    let i = 0;
+    while (i < len) {
+        let element = Vector::borrow(data, i);
+        if (&element.key == &key) {
+            Vector::push_back(data, Element { key, value });
+            Vector::swap(data, i, len);
+            let Element { key, value } = Vector::pop_back(data);
+            return (Option::some(key), Option::some(value))
+        };
+        i = i + 1;
+    };
+    Vector::push_back(&mut map.data, Element { key, value });
+    (Option::none(), Option::none())
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify=false;
+
+ + + +
+ + + +## Function `remove` + + + +
public fun remove<Key: store, Value: store>(map: &mut SimpleMap::SimpleMap<Key, Value>, key: &Key): (Key, Value)
+
+ + + +
+Implementation + + +
public fun remove<Key: store, Value: store>(
+    map: &mut SimpleMap<Key, Value>,
+    key: &Key,
+): (Key, Value) {
+    let maybe_idx = find(map, key);
+    assert!(Option::is_some(&maybe_idx), Errors::invalid_argument(EKEY_NOT_FOUND));
+    let placement = Option::extract(&mut maybe_idx);
+    let Element { key, value } = Vector::swap_remove(&mut map.data, placement);
+    (key, value)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `find` + + + +
fun find<Key: store, Value: store>(map: &SimpleMap::SimpleMap<Key, Value>, key: &Key): Option::Option<u64>
+
+ + + +
+Implementation + + +
fun find<Key: store, Value: store>(
+    map: &SimpleMap<Key, Value>,
+    key: &Key,
+): Option::Option<u64> {
+    let leng = Vector::length(&map.data);
+    let i = 0;
+    while (i < leng) {
+        let element = Vector::borrow(&map.data, i);
+        if (&element.key == key) {
+            return Option::some(i)
+        };
+        i = i + 1;
+    };
+    Option::none<u64>()
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify=false;
+
+ + + +
diff --git a/release/v13/docs/StarcoinVerifier.md b/release/v13/docs/StarcoinVerifier.md new file mode 100644 index 00000000..cb7c6a28 --- /dev/null +++ b/release/v13/docs/StarcoinVerifier.md @@ -0,0 +1,715 @@ + + + +# Module `0x1::StarcoinVerifier` + + + +- [Struct `AccountState`](#0x1_StarcoinVerifier_AccountState) +- [Struct `StateProof`](#0x1_StarcoinVerifier_StateProof) +- [Struct `SparseMerkleProof`](#0x1_StarcoinVerifier_SparseMerkleProof) +- [Struct `SMTNode`](#0x1_StarcoinVerifier_SMTNode) +- [Constants](#@Constants_0) +- [Function `bcs_deserialize_account_state`](#0x1_StarcoinVerifier_bcs_deserialize_account_state) +- [Function `new_state_proof`](#0x1_StarcoinVerifier_new_state_proof) +- [Function `new_sparse_merkle_proof`](#0x1_StarcoinVerifier_new_sparse_merkle_proof) +- [Function `new_smt_node`](#0x1_StarcoinVerifier_new_smt_node) +- [Function `empty_smt_node`](#0x1_StarcoinVerifier_empty_smt_node) +- [Function `verify_state_proof`](#0x1_StarcoinVerifier_verify_state_proof) +- [Function `verify_smp`](#0x1_StarcoinVerifier_verify_smp) +- [Function `compute_smp_root_by_path_and_node_hash`](#0x1_StarcoinVerifier_compute_smp_root_by_path_and_node_hash) +- [Function `placeholder`](#0x1_StarcoinVerifier_placeholder) +- [Function `create_literal_hash`](#0x1_StarcoinVerifier_create_literal_hash) +- [Function `hash_key`](#0x1_StarcoinVerifier_hash_key) +- [Function `hash_value`](#0x1_StarcoinVerifier_hash_value) +- [Function `count_common_prefix`](#0x1_StarcoinVerifier_count_common_prefix) +- [Function `get_bit_at_from_msb`](#0x1_StarcoinVerifier_get_bit_at_from_msb) + + +
use 0x1::BCS;
+use 0x1::Hash;
+use 0x1::Option;
+use 0x1::StructuredHash;
+
+ + + + + +## Struct `AccountState` + + + +
struct AccountState has copy, drop, store
+
+ + + +
+Fields + + +
+
+storage_roots: vector<Option::Option<vector<u8>>> +
+
+ +
+
+ + +
+ + + +## Struct `StateProof` + + + +
struct StateProof has copy, drop, store
+
+ + + +
+Fields + + +
+
+account_proof: StarcoinVerifier::SparseMerkleProof +
+
+ + * Account state's proof for global state root. + +
+
+account_state: vector<u8> +
+
+ + * Account state including storage roots. + +
+
+proof: StarcoinVerifier::SparseMerkleProof +
+
+ + * State's proof for account storage root. + +
+
+ + +
+ + + +## Struct `SparseMerkleProof` + + + +
struct SparseMerkleProof has copy, drop, store
+
+ + + +
+Fields + + +
+
+siblings: vector<vector<u8>> +
+
+ +
+
+leaf: StarcoinVerifier::SMTNode +
+
+ +
+
+ + +
+ + + +## Struct `SMTNode` + + + +
struct SMTNode has copy, drop, store
+
+ + + +
+Fields + + +
+
+hash1: vector<u8> +
+
+ +
+
+hash2: vector<u8> +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ACCOUNT_STORAGE_INDEX_RESOURCE: u64 = 1;
+
+ + + + + + + +
const BLOB_HASH_PREFIX: vector<u8> = [66, 108, 111, 98];
+
+ + + + + + + +
const DEFAULT_VALUE: vector<u8> = [];
+
+ + + + + + + +
const ERROR_ACCOUNT_STORAGE_ROOTS: u64 = 101;
+
+ + + + + + + +
const ERROR_LITERAL_HASH_WRONG_LENGTH: u64 = 102;
+
+ + + + + + + +
const HASH_LEN_IN_BITS: u64 = 256;
+
+ + + + + + + +
const SPARSE_MERKLE_INTERNAL_NODE: vector<u8> = [83, 112, 97, 114, 115, 101, 77, 101, 114, 107, 108, 101, 73, 110, 116, 101, 114, 110, 97, 108, 78, 111, 100, 101];
+
+ + + + + + + +
const SPARSE_MERKLE_LEAF_NODE: vector<u8> = [83, 112, 97, 114, 115, 101, 77, 101, 114, 107, 108, 101, 76, 101, 97, 102, 78, 111, 100, 101];
+
+ + + + + + + +
const SPARSE_MERKLE_PLACEHOLDER_HASH_LITERAL: vector<u8> = [83, 80, 65, 82, 83, 69, 95, 77, 69, 82, 75, 76, 69, 95, 80, 76, 65, 67, 69, 72, 79, 76, 68, 69, 82, 95, 72, 65, 83, 72];
+
+ + + + + +## Function `bcs_deserialize_account_state` + + + +
public fun bcs_deserialize_account_state(data: &vector<u8>): StarcoinVerifier::AccountState
+
+ + + +
+Implementation + + +
public fun bcs_deserialize_account_state(data: &vector<u8>): AccountState {
+    let (vec, _) = BCS::deserialize_option_bytes_vector(data, 0);
+    AccountState{
+        storage_roots: vec
+    }
+}
+
+ + + +
+ + + +## Function `new_state_proof` + + + +
public fun new_state_proof(account_proof: StarcoinVerifier::SparseMerkleProof, account_state: vector<u8>, proof: StarcoinVerifier::SparseMerkleProof): StarcoinVerifier::StateProof
+
+ + + +
+Implementation + + +
public fun new_state_proof(account_proof: SparseMerkleProof, account_state: vector<u8>, proof: SparseMerkleProof): StateProof {
+    StateProof{
+        account_proof,
+        account_state,
+        proof,
+    }
+}
+
+ + + +
+ + + +## Function `new_sparse_merkle_proof` + + + +
public fun new_sparse_merkle_proof(siblings: vector<vector<u8>>, leaf: StarcoinVerifier::SMTNode): StarcoinVerifier::SparseMerkleProof
+
+ + + +
+Implementation + + +
public fun new_sparse_merkle_proof(siblings: vector<vector<u8>>, leaf: SMTNode): SparseMerkleProof {
+    SparseMerkleProof{
+        siblings,
+        leaf,
+    }
+}
+
+ + + +
+ + + +## Function `new_smt_node` + + + +
public fun new_smt_node(hash1: vector<u8>, hash2: vector<u8>): StarcoinVerifier::SMTNode
+
+ + + +
+Implementation + + +
public fun new_smt_node(hash1: vector<u8>, hash2: vector<u8>): SMTNode {
+    SMTNode{
+        hash1,
+        hash2,
+    }
+}
+
+ + + +
+ + + +## Function `empty_smt_node` + + + +
public fun empty_smt_node(): StarcoinVerifier::SMTNode
+
+ + + +
+Implementation + + +
public fun empty_smt_node(): SMTNode {
+    SMTNode{
+        hash1: Vector::empty(),
+        hash2: Vector::empty(),
+    }
+}
+
+ + + +
+ + + +## Function `verify_state_proof` + + + +
public fun verify_state_proof(state_proof: &StarcoinVerifier::StateProof, state_root: &vector<u8>, account_address: address, resource_struct_tag: &vector<u8>, state: &vector<u8>): bool
+
+ + + +
+Implementation + + +
public fun verify_state_proof(state_proof: &StateProof, state_root: &vector<u8>,
+                                       account_address: address, resource_struct_tag: &vector<u8>,
+                                       state: &vector<u8>): bool {
+    let accountState: AccountState = bcs_deserialize_account_state(&state_proof.account_state);
+    assert!(Vector::length(&accountState.storage_roots) > ACCOUNT_STORAGE_INDEX_RESOURCE, ERROR_ACCOUNT_STORAGE_ROOTS);
+
+    // First, verify state for storage root.
+    let storageRoot = Option::borrow(Vector::borrow(&accountState.storage_roots, ACCOUNT_STORAGE_INDEX_RESOURCE));
+    let ok: bool = verify_smp(&state_proof.proof.siblings,
+        &state_proof.proof.leaf,
+        storageRoot,
+        resource_struct_tag, // resource struct tag BCS serialized as key
+        state);
+    if (!ok) {
+        return false
+    };
+
+    // Then, verify account state for global state root.
+    ok = verify_smp(&state_proof.account_proof.siblings,
+        &state_proof.account_proof.leaf,
+        state_root,
+        &BCS::to_bytes<address>(&account_address), // account address as key
+        &state_proof.account_state,
+    );
+    ok
+}
+
+ + + +
+ + + +## Function `verify_smp` + +Verify sparse merkle proof by key and value. + + +
public fun verify_smp(sibling_nodes: &vector<vector<u8>>, leaf_data: &StarcoinVerifier::SMTNode, expected_root: &vector<u8>, key: &vector<u8>, value: &vector<u8>): bool
+
+ + + +
+Implementation + + +
public fun verify_smp(sibling_nodes: &vector<vector<u8>>, leaf_data: &SMTNode, expected_root: &vector<u8>, key: &vector<u8>, value: &vector<u8>): bool {
+    let path = hash_key(key);
+    let current_hash: vector<u8>;
+    if (*value == DEFAULT_VALUE) {
+        // Non-membership proof.
+        if (empty_smt_node() == *leaf_data) {
+            current_hash = placeholder();
+        } else {
+            if (*&leaf_data.hash1 == *&path) {
+                return false
+            };
+            if (!(count_common_prefix(&leaf_data.hash1, &path) >= Vector::length(sibling_nodes))) {
+                return false
+            };
+            current_hash = StructuredHash::hash(SPARSE_MERKLE_LEAF_NODE, leaf_data);
+        };
+    } else {
+        // Membership proof.
+        if (empty_smt_node() == *leaf_data) {
+            return false
+        };
+        if (*&leaf_data.hash1 != *&path) {
+            return false
+        };
+        let value_hash = hash_value(value);
+        if (*&leaf_data.hash2 != value_hash) {
+            return false
+        };
+        current_hash = StructuredHash::hash(SPARSE_MERKLE_LEAF_NODE, leaf_data);
+    };
+
+    current_hash = compute_smp_root_by_path_and_node_hash(sibling_nodes, &path, ¤t_hash);
+    current_hash == *expected_root
+}
+
+ + + +
+ + + +## Function `compute_smp_root_by_path_and_node_hash` + + + +
public fun compute_smp_root_by_path_and_node_hash(sibling_nodes: &vector<vector<u8>>, path: &vector<u8>, node_hash: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun compute_smp_root_by_path_and_node_hash(sibling_nodes: &vector<vector<u8>>, path: &vector<u8>, node_hash: &vector<u8>): vector<u8> {
+    let current_hash = *node_hash;
+    let i = 0;
+    let proof_length = Vector::length(sibling_nodes);
+    while (i < proof_length) {
+        let sibling = *Vector::borrow(sibling_nodes, i);
+        let bit = get_bit_at_from_msb(path, proof_length - i - 1);
+        let internal_node = if (bit) {
+            SMTNode{ hash1: sibling, hash2: current_hash }
+        } else {
+            SMTNode{ hash1: current_hash, hash2: sibling }
+        };
+        current_hash = StructuredHash::hash(SPARSE_MERKLE_INTERNAL_NODE, &internal_node);
+        i = i + 1;
+    };
+    current_hash
+}
+
+ + + +
+ + + +## Function `placeholder` + + + +
public fun placeholder(): vector<u8>
+
+ + + +
+Implementation + + +
public fun placeholder(): vector<u8> {
+    create_literal_hash(&SPARSE_MERKLE_PLACEHOLDER_HASH_LITERAL)
+}
+
+ + + +
+ + + +## Function `create_literal_hash` + + + +
public fun create_literal_hash(word: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
public fun create_literal_hash(word: &vector<u8>): vector<u8> {
+    if (Vector::length(word)  <= 32) {
+        let lenZero = 32 - Vector::length(word);
+        let i = 0;
+        let r = *word;
+        while (i < lenZero) {
+            Vector::push_back(&mut r, 0);
+            i = i + 1;
+        };
+        return r
+    };
+    abort ERROR_LITERAL_HASH_WRONG_LENGTH
+}
+
+ + + +
+ + + +## Function `hash_key` + + + +
fun hash_key(key: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
fun hash_key(key: &vector<u8>): vector<u8> {
+    Hash::sha3_256(*key)
+}
+
+ + + +
+ + + +## Function `hash_value` + + + +
fun hash_value(value: &vector<u8>): vector<u8>
+
+ + + +
+Implementation + + +
fun hash_value(value: &vector<u8>): vector<u8> {
+    StructuredHash::hash(BLOB_HASH_PREFIX, value)
+}
+
+ + + +
+ + + +## Function `count_common_prefix` + + + +
fun count_common_prefix(data1: &vector<u8>, data2: &vector<u8>): u64
+
+ + + +
+Implementation + + +
fun count_common_prefix(data1: &vector<u8>, data2: &vector<u8>): u64 {
+    let count = 0;
+    let i = 0;
+    while ( i < Vector::length(data1) * 8) {
+        if (get_bit_at_from_msb(data1, i) == get_bit_at_from_msb(data2, i)) {
+            count = count + 1;
+        } else {
+            break
+        };
+        i = i + 1;
+    };
+    count
+}
+
+ + + +
+ + + +## Function `get_bit_at_from_msb` + + + +
fun get_bit_at_from_msb(data: &vector<u8>, index: u64): bool
+
+ + + +
+Implementation + + +
fun get_bit_at_from_msb(data: &vector<u8>, index: u64): bool {
+    let pos = index / 8;
+    let bit = (7 - index % 8);
+    (*Vector::borrow(data, pos) >> (bit as u8)) & 1u8 != 0
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma opaque;
+
+ + + +
diff --git a/release/v13/docs/StdlibUpgradeScripts.md b/release/v13/docs/StdlibUpgradeScripts.md new file mode 100644 index 00000000..358ba2c9 --- /dev/null +++ b/release/v13/docs/StdlibUpgradeScripts.md @@ -0,0 +1,422 @@ + + + +# Module `0x1::StdlibUpgradeScripts` + +The module for StdlibUpgrade init scripts + + +- [Function `upgrade_from_v2_to_v3`](#0x1_StdlibUpgradeScripts_upgrade_from_v2_to_v3) +- [Function `take_linear_withdraw_capability`](#0x1_StdlibUpgradeScripts_take_linear_withdraw_capability) +- [Function `do_upgrade_from_v5_to_v6`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v5_to_v6) +- [Function `upgrade_from_v5_to_v6`](#0x1_StdlibUpgradeScripts_upgrade_from_v5_to_v6) +- [Function `upgrade_from_v6_to_v7`](#0x1_StdlibUpgradeScripts_upgrade_from_v6_to_v7) +- [Function `do_upgrade_from_v6_to_v7`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v6_to_v7) +- [Function `do_upgrade_from_v6_to_v7_with_language_version`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v6_to_v7_with_language_version) +- [Function `upgrade_from_v7_to_v8`](#0x1_StdlibUpgradeScripts_upgrade_from_v7_to_v8) +- [Function `do_upgrade_from_v7_to_v8`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v7_to_v8) +- [Function `upgrade_from_v11_to_v12`](#0x1_StdlibUpgradeScripts_upgrade_from_v11_to_v12) +- [Function `do_upgrade_from_v11_to_v12`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v11_to_v12) +- [Function `upgrade_from_v12_to_v13`](#0x1_StdlibUpgradeScripts_upgrade_from_v12_to_v13) +- [Function `do_upgrade_from_v12_to_v13`](#0x1_StdlibUpgradeScripts_do_upgrade_from_v12_to_v13) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::Account;
+use 0x1::Block;
+use 0x1::Collection;
+use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::EasyGas;
+use 0x1::FlexiDagConfig;
+use 0x1::GasSchedule;
+use 0x1::GenesisNFT;
+use 0x1::GenesisSignerCapability;
+use 0x1::LanguageVersion;
+use 0x1::Math;
+use 0x1::NFT;
+use 0x1::Offer;
+use 0x1::OnChainConfigDao;
+use 0x1::Oracle;
+use 0x1::STC;
+use 0x1::STCUSDOracle;
+use 0x1::Timestamp;
+use 0x1::Token;
+use 0x1::Treasury;
+use 0x1::TreasuryWithdrawDaoProposal;
+
+ + + + + +## Function `upgrade_from_v2_to_v3` + +Stdlib upgrade script from v2 to v3 + + +
public entry fun upgrade_from_v2_to_v3(account: signer, total_stc_amount: u128)
+
+ + + +
+Implementation + + +
public entry fun upgrade_from_v2_to_v3(account: signer, total_stc_amount: u128 ) {
+    CoreAddresses::assert_genesis_address(&account);
+
+    let withdraw_cap = STC::upgrade_from_v1_to_v2(&account, total_stc_amount);
+
+    let mint_keys = Collection::borrow_collection<LinearTimeMintKey<STC>>(CoreAddresses::ASSOCIATION_ROOT_ADDRESS());
+    let mint_key = Collection::borrow(&mint_keys, 0);
+    let (total, minted, start_time, period) = Token::read_linear_time_key(mint_key);
+    Collection::return_collection(mint_keys);
+
+    let now = Timestamp::now_seconds();
+    let linear_withdraw_cap = Treasury::issue_linear_withdraw_capability(&mut withdraw_cap, total-minted, period - (now - start_time));
+    // Lock the TreasuryWithdrawCapability to Dao
+    TreasuryWithdrawDaoProposal::plugin(&account, withdraw_cap);
+    // Give a LinearWithdrawCapability Offer to association, association need to take the offer, and destroy old LinearTimeMintKey.
+    Offer::create(&account, linear_withdraw_cap, CoreAddresses::ASSOCIATION_ROOT_ADDRESS(), 0);
+}
+
+ + + +
+ + + +## Function `take_linear_withdraw_capability` + +association account should call this script after upgrade from v2 to v3. + + +
public entry fun take_linear_withdraw_capability(signer: signer)
+
+ + + +
+Implementation + + +
public entry fun take_linear_withdraw_capability(signer: signer){
+    let offered = Offer::redeem<LinearWithdrawCapability<STC>>(&signer, CoreAddresses::GENESIS_ADDRESS());
+    Treasury::add_linear_withdraw_capability(&signer, offered);
+    let mint_key = Collection::take<LinearTimeMintKey<STC>>(&signer);
+    Token::destroy_linear_time_key(mint_key);
+}
+
+ + + +
+ + + +## Function `do_upgrade_from_v5_to_v6` + + + +
public fun do_upgrade_from_v5_to_v6(sender: &signer)
+
+ + + +
+Implementation + + +
public fun do_upgrade_from_v5_to_v6(sender: &signer) {
+    CoreAddresses::assert_genesis_address(sender);
+    Oracle::initialize(sender);
+    //register oracle
+    STCUSDOracle::register(sender);
+    NFT::initialize(sender);
+    let merkle_root = x"5969f0e8e19f8769276fb638e6060d5c02e40088f5fde70a6778dd69d659ee6d";
+    let image = b"ipfs://QmSPcvcXgdtHHiVTAAarzTeubk5X3iWymPAoKBfiRFjPMY";
+    GenesisNFT::initialize(sender, merkle_root, 1639u64, image);
+}
+
+ + + +
+ + + +## Function `upgrade_from_v5_to_v6` + + + +
public entry fun upgrade_from_v5_to_v6(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun upgrade_from_v5_to_v6(sender: signer) {
+   Self::do_upgrade_from_v5_to_v6(&sender)
+}
+
+ + + +
+ + + +## Function `upgrade_from_v6_to_v7` + + + +
public entry fun upgrade_from_v6_to_v7(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun upgrade_from_v6_to_v7(sender: signer) {
+    Self::do_upgrade_from_v6_to_v7_with_language_version(&sender, 2);
+}
+
+ + + +
+ + + +## Function `do_upgrade_from_v6_to_v7` + +deprecated, use do_upgrade_from_v6_to_v7_with_language_version. + + +
public fun do_upgrade_from_v6_to_v7(sender: &signer)
+
+ + + +
+Implementation + + +
public fun do_upgrade_from_v6_to_v7(sender: &signer) {
+   do_upgrade_from_v6_to_v7_with_language_version(sender, 2);
+}
+
+ + + +
+ + + +## Function `do_upgrade_from_v6_to_v7_with_language_version` + + + +
public fun do_upgrade_from_v6_to_v7_with_language_version(sender: &signer, language_version: u64)
+
+ + + +
+Implementation + + +
public fun do_upgrade_from_v6_to_v7_with_language_version(sender: &signer, language_version: u64) {
+    // initialize the language version config.
+    Config::publish_new_config(sender, LanguageVersion::new(language_version));
+    // use STC Dao to upgrade onchain's move-language-version configuration.
+    OnChainConfigDao::plugin<STC, LanguageVersion::LanguageVersion>(sender);
+    // upgrade genesis NFT
+    GenesisNFT::upgrade_to_nft_type_info_v2(sender);
+}
+
+ + + +
+ + + +## Function `upgrade_from_v7_to_v8` + + + +
public entry fun upgrade_from_v7_to_v8(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun upgrade_from_v7_to_v8(sender: signer) {
+    do_upgrade_from_v7_to_v8(&sender);
+}
+
+ + + +
+ + + +## Function `do_upgrade_from_v7_to_v8` + + + +
public fun do_upgrade_from_v7_to_v8(sender: &signer)
+
+ + + +
+Implementation + + +
public fun do_upgrade_from_v7_to_v8(sender: &signer) {
+    {
+        let cap = Oracle::extract_signer_cap(sender);
+        GenesisSignerCapability::initialize(sender, cap);
+    };
+
+    {
+        let cap = NFT::extract_signer_cap(sender);
+        Account::destroy_signer_cap(cap);
+    };
+}
+
+ + + +
+ + + +## Function `upgrade_from_v11_to_v12` + + + +
public entry fun upgrade_from_v11_to_v12(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun upgrade_from_v11_to_v12(sender: signer) {
+    do_upgrade_from_v11_to_v12(&sender);
+}
+
+ + + +
+ + + +## Function `do_upgrade_from_v11_to_v12` + + + +
public fun do_upgrade_from_v11_to_v12(sender: &signer)
+
+ + + +
+Implementation + + +
public fun do_upgrade_from_v11_to_v12(sender: &signer) {
+    {
+        GasSchedule::initialize(sender,GasSchedule::new_gas_schedule());
+        let address = @0x8c109349c6bd91411d6bc962e080c4a3;
+        EasyGas::initialize(sender,
+            address,
+            b"STAR",b"STAR",
+            address);
+        Block::checkpoints_init(sender);
+    };
+}
+
+ + + +
+ + + +## Function `upgrade_from_v12_to_v13` + + + +
public entry fun upgrade_from_v12_to_v13(sender: signer)
+
+ + + +
+Implementation + + +
public entry fun upgrade_from_v12_to_v13(sender: signer) {
+    do_upgrade_from_v12_to_v13(&sender);
+}
+
+ + + +
+ + + +## Function `do_upgrade_from_v12_to_v13` + + + +
public fun do_upgrade_from_v12_to_v13(sender: &signer)
+
+ + + +
+Implementation + + +
public fun do_upgrade_from_v12_to_v13(sender: &signer) {
+    {
+        FlexiDagConfig::initialize(sender, u64_max());
+        Block::checkpoints_init(sender);
+    };
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/String.md b/release/v13/docs/String.md new file mode 100644 index 00000000..856a29b2 --- /dev/null +++ b/release/v13/docs/String.md @@ -0,0 +1,530 @@ + + + +# Module `0x1::String` + +The string module defines the String type which represents UTF8 encoded strings. + + +- [Struct `String`](#0x1_String_String) +- [Constants](#@Constants_0) +- [Function `utf8`](#0x1_String_utf8) +- [Function `try_utf8`](#0x1_String_try_utf8) +- [Function `bytes`](#0x1_String_bytes) +- [Function `is_empty`](#0x1_String_is_empty) +- [Function `length`](#0x1_String_length) +- [Function `append`](#0x1_String_append) +- [Function `append_utf8`](#0x1_String_append_utf8) +- [Function `insert`](#0x1_String_insert) +- [Function `sub_string`](#0x1_String_sub_string) +- [Function `index_of`](#0x1_String_index_of) +- [Function `internal_check_utf8`](#0x1_String_internal_check_utf8) +- [Function `internal_is_char_boundary`](#0x1_String_internal_is_char_boundary) +- [Function `internal_sub_string`](#0x1_String_internal_sub_string) +- [Function `internal_index_of`](#0x1_String_internal_index_of) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Option;
+use 0x1::Vector;
+
+ + + + + +## Struct `String` + +A String holds a sequence of bytes which is guaranteed to be in utf8 format. + + +
struct String has copy, drop, store
+
+ + + +
+Fields + + +
+
+bytes: vector<u8> +
+
+ +
+
+ + +
+ + + +## Constants + + + + +An invalid UTF8 encoding. + + +
const EINVALID_UTF8: u64 = 1;
+
+ + + + + +Index out of range. + + +
const EINVALID_INDEX: u64 = 2;
+
+ + + + + +## Function `utf8` + +Creates a new string from a sequence of bytes. Aborts if the bytes do not represent valid utf8. + + +
public fun utf8(bytes: vector<u8>): String::String
+
+ + + +
+Implementation + + +
public fun utf8(bytes: vector<u8>): String {
+    assert!(internal_check_utf8(&bytes), Errors::invalid_state(EINVALID_UTF8));
+    String{bytes}
+}
+
+ + + +
+ + + +## Function `try_utf8` + +Tries to create a new string from a sequence of bytes. + + +
public fun try_utf8(bytes: vector<u8>): Option::Option<String::String>
+
+ + + +
+Implementation + + +
public fun try_utf8(bytes: vector<u8>): Option<String> {
+    if (internal_check_utf8(&bytes)) {
+        Option::some(String{bytes})
+    } else {
+        Option::none()
+    }
+}
+
+ + + +
+ + + +## Function `bytes` + +Returns a reference to the underlying byte vector. + + +
public fun bytes(s: &String::String): &vector<u8>
+
+ + + +
+Implementation + + +
public fun bytes(s: &String): &vector<u8> {
+    &s.bytes
+}
+
+ + + +
+ + + +## Function `is_empty` + +Checks whether this string is empty. + + +
public fun is_empty(s: &String::String): bool
+
+ + + +
+Implementation + + +
public fun is_empty(s: &String): bool {
+    Vector::is_empty(&s.bytes)
+}
+
+ + + +
+ + + +## Function `length` + +Returns the length of this string, in bytes. + + +
public fun length(s: &String::String): u64
+
+ + + +
+Implementation + + +
public fun length(s: &String): u64 {
+    Vector::length(&s.bytes)
+}
+
+ + + +
+ + + +## Function `append` + +Appends a string. + + +
public fun append(s: &mut String::String, r: String::String)
+
+ + + +
+Implementation + + +
public fun append(s: &mut String, r: String) {
+    Vector::append(&mut s.bytes, *&r.bytes)
+}
+
+ + + +
+ + + +## Function `append_utf8` + +Appends bytes which must be in valid utf8 format. + + +
public fun append_utf8(s: &mut String::String, bytes: vector<u8>)
+
+ + + +
+Implementation + + +
public fun append_utf8(s: &mut String, bytes: vector<u8>) {
+    append(s, utf8(bytes))
+}
+
+ + + +
+ + + +## Function `insert` + +Insert the other string at the byte index in given string. The index must be at a valid utf8 char +boundary. + + +
public fun insert(s: &mut String::String, at: u64, o: String::String)
+
+ + + +
+Implementation + + +
public fun insert(s: &mut String, at: u64, o: String) {
+    let bytes = &s.bytes;
+    assert!(at <= Vector::length(bytes) && internal_is_char_boundary(bytes, at), Errors::invalid_state(EINVALID_INDEX));
+    let l = length(s);
+    let front = sub_string(s, 0, at);
+    let end = sub_string(s, at, l);
+    append(&mut front, o);
+    append(&mut front, end);
+    *s = front;
+}
+
+ + + +
+ + + +## Function `sub_string` + +Returns a sub-string using the given byte indices, where i is the first byte position and j is the start +of the first byte not included (or the length of the string). The indices must be at valid utf8 char boundaries, +guaranteeing that the result is valid utf8. + + +
public fun sub_string(s: &String::String, i: u64, j: u64): String::String
+
+ + + +
+Implementation + + +
public fun sub_string(s: &String, i: u64, j: u64): String {
+    let bytes = &s.bytes;
+    let l = Vector::length(bytes);
+    assert!(
+        j <= l && i <= j && internal_is_char_boundary(bytes, i) && internal_is_char_boundary(bytes, j),
+        Errors::invalid_state(EINVALID_INDEX)
+    );
+    String{bytes: internal_sub_string(bytes, i, j)}
+}
+
+ + + +
+ + + +## Function `index_of` + +Computes the index of the first occurrence of a string. Returns length(s) if no occurrence found. + + +
public fun index_of(s: &String::String, r: &String::String): u64
+
+ + + +
+Implementation + + +
public fun index_of(s: &String, r: &String): u64 {
+    internal_index_of(&s.bytes, &r.bytes)
+}
+
+ + + +
+ + + +## Function `internal_check_utf8` + + + +
fun internal_check_utf8(v: &vector<u8>): bool
+
+ + + +
+Implementation + + +
native fun internal_check_utf8(v: &vector<u8>): bool;
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if [abstract] false;
+ensures [abstract] result == spec_internal_check_utf8(v);
+
+ + + +
+ + + +## Function `internal_is_char_boundary` + + + +
fun internal_is_char_boundary(v: &vector<u8>, i: u64): bool
+
+ + + +
+Implementation + + +
native fun internal_is_char_boundary(v: &vector<u8>, i: u64): bool;
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if [abstract] false;
+ensures [abstract] result == spec_internal_is_char_boundary(v, i);
+
+ + + +
+ + + +## Function `internal_sub_string` + + + +
fun internal_sub_string(v: &vector<u8>, i: u64, j: u64): vector<u8>
+
+ + + +
+Implementation + + +
native fun internal_sub_string(v: &vector<u8>, i: u64, j: u64): vector<u8>;
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if [abstract] false;
+ensures [abstract] result == spec_internal_sub_string(v, i, j);
+
+ + + +
+ + + +## Function `internal_index_of` + + + +
fun internal_index_of(v: &vector<u8>, r: &vector<u8>): u64
+
+ + + +
+Implementation + + +
native fun internal_index_of(v: &vector<u8>, r: &vector<u8>): u64;
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if [abstract] false;
+ensures [abstract] result == spec_internal_index_of(v, r);
+
+ + + + + + + +
fun spec_internal_check_utf8(v: vector<u8>): bool;
+
+fun spec_internal_is_char_boundary(v: vector<u8>, i: u64): bool;
+
+fun spec_internal_sub_string(v: vector<u8>, i: u64, j: u64): vector<u8>;
+
+fun spec_internal_index_of(v: vector<u8>, r: vector<u8>): u64;
+
+ + + +
+ + + +## Module Specification + + + + + + +
fun spec_utf8(bytes: vector<u8>): String {
+   String{bytes}
+}
+
diff --git a/release/v13/docs/Table.md b/release/v13/docs/Table.md new file mode 100644 index 00000000..f7c4a3f5 --- /dev/null +++ b/release/v13/docs/Table.md @@ -0,0 +1,831 @@ + + + +# Module `0x1::Table` + +Type of large-scale storage tables. + + +- [Struct `Table`](#0x1_Table_Table) +- [Resource `Box`](#0x1_Table_Box) +- [Constants](#@Constants_0) +- [Function `new`](#0x1_Table_new) +- [Function `destroy_empty`](#0x1_Table_destroy_empty) +- [Function `add`](#0x1_Table_add) +- [Function `borrow`](#0x1_Table_borrow) +- [Function `borrow_with_default`](#0x1_Table_borrow_with_default) +- [Function `borrow_mut`](#0x1_Table_borrow_mut) +- [Function `length`](#0x1_Table_length) +- [Function `empty`](#0x1_Table_empty) +- [Function `borrow_mut_with_default`](#0x1_Table_borrow_mut_with_default) +- [Function `upsert`](#0x1_Table_upsert) +- [Function `remove`](#0x1_Table_remove) +- [Function `contains`](#0x1_Table_contains) +- [Function `new_table_handle`](#0x1_Table_new_table_handle) +- [Function `add_box`](#0x1_Table_add_box) +- [Function `borrow_box`](#0x1_Table_borrow_box) +- [Function `borrow_box_mut`](#0x1_Table_borrow_box_mut) +- [Function `contains_box`](#0x1_Table_contains_box) +- [Function `remove_box`](#0x1_Table_remove_box) +- [Function `destroy_empty_box`](#0x1_Table_destroy_empty_box) +- [Function `drop_unchecked_box`](#0x1_Table_drop_unchecked_box) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+
+ + + + + +## Struct `Table` + +Type of tables + + +
struct Table<K: copy, drop, V> has store
+
+ + + +
+Fields + + +
+
+handle: address +
+
+ +
+
+length: u64 +
+
+ +
+
+ + +
+ +
+Specification + + + +
pragma intrinsic = map,
+map_new = new,
+map_destroy_empty = destroy_empty,
+map_len = length,
+map_is_empty = empty,
+map_has_key = contains,
+map_add_no_override = add,
+map_del_must_exist = remove,
+map_borrow = borrow,
+map_borrow_mut = borrow_mut,
+map_spec_get = spec_get,
+map_spec_set = spec_set,
+map_spec_del = spec_remove,
+map_spec_len = spec_len,
+map_spec_has_key = spec_contains;
+
+ + + +
+ + + +## Resource `Box` + +Wrapper for values. Required for making values appear as resources in the implementation. + + +
struct Box<V> has drop, store, key
+
+ + + +
+Fields + + +
+
+val: V +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const EALREADY_EXISTS: u64 = 100;
+
+ + + + + + + +
const ENOT_EMPTY: u64 = 102;
+
+ + + + + + + +
const ENOT_FOUND: u64 = 101;
+
+ + + + + +## Function `new` + +Create a new Table. + + +
public fun new<K: copy, drop, V: store>(): Table::Table<K, V>
+
+ + + +
+Implementation + + +
public fun new<K: copy + drop, V: store>(): Table<K, V> {
+    Table{
+        handle: new_table_handle<K, V>(),
+        length: 0,
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `destroy_empty` + +Destroy a table. The table must be empty to succeed. + + +
public fun destroy_empty<K: copy, drop, V>(table: Table::Table<K, V>)
+
+ + + +
+Implementation + + +
public fun destroy_empty<K: copy + drop, V>(table: Table<K, V>) {
+    assert!(table.length == 0, Errors::invalid_state(ENOT_EMPTY));
+    destroy_empty_box<K, V, Box<V>>(&table);
+    drop_unchecked_box<K, V, Box<V>>(table)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `add` + +Add a new entry to the table. Aborts if an entry for this +key already exists. The entry itself is not stored in the +table, and cannot be discovered from it. + + +
public fun add<K: copy, drop, V>(table: &mut Table::Table<K, V>, key: K, val: V)
+
+ + + +
+Implementation + + +
public fun add<K: copy + drop, V>(table: &mut Table<K, V>, key: K, val: V) {
+    add_box<K, V, Box<V>>(table, key, Box{val});
+    table.length = table.length + 1
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `borrow` + +Acquire an immutable reference to the value which key maps to. +Aborts if there is no entry for key. + + +
public fun borrow<K: copy, drop, V>(table: &Table::Table<K, V>, key: K): &V
+
+ + + +
+Implementation + + +
public fun borrow<K: copy + drop, V>(table: &Table<K, V>, key: K): &V {
+    &borrow_box<K, V, Box<V>>(table, key).val
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `borrow_with_default` + +Acquire an immutable reference to the value which key maps to. +Returns specified default value if there is no entry for key. + + +
public fun borrow_with_default<K: copy, drop, V>(table: &Table::Table<K, V>, key: K, default: &V): &V
+
+ + + +
+Implementation + + +
public fun borrow_with_default<K: copy + drop, V>(table: &Table<K, V>, key: K, default: &V): &V {
+    if (!contains(table, copy key)) {
+        default
+    } else {
+        borrow(table, copy key)
+    }
+}
+
+ + + +
+ + + +## Function `borrow_mut` + +Acquire a mutable reference to the value which key maps to. +Aborts if there is no entry for key. + + +
public fun borrow_mut<K: copy, drop, V>(table: &mut Table::Table<K, V>, key: K): &mut V
+
+ + + +
+Implementation + + +
public fun borrow_mut<K: copy + drop, V>(table: &mut Table<K, V>, key: K): &mut V {
+    &mut borrow_box_mut<K, V, Box<V>>(table, key).val
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `length` + +Returns the length of the table, i.e. the number of entries. + + +
public fun length<K: copy, drop, V>(table: &Table::Table<K, V>): u64
+
+ + + +
+Implementation + + +
public fun length<K: copy + drop, V>(table: &Table<K, V>): u64 {
+    table.length
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `empty` + +Returns true if this table is empty. + + +
public fun empty<K: copy, drop, V>(table: &Table::Table<K, V>): bool
+
+ + + +
+Implementation + + +
public fun empty<K: copy + drop, V>(table: &Table<K, V>): bool {
+    table.length == 0
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `borrow_mut_with_default` + +Acquire a mutable reference to the value which key maps to. +Insert the pair (key, default) first if there is no entry for key. + + +
public fun borrow_mut_with_default<K: copy, drop, V: drop>(table: &mut Table::Table<K, V>, key: K, default: V): &mut V
+
+ + + +
+Implementation + + +
public fun borrow_mut_with_default<K: copy + drop, V: drop>(table: &mut Table<K, V>, key: K, default: V): &mut V {
+    if (!contains(table, copy key)) {
+        add(table, copy key, default)
+    };
+    borrow_mut(table, key)
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque, verify=false;
+aborts_if false;
+
+ + + +
+ + + +## Function `upsert` + +Insert the pair (key, value) if there is no entry for key. +update the value of the entry for key to value otherwise + + +
public fun upsert<K: copy, drop, V: drop>(table: &mut Table::Table<K, V>, key: K, value: V)
+
+ + + +
+Implementation + + +
public fun upsert<K: copy + drop, V: drop>(table: &mut Table<K, V>, key: K, value: V) {
+    if (!contains(table, copy key)) {
+        add(table, copy key, value)
+    } else {
+        let ref = borrow_mut(table, key);
+        *ref = value;
+    };
+}
+
+ + + +
+ + + +## Function `remove` + +Remove from table and return the value which key maps to. +Aborts if there is no entry for key. + + +
public fun remove<K: copy, drop, V>(table: &mut Table::Table<K, V>, key: K): V
+
+ + + +
+Implementation + + +
public fun remove<K: copy + drop, V>(table: &mut Table<K, V>, key: K): V {
+    let Box{val} = remove_box<K, V, Box<V>>(table, key);
+    table.length = table.length - 1;
+    val
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `contains` + +Returns true iff table contains an entry for key. + + +
public fun contains<K: copy, drop, V>(table: &Table::Table<K, V>, key: K): bool
+
+ + + +
+Implementation + + +
public fun contains<K: copy + drop, V>(table: &Table<K, V>, key: K): bool {
+    contains_box<K, V, Box<V>>(table, key)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic;
+
+ + + +
+ + + +## Function `new_table_handle` + + + +
fun new_table_handle<K, V>(): address
+
+ + + +
+Implementation + + +
native fun new_table_handle<K, V>(): address;
+
+ + + +
+ + + +## Function `add_box` + + + +
fun add_box<K: copy, drop, V, B>(table: &mut Table::Table<K, V>, key: K, val: Table::Box<V>)
+
+ + + +
+Implementation + + +
native fun add_box<K: copy + drop, V, B>(table: &mut Table<K, V>, key: K, val: Box<V>);
+
+ + + +
+ + + +## Function `borrow_box` + + + +
fun borrow_box<K: copy, drop, V, B>(table: &Table::Table<K, V>, key: K): &Table::Box<V>
+
+ + + +
+Implementation + + +
native fun borrow_box<K: copy + drop, V, B>(table: &Table<K, V>, key: K): &Box<V>;
+
+ + + +
+ + + +## Function `borrow_box_mut` + + + +
fun borrow_box_mut<K: copy, drop, V, B>(table: &mut Table::Table<K, V>, key: K): &mut Table::Box<V>
+
+ + + +
+Implementation + + +
native fun borrow_box_mut<K: copy + drop, V, B>(table: &mut Table<K, V>, key: K): &mut Box<V>;
+
+ + + +
+ + + +## Function `contains_box` + + + +
fun contains_box<K: copy, drop, V, B>(table: &Table::Table<K, V>, key: K): bool
+
+ + + +
+Implementation + + +
native fun contains_box<K: copy + drop, V, B>(table: &Table<K, V>, key: K): bool;
+
+ + + +
+ + + +## Function `remove_box` + + + +
fun remove_box<K: copy, drop, V, B>(table: &mut Table::Table<K, V>, key: K): Table::Box<V>
+
+ + + +
+Implementation + + +
native fun remove_box<K: copy + drop, V, B>(table: &mut Table<K, V>, key: K): Box<V>;
+
+ + + +
+ + + +## Function `destroy_empty_box` + + + +
fun destroy_empty_box<K: copy, drop, V, B>(table: &Table::Table<K, V>)
+
+ + + +
+Implementation + + +
native fun destroy_empty_box<K: copy + drop, V, B>(table: &Table<K, V>);
+
+ + + +
+ + + +## Function `drop_unchecked_box` + + + +
fun drop_unchecked_box<K: copy, drop, V, B>(table: Table::Table<K, V>)
+
+ + + +
+Implementation + + +
native fun drop_unchecked_box<K: copy + drop, V, B>(table: Table<K, V>);
+
+ + + +
+ + + +## Module Specification + + + + + + +
native fun spec_len<K, V>(t: Table<K, V>): num;
+
+ + + + + + + +
native fun spec_contains<K, V>(t: Table<K, V>, k: K): bool;
+
+ + + + + + + +
native fun spec_set<K, V>(t: Table<K, V>, k: K, v: V): Table<K, V>;
+
+ + + + + + + +
native fun spec_remove<K, V>(t: Table<K, V>, k: K): Table<K, V>;
+
+ + + + + + + +
native fun spec_get<K, V>(t: Table<K, V>, k: K): V;
+
diff --git a/release/v13/docs/Timestamp.md b/release/v13/docs/Timestamp.md new file mode 100644 index 00000000..a4af9aaa --- /dev/null +++ b/release/v13/docs/Timestamp.md @@ -0,0 +1,461 @@ + + + +# Module `0x1::Timestamp` + +The module implements onchain timestamp oracle. +Timestamp is updated on each block. It always steps forward, and never come backward. + + +- [Resource `CurrentTimeMilliseconds`](#0x1_Timestamp_CurrentTimeMilliseconds) +- [Resource `TimeHasStarted`](#0x1_Timestamp_TimeHasStarted) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_Timestamp_initialize) +- [Function `update_global_time`](#0x1_Timestamp_update_global_time) +- [Function `now_seconds`](#0x1_Timestamp_now_seconds) +- [Function `now_milliseconds`](#0x1_Timestamp_now_milliseconds) +- [Function `set_time_has_started`](#0x1_Timestamp_set_time_has_started) +- [Function `is_genesis`](#0x1_Timestamp_is_genesis) +- [Function `assert_genesis`](#0x1_Timestamp_assert_genesis) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::CoreAddresses;
+use 0x1::Errors;
+
+ + + + + +## Resource `CurrentTimeMilliseconds` + + + +
struct CurrentTimeMilliseconds has key
+
+ + + +
+Fields + + +
+
+milliseconds: u64 +
+
+ +
+
+ + +
+ + + +## Resource `TimeHasStarted` + +A singleton resource used to determine whether time has started. This +is called at the end of genesis. + + +
struct TimeHasStarted has key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const EINVALID_TIMESTAMP: u64 = 14;
+
+ + + + + + + +
const ENOT_GENESIS: u64 = 12;
+
+ + + + + + + +
const ENOT_INITIALIZED: u64 = 101;
+
+ + + + + +Conversion factor between seconds and milliseconds + + +
const MILLI_CONVERSION_FACTOR: u64 = 1000;
+
+ + + + + +## Function `initialize` + + + +
public fun initialize(account: &signer, genesis_timestamp: u64)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, genesis_timestamp: u64) {
+    // Only callable by the Genesis address
+    CoreAddresses::assert_genesis_address(account);
+    let milli_timer = CurrentTimeMilliseconds {milliseconds: genesis_timestamp};
+    move_to<CurrentTimeMilliseconds>(account, milli_timer);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<CurrentTimeMilliseconds>(Signer::address_of(account));
+ensures exists<CurrentTimeMilliseconds>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `update_global_time` + + + +
public fun update_global_time(account: &signer, timestamp: u64)
+
+ + + +
+Implementation + + +
public fun update_global_time(account: &signer, timestamp: u64) acquires CurrentTimeMilliseconds {
+    CoreAddresses::assert_genesis_address(account);
+    //Do not update time before time start.
+    let global_milli_timer = borrow_global_mut<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+    assert!(timestamp > global_milli_timer.milliseconds, Errors::invalid_argument(EINVALID_TIMESTAMP));
+    global_milli_timer.milliseconds = timestamp;
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if timestamp <= global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds;
+ensures global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds == timestamp;
+
+ + + +
+ + + +## Function `now_seconds` + + + +
public fun now_seconds(): u64
+
+ + + +
+Implementation + + +
public fun now_seconds(): u64 acquires CurrentTimeMilliseconds {
+    now_milliseconds() / MILLI_CONVERSION_FACTOR
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+ensures result == now_milliseconds() / MILLI_CONVERSION_FACTOR;
+
+ + + + + + + +
fun spec_now_seconds(): u64 {
+   global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds / MILLI_CONVERSION_FACTOR
+}
+
+ + + +
+ + + +## Function `now_milliseconds` + + + +
public fun now_milliseconds(): u64
+
+ + + +
+Implementation + + +
public fun now_milliseconds(): u64 acquires CurrentTimeMilliseconds {
+    borrow_global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+ensures result == global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds;
+
+ + + + + + + +
fun spec_now_millseconds(): u64 {
+   global<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()).milliseconds
+}
+
+ + + +
+ + + +## Function `set_time_has_started` + +Marks that time has started and genesis has finished. This can only be called from genesis. + + +
public fun set_time_has_started(account: &signer)
+
+ + + +
+Implementation + + +
public fun set_time_has_started(account: &signer) {
+    CoreAddresses::assert_genesis_address(account);
+
+    // Current time must have been initialized.
+    assert!(
+        exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS()),
+        Errors::invalid_state(ENOT_INITIALIZED)
+    );
+    move_to(account, TimeHasStarted{});
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<CurrentTimeMilliseconds>(Signer::address_of(account));
+aborts_if exists<TimeHasStarted>(Signer::address_of(account));
+ensures exists<TimeHasStarted>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `is_genesis` + +Helper function to determine if the blockchain is in genesis state. + + +
public fun is_genesis(): bool
+
+ + + +
+Implementation + + +
public fun is_genesis(): bool {
+    !exists<TimeHasStarted>(CoreAddresses::GENESIS_ADDRESS())
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == !exists<TimeHasStarted>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `assert_genesis` + +Helper function to assert genesis state. + + +
public fun assert_genesis()
+
+ + + +
+Implementation + + +
public fun assert_genesis() {
+    assert!(is_genesis(), Errors::invalid_state(ENOT_GENESIS));
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+include AbortsIfNotGenesis;
+
+ + +Helper schema to specify that a function aborts if not in genesis. + + + + + +
schema AbortsIfNotGenesis {
+    aborts_if !is_genesis();
+}
+
+ + + + + + + +
schema AbortsIfTimestampNotExists {
+    aborts_if !exists<CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Token.md b/release/v13/docs/Token.md new file mode 100644 index 00000000..a32c5fb7 --- /dev/null +++ b/release/v13/docs/Token.md @@ -0,0 +1,1845 @@ + + + +# Module `0x1::Token` + +Token implementation of Starcoin. + + +- [Struct `Token`](#0x1_Token_Token) +- [Struct `TokenCode`](#0x1_Token_TokenCode) +- [Resource `MintCapability`](#0x1_Token_MintCapability) +- [Resource `FixedTimeMintKey`](#0x1_Token_FixedTimeMintKey) +- [Resource `LinearTimeMintKey`](#0x1_Token_LinearTimeMintKey) +- [Resource `BurnCapability`](#0x1_Token_BurnCapability) +- [Struct `MintEvent`](#0x1_Token_MintEvent) +- [Struct `BurnEvent`](#0x1_Token_BurnEvent) +- [Resource `TokenInfo`](#0x1_Token_TokenInfo) +- [Constants](#@Constants_0) +- [Function `register_token`](#0x1_Token_register_token) +- [Function `remove_mint_capability`](#0x1_Token_remove_mint_capability) +- [Function `add_mint_capability`](#0x1_Token_add_mint_capability) +- [Function `destroy_mint_capability`](#0x1_Token_destroy_mint_capability) +- [Function `remove_burn_capability`](#0x1_Token_remove_burn_capability) +- [Function `add_burn_capability`](#0x1_Token_add_burn_capability) +- [Function `destroy_burn_capability`](#0x1_Token_destroy_burn_capability) +- [Function `mint`](#0x1_Token_mint) +- [Function `mint_with_capability`](#0x1_Token_mint_with_capability) +- [Function `do_mint`](#0x1_Token_do_mint) +- [Function `issue_fixed_mint_key`](#0x1_Token_issue_fixed_mint_key) +- [Function `issue_linear_mint_key`](#0x1_Token_issue_linear_mint_key) +- [Function `destroy_linear_time_key`](#0x1_Token_destroy_linear_time_key) +- [Function `read_linear_time_key`](#0x1_Token_read_linear_time_key) +- [Function `burn`](#0x1_Token_burn) +- [Function `burn_with_capability`](#0x1_Token_burn_with_capability) +- [Function `zero`](#0x1_Token_zero) +- [Function `value`](#0x1_Token_value) +- [Function `split`](#0x1_Token_split) +- [Function `withdraw`](#0x1_Token_withdraw) +- [Function `join`](#0x1_Token_join) +- [Function `deposit`](#0x1_Token_deposit) +- [Function `destroy_zero`](#0x1_Token_destroy_zero) +- [Function `scaling_factor`](#0x1_Token_scaling_factor) +- [Function `market_cap`](#0x1_Token_market_cap) +- [Function `is_registered_in`](#0x1_Token_is_registered_in) +- [Function `is_same_token`](#0x1_Token_is_same_token) +- [Function `token_address`](#0x1_Token_token_address) +- [Function `token_code`](#0x1_Token_token_code) +- [Function `type_of`](#0x1_Token_type_of) +- [Function `name_of`](#0x1_Token_name_of) +- [Function `name_of_token`](#0x1_Token_name_of_token) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Math;
+use 0x1::Signer;
+
+ + + + + +## Struct `Token` + +The token has a TokenType color that tells us what token the +value inside represents. + + +
struct Token<TokenType> has store
+
+ + + +
+Fields + + +
+
+value: u128 +
+
+ +
+
+ + +
+ + + +## Struct `TokenCode` + +Token Code which identify a unique Token. + + +
struct TokenCode has copy, drop, store
+
+ + + +
+Fields + + +
+
+addr: address +
+
+ address who define the module contains the Token Type. +
+
+module_name: vector<u8> +
+
+ module which contains the Token Type. +
+
+name: vector<u8> +
+
+ name of the token. may nested if the token is an instantiated generic token type. +
+
+ + +
+ + + +## Resource `MintCapability` + +A minting capability allows tokens of type TokenType to be minted + + +
struct MintCapability<TokenType> has store, key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Resource `FixedTimeMintKey` + +A fixed time mint key which can mint token until global time > end_time + + +
struct FixedTimeMintKey<TokenType> has store, key
+
+ + + +
+Fields + + +
+
+total: u128 +
+
+ +
+
+end_time: u64 +
+
+ +
+
+ + +
+ + + +## Resource `LinearTimeMintKey` + +A linear time mint key which can mint token in a period by time-based linear release. + + +
struct LinearTimeMintKey<TokenType> has store, key
+
+ + + +
+Fields + + +
+
+total: u128 +
+
+ +
+
+minted: u128 +
+
+ +
+
+start_time: u64 +
+
+ +
+
+period: u64 +
+
+ +
+
+ + +
+ + + +## Resource `BurnCapability` + +A burn capability allows tokens of type TokenType to be burned. + + +
struct BurnCapability<TokenType> has store, key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Struct `MintEvent` + +Event emitted when token minted. + + +
struct MintEvent has drop, store
+
+ + + +
+Fields + + +
+
+amount: u128 +
+
+ funds added to the system +
+
+token_code: Token::TokenCode +
+
+ full info of Token. +
+
+ + +
+ + + +## Struct `BurnEvent` + +Event emitted when token burned. + + +
struct BurnEvent has drop, store
+
+ + + +
+Fields + + +
+
+amount: u128 +
+
+ funds removed from the system +
+
+token_code: Token::TokenCode +
+
+ full info of Token +
+
+ + +
+ + + +## Resource `TokenInfo` + +Token information. + + +
struct TokenInfo<TokenType> has key
+
+ + + +
+Fields + + +
+
+total_value: u128 +
+
+ The total value for the token represented by + TokenType. Mutable. +
+
+scaling_factor: u128 +
+
+ The scaling factor for the coin (i.e. the amount to divide by + to get to the human-readable representation for this currency). + e.g. 10^6 for Coin1 +
+
+mint_events: Event::EventHandle<Token::MintEvent> +
+
+ event stream for minting +
+
+burn_events: Event::EventHandle<Token::BurnEvent> +
+
+ event stream for burning +
+
+ + +
+ + + +## Constants + + + + + + +
const EAMOUNT_EXCEEDS_COIN_VALUE: u64 = 102;
+
+ + + + + + + +
const EDEPRECATED_FUNCTION: u64 = 19;
+
+ + + + + + + +
const EDESTROY_KEY_NOT_EMPTY: u64 = 104;
+
+ + + + + + + +
const EDESTROY_TOKEN_NON_ZERO: u64 = 16;
+
+ + + + + + + +
const EEMPTY_KEY: u64 = 106;
+
+ + + + + + + +
const EINVALID_ARGUMENT: u64 = 18;
+
+ + + + + + + +
const EMINT_AMOUNT_EQUAL_ZERO: u64 = 109;
+
+ + + + + + + +
const EMINT_KEY_TIME_LIMIT: u64 = 103;
+
+ + + + + + + +
const EPERIOD_NEW: u64 = 108;
+
+ + + + + + + +
const EPRECISION_TOO_LARGE: u64 = 105;
+
+ + + + + + + +
const ESPLIT: u64 = 107;
+
+ + + + + +Token register's address should same as TokenType's address. + + +
const ETOKEN_REGISTER: u64 = 101;
+
+ + + + + +2^128 < 10**39 + + +
const MAX_PRECISION: u8 = 38;
+
+ + + + + +## Function `register_token` + +Register the type TokenType as a Token and got MintCapability and BurnCapability. + + +
public fun register_token<TokenType: store>(account: &signer, precision: u8)
+
+ + + +
+Implementation + + +
public fun register_token<TokenType: store>(
+    account: &signer,
+    precision: u8,
+) {
+    assert!(precision <= MAX_PRECISION, Errors::invalid_argument(EPRECISION_TOO_LARGE));
+    let scaling_factor = Math::pow(10, (precision as u64));
+    let token_address = token_address<TokenType>();
+    assert!(Signer::address_of(account) == token_address, Errors::requires_address(ETOKEN_REGISTER));
+    move_to(account, MintCapability<TokenType> {});
+    move_to(account, BurnCapability<TokenType> {});
+    move_to(
+        account,
+        TokenInfo<TokenType> {
+            total_value: 0,
+            scaling_factor,
+            mint_events: Event::new_event_handle<MintEvent>(account),
+            burn_events: Event::new_event_handle<BurnEvent>(account),
+        },
+    );
+}
+
+ + + +
+ +
+Specification + + + +
include RegisterTokenAbortsIf<TokenType>;
+include RegisterTokenEnsures<TokenType>;
+
+ + + + + + + +
schema RegisterTokenAbortsIf<TokenType> {
+    precision: u8;
+    account: signer;
+    aborts_if precision > MAX_PRECISION;
+    aborts_if Signer::address_of(account) != SPEC_TOKEN_TEST_ADDRESS();
+    aborts_if exists<MintCapability<TokenType>>(Signer::address_of(account));
+    aborts_if exists<BurnCapability<TokenType>>(Signer::address_of(account));
+    aborts_if exists<TokenInfo<TokenType>>(Signer::address_of(account));
+}
+
+ + + + + + + +
schema RegisterTokenEnsures<TokenType> {
+    account: signer;
+    ensures exists<MintCapability<TokenType>>(Signer::address_of(account));
+    ensures exists<BurnCapability<TokenType>>(Signer::address_of(account));
+    ensures exists<TokenInfo<TokenType>>(Signer::address_of(account));
+}
+
+ + + +
+ + + +## Function `remove_mint_capability` + +Remove mint capability from signer. + + +
public fun remove_mint_capability<TokenType: store>(signer: &signer): Token::MintCapability<TokenType>
+
+ + + +
+Implementation + + +
public fun remove_mint_capability<TokenType: store>(signer: &signer): MintCapability<TokenType>
+acquires MintCapability {
+    move_from<MintCapability<TokenType>>(Signer::address_of(signer))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<MintCapability<TokenType>>(Signer::address_of(signer));
+ensures !exists<MintCapability<TokenType>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `add_mint_capability` + +Add mint capability to signer. + + +
public fun add_mint_capability<TokenType: store>(signer: &signer, cap: Token::MintCapability<TokenType>)
+
+ + + +
+Implementation + + +
public fun add_mint_capability<TokenType: store>(signer: &signer, cap: MintCapability<TokenType>) {
+    move_to(signer, cap)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if exists<MintCapability<TokenType>>(Signer::address_of(signer));
+ensures exists<MintCapability<TokenType>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `destroy_mint_capability` + +Destroy the given mint capability. + + +
public fun destroy_mint_capability<TokenType: store>(cap: Token::MintCapability<TokenType>)
+
+ + + +
+Implementation + + +
public fun destroy_mint_capability<TokenType: store>(cap: MintCapability<TokenType>) {
+    let MintCapability<TokenType> {} = cap;
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Function `remove_burn_capability` + +remove the token burn capability from signer. + + +
public fun remove_burn_capability<TokenType: store>(signer: &signer): Token::BurnCapability<TokenType>
+
+ + + +
+Implementation + + +
public fun remove_burn_capability<TokenType: store>(signer: &signer): BurnCapability<TokenType>
+acquires BurnCapability {
+    move_from<BurnCapability<TokenType>>(Signer::address_of(signer))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<BurnCapability<TokenType>>(Signer::address_of(signer));
+ensures !exists<BurnCapability<TokenType>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `add_burn_capability` + +Add token burn capability to signer. + + +
public fun add_burn_capability<TokenType: store>(signer: &signer, cap: Token::BurnCapability<TokenType>)
+
+ + + +
+Implementation + + +
public fun add_burn_capability<TokenType: store>(signer: &signer, cap: BurnCapability<TokenType>) {
+    move_to(signer, cap)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if exists<BurnCapability<TokenType>>(Signer::address_of(signer));
+ensures exists<BurnCapability<TokenType>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `destroy_burn_capability` + +Destroy the given burn capability. + + +
public fun destroy_burn_capability<TokenType: store>(cap: Token::BurnCapability<TokenType>)
+
+ + + +
+Implementation + + +
public fun destroy_burn_capability<TokenType: store>(cap: BurnCapability<TokenType>) {
+    let BurnCapability<TokenType> {} = cap;
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Function `mint` + +Return amount tokens. +Fails if the sender does not have a published MintCapability. + + +
public fun mint<TokenType: store>(account: &signer, amount: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun mint<TokenType: store>(account: &signer, amount: u128): Token<TokenType>
+acquires TokenInfo, MintCapability {
+    mint_with_capability(
+        borrow_global<MintCapability<TokenType>>(Signer::address_of(account)),
+        amount,
+    )
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if spec_abstract_total_value<TokenType>() + amount > MAX_U128;
+aborts_if !exists<MintCapability<TokenType>>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `mint_with_capability` + +Mint a new Token::Token worth amount. +The caller must have a reference to a MintCapability. +Only the Association account can acquire such a reference, and it can do so only via +borrow_sender_mint_capability + + +
public fun mint_with_capability<TokenType: store>(_capability: &Token::MintCapability<TokenType>, amount: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun mint_with_capability<TokenType: store>(
+    _capability: &MintCapability<TokenType>,
+    amount: u128,
+): Token<TokenType> acquires TokenInfo {
+    do_mint(amount)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if spec_abstract_total_value<TokenType>() + amount > MAX_U128;
+ensures spec_abstract_total_value<TokenType>() ==
+        old(global<TokenInfo<TokenType>>(SPEC_TOKEN_TEST_ADDRESS()).total_value) + amount;
+
+ + + +
+ + + +## Function `do_mint` + + + +
fun do_mint<TokenType: store>(amount: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
fun do_mint<TokenType: store>(amount: u128): Token<TokenType> acquires TokenInfo {
+    // update market cap resource to reflect minting
+    let (token_address, module_name, token_name) = name_of_token<TokenType>();
+    let info = borrow_global_mut<TokenInfo<TokenType>>(token_address);
+    info.total_value = info.total_value + amount;
+    Event::emit_event(
+        &mut info.mint_events,
+        MintEvent {
+            amount,
+            token_code: TokenCode { addr: token_address, module_name, name: token_name },
+        },
+    );
+    Token<TokenType> { value: amount }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<TokenInfo<TokenType>>(SPEC_TOKEN_TEST_ADDRESS());
+aborts_if spec_abstract_total_value<TokenType>() + amount > MAX_U128;
+
+ + + +
+ + + +## Function `issue_fixed_mint_key` + +Deprecated since @v3 +Issue a FixedTimeMintKey with given MintCapability. + + +
public fun issue_fixed_mint_key<TokenType: store>(_capability: &Token::MintCapability<TokenType>, _amount: u128, _period: u64): Token::FixedTimeMintKey<TokenType>
+
+ + + +
+Implementation + + +
public fun issue_fixed_mint_key<TokenType: store>(
+    _capability: &MintCapability<TokenType>,
+    _amount: u128,
+    _period: u64,
+): FixedTimeMintKey<TokenType> {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if true;
+
+ + + +
+ + + +## Function `issue_linear_mint_key` + +Deprecated since @v3 +Issue a LinearTimeMintKey with given MintCapability. + + +
public fun issue_linear_mint_key<TokenType: store>(_capability: &Token::MintCapability<TokenType>, _amount: u128, _period: u64): Token::LinearTimeMintKey<TokenType>
+
+ + + +
+Implementation + + +
public fun issue_linear_mint_key<TokenType: store>(
+    _capability: &MintCapability<TokenType>,
+    _amount: u128,
+    _period: u64,
+): LinearTimeMintKey<TokenType> {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if true;
+
+ + + +
+ + + +## Function `destroy_linear_time_key` + +Destroy LinearTimeMintKey, for deprecated + + +
public fun destroy_linear_time_key<TokenType: store>(key: Token::LinearTimeMintKey<TokenType>): (u128, u128, u64, u64)
+
+ + + +
+Implementation + + +
public fun destroy_linear_time_key<TokenType: store>(key: LinearTimeMintKey<TokenType>): (u128, u128, u64, u64) {
+    let LinearTimeMintKey<TokenType> { total, minted, start_time, period } = key;
+    (total, minted, start_time, period)
+}
+
+ + + +
+ + + +## Function `read_linear_time_key` + + + +
public fun read_linear_time_key<TokenType: store>(key: &Token::LinearTimeMintKey<TokenType>): (u128, u128, u64, u64)
+
+ + + +
+Implementation + + +
public fun read_linear_time_key<TokenType: store>(key: &LinearTimeMintKey<TokenType>): (u128, u128, u64, u64) {
+    (key.total, key.minted, key.start_time, key.period)
+}
+
+ + + +
+ + + +## Function `burn` + +Burn some tokens of signer. + + +
public fun burn<TokenType: store>(account: &signer, tokens: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun burn<TokenType: store>(account: &signer, tokens: Token<TokenType>)
+acquires TokenInfo, BurnCapability {
+    burn_with_capability(
+        borrow_global<BurnCapability<TokenType>>(Signer::address_of(account)),
+        tokens,
+    )
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if spec_abstract_total_value<TokenType>() - tokens.value < 0;
+aborts_if !exists<BurnCapability<TokenType>>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `burn_with_capability` + +Burn tokens with the given BurnCapability. + + +
public fun burn_with_capability<TokenType: store>(_capability: &Token::BurnCapability<TokenType>, tokens: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun burn_with_capability<TokenType: store>(
+    _capability: &BurnCapability<TokenType>,
+    tokens: Token<TokenType>,
+) acquires TokenInfo {
+    let (token_address, module_name, token_name) = name_of_token<TokenType>();
+    let info = borrow_global_mut<TokenInfo<TokenType>>(token_address);
+    let Token { value } = tokens;
+    info.total_value = info.total_value - value;
+    Event::emit_event(
+        &mut info.burn_events,
+        BurnEvent {
+            amount: value,
+            token_code: TokenCode { addr: token_address, module_name, name: token_name },
+        },
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if spec_abstract_total_value<TokenType>() - tokens.value < 0;
+ensures spec_abstract_total_value<TokenType>() ==
+        old(global<TokenInfo<TokenType>>(SPEC_TOKEN_TEST_ADDRESS()).total_value) - tokens.value;
+
+ + + +
+ + + +## Function `zero` + +Create a new Token::Token with a value of 0 + + +
public fun zero<TokenType: store>(): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun zero<TokenType: store>(): Token<TokenType> {
+    Token<TokenType> { value: 0 }
+}
+
+ + + +
+ +
+Specification + + + +
ensures result.value == 0;
+
+ + + +
+ + + +## Function `value` + +Public accessor for the value of a token + + +
public fun value<TokenType: store>(token: &Token::Token<TokenType>): u128
+
+ + + +
+Implementation + + +
public fun value<TokenType: store>(token: &Token<TokenType>): u128 {
+    token.value
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == token.value;
+
+ + + +
+ + + +## Function `split` + +Splits the given token into two and returns them both + + +
public fun split<TokenType: store>(token: Token::Token<TokenType>, value: u128): (Token::Token<TokenType>, Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun split<TokenType: store>(
+    token: Token<TokenType>,
+    value: u128,
+): (Token<TokenType>, Token<TokenType>) {
+    let rest = withdraw(&mut token, value);
+    (token, rest)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if token.value < value;
+ensures token.value == result_1.value + result_2.value;
+
+ + + +
+ + + +## Function `withdraw` + +"Divides" the given token into two, where the original token is modified in place. +The original token will have value = original value - value +The new token will have a value = value +Fails if the tokens value is less than value + + +
public fun withdraw<TokenType: store>(token: &mut Token::Token<TokenType>, value: u128): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun withdraw<TokenType: store>(
+    token: &mut Token<TokenType>,
+    value: u128,
+): Token<TokenType> {
+    // Check that `value` is less than the token's value
+    assert!(token.value >= value, Errors::limit_exceeded(EAMOUNT_EXCEEDS_COIN_VALUE));
+    token.value = token.value - value;
+    Token { value: value }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if token.value < value;
+ensures result.value == value;
+ensures token.value == old(token).value - value;
+
+ + + +
+ + + +## Function `join` + +Merges two tokens of the same token and returns a new token whose +value is equal to the sum of the two inputs + + +
public fun join<TokenType: store>(token1: Token::Token<TokenType>, token2: Token::Token<TokenType>): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun join<TokenType: store>(
+    token1: Token<TokenType>,
+    token2: Token<TokenType>,
+): Token<TokenType> {
+    deposit(&mut token1, token2);
+    token1
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if token1.value + token2.value > max_u128();
+ensures token1.value + token2.value == result.value;
+
+ + + +
+ + + +## Function `deposit` + +"Merges" the two tokens +The token passed in by reference will have a value equal to the sum of the two tokens +The check token is consumed in the process + + +
public fun deposit<TokenType: store>(token: &mut Token::Token<TokenType>, check: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun deposit<TokenType: store>(token: &mut Token<TokenType>, check: Token<TokenType>) {
+    let Token { value } = check;
+    token.value = token.value + value;
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if token.value + check.value > max_u128();
+ensures old(token).value + check.value == token.value;
+
+ + + +
+ + + +## Function `destroy_zero` + +Destroy a token +Fails if the value is non-zero +The amount of Token in the system is a tightly controlled property, +so you cannot "burn" any non-zero amount of Token + + +
public fun destroy_zero<TokenType: store>(token: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun destroy_zero<TokenType: store>(token: Token<TokenType>) {
+    let Token { value } = token;
+    assert!(value == 0, Errors::invalid_state(EDESTROY_TOKEN_NON_ZERO))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if token.value > 0;
+
+ + + +
+ + + +## Function `scaling_factor` + +Returns the scaling_factor for the TokenType token. + + +
public fun scaling_factor<TokenType: store>(): u128
+
+ + + +
+Implementation + + +
public fun scaling_factor<TokenType: store>(): u128 acquires TokenInfo {
+    let token_address = token_address<TokenType>();
+    borrow_global<TokenInfo<TokenType>>(token_address).scaling_factor
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == global<TokenInfo<TokenType>>(SPEC_TOKEN_TEST_ADDRESS()).scaling_factor;
+
+ + + +
+ + + +## Function `market_cap` + +Return the total amount of token of type TokenType. + + +
public fun market_cap<TokenType: store>(): u128
+
+ + + +
+Implementation + + +
public fun market_cap<TokenType: store>(): u128 acquires TokenInfo {
+    let token_address = token_address<TokenType>();
+    borrow_global<TokenInfo<TokenType>>(token_address).total_value
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == global<TokenInfo<TokenType>>(SPEC_TOKEN_TEST_ADDRESS()).total_value;
+
+ + + +
+ + + +## Function `is_registered_in` + +Return true if the type TokenType is a registered in token_address. + + +
public fun is_registered_in<TokenType: store>(token_address: address): bool
+
+ + + +
+Implementation + + +
public fun is_registered_in<TokenType: store>(token_address: address): bool {
+    exists<TokenInfo<TokenType>>(token_address)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == exists<TokenInfo<TokenType>>(token_address);
+
+ + + +
+ + + +## Function `is_same_token` + +Return true if the type TokenType1 is same with TokenType2 + + +
public fun is_same_token<TokenType1: store, TokenType2: store>(): bool
+
+ + + +
+Implementation + + +
public fun is_same_token<TokenType1: store, TokenType2: store>(): bool {
+    return token_code<TokenType1>() == token_code<TokenType2>()
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `token_address` + +Return the TokenType's address + + +
public fun token_address<TokenType: store>(): address
+
+ + + +
+Implementation + + +
public fun token_address<TokenType: store>(): address {
+    let (addr, _, _) = name_of<TokenType>();
+    addr
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures [abstract] exists<TokenInfo<TokenType>>(result);
+ensures [abstract] result == SPEC_TOKEN_TEST_ADDRESS();
+ensures [abstract] global<TokenInfo<TokenType>>(result).total_value == 100000000u128;
+
+ + + +
+ + + +## Function `token_code` + +Return the token code for the registered token. + + +
public fun token_code<TokenType: store>(): Token::TokenCode
+
+ + + +
+Implementation + + +
public fun token_code<TokenType: store>(): TokenCode {
+    let (addr, module_name, name) = name_of<TokenType>();
+    TokenCode {
+        addr,
+        module_name,
+        name
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+
+ + +We use an uninterpreted function to represent the result of derived address. The actual value +does not matter for the verification of callers. + + + + + +
fun spec_token_code<TokenType>(): TokenCode;
+
+ + + +
+ + + +## Function `type_of` + + + +
public(friend) fun type_of<T>(): (address, vector<u8>, vector<u8>)
+
+ + + +
+Implementation + + +
public (friend) fun type_of<T>(): (address, vector<u8>, vector<u8>){
+    name_of<T>()
+}
+
+ + + +
+ + + +## Function `name_of` + +Return Token's module address, module name, and type name of TokenType. + + +
fun name_of<TokenType>(): (address, vector<u8>, vector<u8>)
+
+ + + +
+Implementation + + +
native fun name_of<TokenType>(): (address, vector<u8>, vector<u8>);
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+
+ + + +
+ + + +## Function `name_of_token` + + + +
fun name_of_token<TokenType: store>(): (address, vector<u8>, vector<u8>)
+
+ + + +
+Implementation + + +
fun name_of_token<TokenType: store>(): (address, vector<u8>, vector<u8>) {
+    name_of<TokenType>()
+}
+
+ + + +
+ +
+Specification + + + +
pragma opaque = true;
+aborts_if false;
+ensures [abstract] exists<TokenInfo<TokenType>>(result_1);
+ensures [abstract] result_1 == SPEC_TOKEN_TEST_ADDRESS();
+ensures [abstract] global<TokenInfo<TokenType>>(result_1).total_value == 100000000u128;
+
+ + + + + + + +
fun SPEC_TOKEN_TEST_ADDRESS(): address {
+   @0x2
+}
+
+ + + + + + + +
fun spec_abstract_total_value<TokenType>(): num {
+   global<TokenInfo<TokenType>>(SPEC_TOKEN_TEST_ADDRESS()).total_value
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/TransactionFee.md b/release/v13/docs/TransactionFee.md new file mode 100644 index 00000000..b6dcc89b --- /dev/null +++ b/release/v13/docs/TransactionFee.md @@ -0,0 +1,245 @@ + + + +# Module `0x1::TransactionFee` + +TransactionFee collect gas fees used by transactions in blocks temporarily. +Then they are distributed in TransactionManager. + + +- [Resource `TransactionFee`](#0x1_TransactionFee_TransactionFee) +- [Function `initialize`](#0x1_TransactionFee_initialize) +- [Function `add_txn_fee_token`](#0x1_TransactionFee_add_txn_fee_token) +- [Function `pay_fee`](#0x1_TransactionFee_pay_fee) +- [Function `distribute_transaction_fees`](#0x1_TransactionFee_distribute_transaction_fees) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::CoreAddresses;
+use 0x1::STC;
+use 0x1::Timestamp;
+use 0x1::Token;
+
+ + + + + +## Resource `TransactionFee` + +The TransactionFee resource holds a preburn resource for each +fiat TokenType that can be collected as a transaction fee. + + +
struct TransactionFee<TokenType> has key
+
+ + + +
+Fields + + +
+
+fee: Token::Token<TokenType> +
+
+ +
+
+ + +
+ + + +## Function `initialize` + +Called in genesis. Sets up the needed resources to collect transaction fees from the +TransactionFee resource with the TreasuryCompliance account. + + +
public fun initialize(account: &signer)
+
+ + + +
+Implementation + + +
public fun initialize(
+    account: &signer,
+) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+
+    // accept fees in all the currencies
+    add_txn_fee_token<STC>(account);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<TransactionFee<STC>>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `add_txn_fee_token` + +publishing a wrapper of the Preburn<TokenType> resource under fee_account + + +
fun add_txn_fee_token<TokenType: store>(account: &signer)
+
+ + + +
+Implementation + + +
fun add_txn_fee_token<TokenType: store>(
+    account: &signer,
+) {
+    move_to(
+        account,
+        TransactionFee<TokenType> {
+            fee: Token::zero(),
+        }
+    )
+ }
+
+ + + +
+ +
+Specification + + + +
aborts_if exists<TransactionFee<TokenType>>(Signer::address_of(account));
+
+ + + +
+ + + +## Function `pay_fee` + +Deposit token into the transaction fees bucket + + +
public fun pay_fee<TokenType: store>(token: Token::Token<TokenType>)
+
+ + + +
+Implementation + + +
public fun pay_fee<TokenType: store>(token: Token<TokenType>) acquires TransactionFee {
+    let txn_fees = borrow_global_mut<TransactionFee<TokenType>>(
+        CoreAddresses::GENESIS_ADDRESS()
+    );
+    Token::deposit(&mut txn_fees.fee, token)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if global<TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS()).fee.value + token.value > max_u128();
+
+ + + +
+ + + +## Function `distribute_transaction_fees` + +Distribute the transaction fees collected in the TokenType token. +If the TokenType is STC, it unpacks the token and preburns the +underlying fiat. + + +
public fun distribute_transaction_fees<TokenType: store>(account: &signer): Token::Token<TokenType>
+
+ + + +
+Implementation + + +
public fun distribute_transaction_fees<TokenType: store>(
+    account: &signer,
+): Token<TokenType> acquires TransactionFee {
+    let fee_address =  CoreAddresses::GENESIS_ADDRESS();
+    CoreAddresses::assert_genesis_address(account);
+
+    // extract fees
+    let txn_fees = borrow_global_mut<TransactionFee<TokenType>>(fee_address);
+    let value = Token::value<TokenType>(&txn_fees.fee);
+    if (value > 0) {
+        Token::withdraw(&mut txn_fees.fee, value)
+    }else {
+        Token::zero<TokenType>()
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/TransactionManager.md b/release/v13/docs/TransactionManager.md new file mode 100644 index 00000000..6477ab0d --- /dev/null +++ b/release/v13/docs/TransactionManager.md @@ -0,0 +1,710 @@ + + + +# Module `0x1::TransactionManager` + +TransactionManager manages: +1. prologue and epilogue of transactions. +2. prologue of blocks. + + +- [Constants](#@Constants_0) +- [Function `prologue`](#0x1_TransactionManager_prologue) +- [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::Option;
+use 0x1::PackageTxnManager;
+use 0x1::STC;
+use 0x1::Signer;
+use 0x1::Timestamp;
+use 0x1::Token;
+use 0x1::TransactionFee;
+use 0x1::TransactionPublishOption;
+use 0x1::TransactionTimeout;
+use 0x1::Vector;
+
+ + + + + +## Constants + + + + + + +
const MAX_U64: u128 = 18446744073709551615;
+
+ + + + + + + +
const EDEPRECATED_FUNCTION: u64 = 19;
+
+ + + + + + + +
const EPROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0;
+
+ + + + + + + +
const ECOIN_DEPOSIT_IS_ZERO: u64 = 15;
+
+ + + + + + + +
const EINSUFFICIENT_BALANCE: u64 = 10;
+
+ + + + + + + +
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 EPROLOGUE_BAD_CHAIN_ID: u64 = 6;
+
+ + + + + + + +
const EPROLOGUE_MODULE_NOT_ALLOWED: u64 = 7;
+
+ + + + + + + +
const EPROLOGUE_SCRIPT_NOT_ALLOWED: u64 = 8;
+
+ + + + + + + +
const EPROLOGUE_TRANSACTION_EXPIRED: u64 = 5;
+
+ + + + + + + +
const TXN_PAYLOAD_TYPE_PACKAGE: u8 = 1;
+
+ + + + + + + +
const TXN_PAYLOAD_TYPE_SCRIPT: u8 = 0;
+
+ + + + + + + +
const TXN_PAYLOAD_TYPE_SCRIPT_FUNCTION: u8 = 2;
+
+ + + + + +## Function `prologue` + +The prologue is invoked at the beginning of every transaction +It verifies: +- The account's auth key matches the transaction's public key +- That the account has enough balance to pay for all of the gas +- That the sequence number matches the transaction's sequence key + + +
public fun prologue<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, txn_expiration_time: u64, chain_id: u8, txn_payload_type: u8, txn_script_or_package_hash: vector<u8>, txn_package_address: address)
+
+ + + +
+Implementation + + +
public fun prologue<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,
+    txn_expiration_time: u64,
+    chain_id: u8,
+    txn_payload_type: u8,
+    txn_script_or_package_hash: vector<u8>,
+    txn_package_address: address,
+) {
+    // Can only be invoked by genesis account
+    assert!(
+        Signer::address_of(&account) == CoreAddresses::GENESIS_ADDRESS(),
+        Errors::requires_address(EPROLOGUE_ACCOUNT_DOES_NOT_EXIST),
+    );
+    // 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));
+    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),
+        Errors::invalid_argument(EPROLOGUE_TRANSACTION_EXPIRED),
+    );
+    if (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE) {
+        // stdlib upgrade is not affected by PublishOption
+        if (txn_package_address != CoreAddresses::GENESIS_ADDRESS()) {
+            assert!(
+                TransactionPublishOption::is_module_allowed(Signer::address_of(&account)),
+                Errors::invalid_argument(EPROLOGUE_MODULE_NOT_ALLOWED),
+            );
+        };
+        PackageTxnManager::package_txn_prologue_v2(
+            &account,
+            txn_sender,
+            txn_package_address,
+            txn_script_or_package_hash,
+        );
+    } else if (txn_payload_type == TXN_PAYLOAD_TYPE_SCRIPT) {
+        assert!(
+            TransactionPublishOption::is_script_allowed(
+                Signer::address_of(&account),
+            ),
+            Errors::invalid_argument(EPROLOGUE_SCRIPT_NOT_ALLOWED),
+        );
+    };
+    // do nothing for TXN_PAYLOAD_TYPE_SCRIPT_FUNCTION
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<ChainId::ChainId>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if ChainId::get() != chain_id;
+aborts_if !exists<Account::Account>(txn_sender);
+aborts_if Hash::sha3_256(txn_authentication_key_preimage) != global<Account::Account>(txn_sender).authentication_key;
+aborts_if txn_gas_price * txn_max_gas_units > max_u64();
+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 && 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;
+include TransactionTimeout::AbortsIfTimestampNotValid;
+aborts_if !TransactionTimeout::spec_is_valid_transaction_timestamp(txn_expiration_time);
+include TransactionPublishOption::AbortsIfTxnPublishOptionNotExistWithBool {
+    is_script_or_package: (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE || txn_payload_type == TXN_PAYLOAD_TYPE_SCRIPT),
+};
+aborts_if txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE && txn_package_address != CoreAddresses::GENESIS_ADDRESS() && !TransactionPublishOption::spec_is_module_allowed(Signer::address_of(account));
+aborts_if txn_payload_type == TXN_PAYLOAD_TYPE_SCRIPT && !TransactionPublishOption::spec_is_script_allowed(Signer::address_of(account));
+include PackageTxnManager::CheckPackageTxnAbortsIfWithType{is_package: (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE), sender:txn_sender, package_address: txn_package_address, package_hash: txn_script_or_package_hash};
+
+ + + +
+ + + +## Function `epilogue` + +The epilogue is invoked at the end of transactions. +It collects gas and bumps the sequence number + + +
public fun epilogue<TokenType: store>(account: signer, txn_sender: address, txn_sequence_number: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, txn_payload_type: u8, _txn_script_or_package_hash: vector<u8>, txn_package_address: address, success: bool)
+
+ + + +
+Implementation + + +
public fun epilogue<TokenType: store>(
+    account: signer,
+    txn_sender: address,
+    txn_sequence_number: u64,
+    txn_gas_price: u64,
+    txn_max_gas_units: u64,
+    gas_units_remaining: u64,
+    txn_payload_type: u8,
+    _txn_script_or_package_hash: vector<u8>,
+    txn_package_address: address,
+    // txn execute success or fail.
+    success: bool,
+) {
+    epilogue_v2<TokenType>(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining, txn_payload_type, _txn_script_or_package_hash, txn_package_address, success)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+include CoreAddresses::AbortsIfNotGenesisAddress;
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<Account::Account>(txn_sender);
+aborts_if !exists<Account::Balance<TokenType>>(txn_sender);
+aborts_if txn_max_gas_units < gas_units_remaining;
+aborts_if txn_sequence_number + 1 > max_u64();
+aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > max_u64();
+include PackageTxnManager::AbortsIfPackageTxnEpilogue {
+    is_package: (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE),
+    package_address: txn_package_address,
+    success: success,
+};
+
+ + + +
+ + + +## Function `epilogue_v2` + +The epilogue is invoked at the end of transactions. +It collects gas and bumps the sequence number + + +
public fun epilogue_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, gas_units_remaining: u64, txn_payload_type: u8, _txn_script_or_package_hash: vector<u8>, txn_package_address: address, success: bool)
+
+ + + +
+Implementation + + +
public fun epilogue_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,
+    gas_units_remaining: u64,
+    txn_payload_type: u8,
+    _txn_script_or_package_hash: vector<u8>,
+    txn_package_address: address,
+    // txn execute success or fail.
+    success: bool,
+) {
+    CoreAddresses::assert_genesis_address(&account);
+    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,
+        txn_authentication_key_preimage,
+        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(
+            &account,
+            txn_sender,
+            txn_package_address,
+            success,
+        );
+    }
+}
+
+ + + +
+ + + +## Function `block_prologue` + +Set the metadata for the current block and distribute transaction fees and block rewards. +The runtime always runs this before executing the transactions in a block. + + +
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: Option::Option<vector<u8>>)
+
+ + + +
+Implementation + + +
public fun block_prologue(
+    account: signer,
+    parent_hash: vector<u8>,
+    timestamp: u64,
+    author: address,
+    auth_key_vec: vector<u8>,
+    uncles: u64,
+    number: u64,
+    chain_id: u8,
+    parent_gas_used: u64,
+    parents_hash: Option::Option<vector<u8>>,
+) {
+    // Can only be invoked by genesis account
+    CoreAddresses::assert_genesis_address(&account);
+    // 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));
+
+    // deal with previous block first.
+    let txn_fee = TransactionFee::distribute_transaction_fees<STC>(&account);
+
+    // then deal with current block.
+    Timestamp::update_global_time(&account, timestamp);
+    Block::process_block_metadata(
+        &account,
+        parent_hash,
+        author,
+        timestamp,
+        uncles,
+        number,
+        parents_hash,
+    );
+    let reward = Epoch::adjust_epoch(&account, number, timestamp, uncles, parent_gas_used);
+    // pass in previous block gas fees.
+    BlockReward::process_block_reward(&account, number, reward, author, auth_key_vec, txn_fee);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## 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;
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/TransactionPublishOption.md b/release/v13/docs/TransactionPublishOption.md new file mode 100644 index 00000000..9507c62a --- /dev/null +++ b/release/v13/docs/TransactionPublishOption.md @@ -0,0 +1,348 @@ + + + +# Module `0x1::TransactionPublishOption` + +TransactionPublishOption provide an option to limit: +- whether user can use script or publish custom modules on chain. + + +- [Struct `TransactionPublishOption`](#0x1_TransactionPublishOption_TransactionPublishOption) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_TransactionPublishOption_initialize) +- [Function `new_transaction_publish_option`](#0x1_TransactionPublishOption_new_transaction_publish_option) +- [Function `is_script_allowed`](#0x1_TransactionPublishOption_is_script_allowed) +- [Function `is_module_allowed`](#0x1_TransactionPublishOption_is_module_allowed) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::Errors;
+use 0x1::Signer;
+use 0x1::Timestamp;
+
+ + + + + +## Struct `TransactionPublishOption` + +Defines and holds the publishing policies for the VM. There are three possible configurations: +1. !script_allowed && !module_publishing_allowed No module publishing, only script function in module are allowed. +2. script_allowed && !module_publishing_allowed No module publishing, custom scripts are allowed. +3. script_allowed && module_publishing_allowed Both module publishing and custom scripts are allowed. +We represent these as the following resource. + + +
struct TransactionPublishOption has copy, drop, store
+
+ + + +
+Fields + + +
+
+script_allowed: bool +
+
+ +
+
+module_publishing_allowed: bool +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const EINVALID_ARGUMENT: u64 = 18;
+
+ + + + + +The script hash already exists in the allowlist + + +
const EALLOWLIST_ALREADY_CONTAINS_SCRIPT: u64 = 1002;
+
+ + + + + +The script hash has an invalid length + + +
const EINVALID_SCRIPT_HASH: u64 = 1001;
+
+ + + + + + + +
const EPROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0;
+
+ + + + + + + +
const SCRIPT_HASH_LENGTH: u64 = 32;
+
+ + + + + +## Function `initialize` + +Module initialization. + + +
public fun initialize(account: &signer, script_allowed: bool, module_publishing_allowed: bool)
+
+ + + +
+Implementation + + +
public fun initialize(
+    account: &signer,
+    script_allowed: bool,
+    module_publishing_allowed: bool,
+) {
+    Timestamp::assert_genesis();
+    assert!(
+        Signer::address_of(account) == CoreAddresses::GENESIS_ADDRESS(),
+        Errors::requires_address(EPROLOGUE_ACCOUNT_DOES_NOT_EXIST),
+    );
+    let transaction_publish_option = Self::new_transaction_publish_option(script_allowed, module_publishing_allowed);
+    Config::publish_new_config(
+        account,
+        transaction_publish_option,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+include Config::PublishNewConfigAbortsIf<TransactionPublishOption>;
+include Config::PublishNewConfigEnsures<TransactionPublishOption>;
+
+ + + +
+ + + +## Function `new_transaction_publish_option` + +Create a new option. Mainly used in DAO. + + +
public fun new_transaction_publish_option(script_allowed: bool, module_publishing_allowed: bool): TransactionPublishOption::TransactionPublishOption
+
+ + + +
+Implementation + + +
public fun new_transaction_publish_option(
+    script_allowed: bool,
+    module_publishing_allowed: bool,
+): TransactionPublishOption {
+    TransactionPublishOption { script_allowed, module_publishing_allowed }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `is_script_allowed` + +Check if sender can execute script with + + +
public fun is_script_allowed(account: address): bool
+
+ + + +
+Implementation + + +
public fun is_script_allowed(account: address): bool {
+    let publish_option = Config::get_by_address<TransactionPublishOption>(account);
+    publish_option.script_allowed
+}
+
+ + + +
+ +
+Specification + + + +
include Config::AbortsIfConfigNotExist<TransactionPublishOption>{
+    addr: account
+};
+
+ + + +
+ + + +## Function `is_module_allowed` + +Check if a sender can publish a module + + +
public fun is_module_allowed(account: address): bool
+
+ + + +
+Implementation + + +
public fun is_module_allowed(account: address): bool {
+    let publish_option = Config::get_by_address<TransactionPublishOption>(account);
+    publish_option.module_publishing_allowed
+}
+
+ + + +
+ +
+Specification + + + +
include Config::AbortsIfConfigNotExist<TransactionPublishOption>{
+    addr: account
+};
+
+ + + + + + + +
schema AbortsIfTxnPublishOptionNotExist {
+    include Config::AbortsIfConfigNotExist<TransactionPublishOption>{
+        addr: CoreAddresses::GENESIS_ADDRESS()
+    };
+}
+
+ + + + + + + +
schema AbortsIfTxnPublishOptionNotExistWithBool {
+    is_script_or_package : bool;
+    aborts_if is_script_or_package && !exists<Config::Config<TransactionPublishOption>>(CoreAddresses::GENESIS_ADDRESS());
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
+ + + + + + + +
fun spec_is_script_allowed(addr: address) : bool{
+   let publish_option = Config::get_by_address<TransactionPublishOption>(addr);
+   publish_option.script_allowed
+}
+
+ + + + + + + +
fun spec_is_module_allowed(addr: address) : bool{
+   let publish_option = Config::get_by_address<TransactionPublishOption>(addr);
+   publish_option.module_publishing_allowed
+}
+
diff --git a/release/v13/docs/TransactionTimeout.md b/release/v13/docs/TransactionTimeout.md new file mode 100644 index 00000000..9e5baaf1 --- /dev/null +++ b/release/v13/docs/TransactionTimeout.md @@ -0,0 +1,108 @@ + + + +# Module `0x1::TransactionTimeout` + +A module used to check expiration time of transactions. + + +- [Function `is_valid_transaction_timestamp`](#0x1_TransactionTimeout_is_valid_transaction_timestamp) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::Block;
+use 0x1::Timestamp;
+use 0x1::TransactionTimeoutConfig;
+
+ + + + + +## Function `is_valid_transaction_timestamp` + +Check whether the given timestamp is valid for transactions. + + +
public fun is_valid_transaction_timestamp(txn_timestamp: u64): bool
+
+ + + +
+Implementation + + +
public fun is_valid_transaction_timestamp(txn_timestamp: u64): bool {
+  let current_block_time = Timestamp::now_seconds();
+  let block_number = Block::get_current_block_number();
+  // before first block, just require txn_timestamp > genesis timestamp.
+  if (block_number == 0) {
+    return txn_timestamp > current_block_time
+  };
+  let timeout = TransactionTimeoutConfig::duration_seconds();
+  let max_txn_time = current_block_time + timeout;
+  current_block_time < txn_timestamp && txn_timestamp < max_txn_time
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if !exists<Block::BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+include Timestamp::AbortsIfTimestampNotExists;
+aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
+aborts_if Block::get_current_block_number() != 0 && !exists<Config::Config<TransactionTimeoutConfig::TransactionTimeoutConfig>>(CoreAddresses::GENESIS_ADDRESS());
+
+ + + + + + + +
schema AbortsIfTimestampNotValid {
+    aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if !exists<Block::BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    include Timestamp::AbortsIfTimestampNotExists;
+    aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
+    aborts_if Block::get_current_block_number() != 0 && !exists<Config::Config<TransactionTimeoutConfig::TransactionTimeoutConfig>>(CoreAddresses::GENESIS_ADDRESS());
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
+ + + + + + + +
fun spec_is_valid_transaction_timestamp(txn_timestamp: u64):bool {
+ if (Block::get_current_block_number() == 0) {
+   txn_timestamp > Timestamp::now_seconds()
+ } else {
+     Timestamp::now_seconds() < txn_timestamp && txn_timestamp <
+     (Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds())
+ }
+}
+
diff --git a/release/v13/docs/TransactionTimeoutConfig.md b/release/v13/docs/TransactionTimeoutConfig.md new file mode 100644 index 00000000..e0488861 --- /dev/null +++ b/release/v13/docs/TransactionTimeoutConfig.md @@ -0,0 +1,235 @@ + + + +# Module `0x1::TransactionTimeoutConfig` + +Onchain configuration for timeout setting of transaction. + + +- [Struct `TransactionTimeoutConfig`](#0x1_TransactionTimeoutConfig_TransactionTimeoutConfig) +- [Function `initialize`](#0x1_TransactionTimeoutConfig_initialize) +- [Function `new_transaction_timeout_config`](#0x1_TransactionTimeoutConfig_new_transaction_timeout_config) +- [Function `get_transaction_timeout_config`](#0x1_TransactionTimeoutConfig_get_transaction_timeout_config) +- [Function `duration_seconds`](#0x1_TransactionTimeoutConfig_duration_seconds) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::Config;
+use 0x1::CoreAddresses;
+use 0x1::Timestamp;
+
+ + + + + +## Struct `TransactionTimeoutConfig` + +config structs. + + +
struct TransactionTimeoutConfig has copy, drop, store
+
+ + + +
+Fields + + +
+
+duration_seconds: u64 +
+
+ timeout in second. +
+
+ + +
+ + + +## Function `initialize` + +Initialize function. Should only be called in genesis. + + +
public fun initialize(account: &signer, duration_seconds: u64)
+
+ + + +
+Implementation + + +
public fun initialize(account: &signer, duration_seconds: u64) {
+    Timestamp::assert_genesis();
+    CoreAddresses::assert_genesis_address(account);
+
+    Config::publish_new_config<Self::TransactionTimeoutConfig>(
+        account,
+        new_transaction_timeout_config(duration_seconds)
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !Timestamp::is_genesis();
+aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+include Config::PublishNewConfigAbortsIf<TransactionTimeoutConfig>;
+include Config::PublishNewConfigEnsures<TransactionTimeoutConfig>;
+
+ + + +
+ + + +## Function `new_transaction_timeout_config` + +Create a new timeout config used in dao proposal. + + +
public fun new_transaction_timeout_config(duration_seconds: u64): TransactionTimeoutConfig::TransactionTimeoutConfig
+
+ + + +
+Implementation + + +
public fun new_transaction_timeout_config(duration_seconds: u64) : TransactionTimeoutConfig {
+    TransactionTimeoutConfig {duration_seconds: duration_seconds}
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `get_transaction_timeout_config` + +Get current timeout config. + + +
public fun get_transaction_timeout_config(): TransactionTimeoutConfig::TransactionTimeoutConfig
+
+ + + +
+Implementation + + +
public fun get_transaction_timeout_config(): TransactionTimeoutConfig {
+    Config::get_by_address<TransactionTimeoutConfig>(CoreAddresses::GENESIS_ADDRESS())
+}
+
+ + + +
+ +
+Specification + + + +
include Config::AbortsIfConfigNotExist<TransactionTimeoutConfig>{
+    addr: CoreAddresses::GENESIS_ADDRESS()
+};
+
+ + + +
+ + + +## Function `duration_seconds` + +Get current txn timeout in seconds. + + +
public fun duration_seconds(): u64
+
+ + + +
+Implementation + + +
public fun duration_seconds() :u64 {
+    let config = get_transaction_timeout_config();
+    config.duration_seconds
+}
+
+ + + +
+ +
+Specification + + + +
include Config::AbortsIfConfigNotExist<TransactionTimeoutConfig>{
+    addr: CoreAddresses::GENESIS_ADDRESS()
+};
+
+ + + + + + + +
schema AbortsIfTxnTimeoutConfigNotExist {
+    include Config::AbortsIfConfigNotExist<TransactionTimeoutConfig>{
+        addr: CoreAddresses::GENESIS_ADDRESS()
+    };
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict = true;
+
diff --git a/release/v13/docs/TransferScripts.md b/release/v13/docs/TransferScripts.md new file mode 100644 index 00000000..f9227cb6 --- /dev/null +++ b/release/v13/docs/TransferScripts.md @@ -0,0 +1,252 @@ + + + +# Module `0x1::TransferScripts` + + + +- [Constants](#@Constants_0) +- [Function `peer_to_peer`](#0x1_TransferScripts_peer_to_peer) +- [Function `peer_to_peer_v2`](#0x1_TransferScripts_peer_to_peer_v2) +- [Function `batch_peer_to_peer`](#0x1_TransferScripts_batch_peer_to_peer) +- [Function `batch_peer_to_peer_v2`](#0x1_TransferScripts_batch_peer_to_peer_v2) +- [Function `peer_to_peer_batch`](#0x1_TransferScripts_peer_to_peer_batch) +- [Function `peer_to_peer_with_metadata`](#0x1_TransferScripts_peer_to_peer_with_metadata) +- [Function `peer_to_peer_with_metadata_v2`](#0x1_TransferScripts_peer_to_peer_with_metadata_v2) + + +
use 0x1::Account;
+use 0x1::Errors;
+
+ + + + + +## Constants + + + + + + +
const EDEPRECATED_FUNCTION: u64 = 19;
+
+ + + + + + + +
const EADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 101;
+
+ + + + + + + +
const ELENGTH_MISMATCH: u64 = 102;
+
+ + + + + +## Function `peer_to_peer` + + + +
public entry fun peer_to_peer<TokenType: store>(account: signer, payee: address, _payee_auth_key: vector<u8>, amount: u128)
+
+ + + +
+Implementation + + +
public entry fun peer_to_peer<TokenType: store>(account: signer, payee: address, _payee_auth_key: vector<u8>, amount: u128) {
+     peer_to_peer_v2<TokenType>(account, payee, amount)
+}
+
+ + + +
+ + + +## Function `peer_to_peer_v2` + + + +
public entry fun peer_to_peer_v2<TokenType: store>(account: signer, payee: address, amount: u128)
+
+ + + +
+Implementation + + +
public entry fun peer_to_peer_v2<TokenType: store>(account: signer, payee: address, amount: u128) {
+    if (!Account::exists_at(payee)) {
+        Account::create_account_with_address<TokenType>(payee);
+    };
+    Account::pay_from<TokenType>(&account, payee, amount)
+}
+
+ + + +
+ + + +## Function `batch_peer_to_peer` + +Batch transfer token to others. + + +
public entry fun batch_peer_to_peer<TokenType: store>(account: signer, payeees: vector<address>, _payee_auth_keys: vector<vector<u8>>, amounts: vector<u128>)
+
+ + + +
+Implementation + + +
public entry fun batch_peer_to_peer<TokenType: store>(account: signer, payeees: vector<address>, _payee_auth_keys: vector<vector<u8>>, amounts: vector<u128>) {
+     batch_peer_to_peer_v2<TokenType>(account, payeees, amounts)
+}
+
+ + + +
+ + + +## Function `batch_peer_to_peer_v2` + +Batch transfer token to others. + + +
public entry fun batch_peer_to_peer_v2<TokenType: store>(account: signer, payeees: vector<address>, amounts: vector<u128>)
+
+ + + +
+Implementation + + +
public entry fun batch_peer_to_peer_v2<TokenType: store>(account: signer, payeees: vector<address>, amounts: vector<u128>) {
+    let len = Vector::length(&payeees);
+    assert!(len == Vector::length(&amounts), ELENGTH_MISMATCH);
+    let i = 0;
+    while (i < len){
+        let payee = *Vector::borrow(&payeees, i);
+        if (!Account::exists_at(payee)) {
+            Account::create_account_with_address<TokenType>(payee);
+        };
+        let amount = *Vector::borrow(&amounts, i);
+        Account::pay_from<TokenType>(&account, payee, amount);
+        i = i + 1;
+    }
+}
+
+ + + +
+ + + +## Function `peer_to_peer_batch` + + + +
public entry fun peer_to_peer_batch<TokenType: store>(_account: signer, _payeees: vector<u8>, _payee_auth_keys: vector<u8>, _amount: u128)
+
+ + + +
+Implementation + + +
public entry fun peer_to_peer_batch<TokenType: store>(_account: signer, _payeees: vector<u8>, _payee_auth_keys: vector<u8>, _amount: u128) {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ + + +## Function `peer_to_peer_with_metadata` + + + +
public entry fun peer_to_peer_with_metadata<TokenType: store>(account: signer, payee: address, _payee_auth_key: vector<u8>, amount: u128, metadata: vector<u8>)
+
+ + + +
+Implementation + + +
public entry fun peer_to_peer_with_metadata<TokenType: store>(
+    account: signer,
+    payee: address,
+    _payee_auth_key: vector<u8>,
+    amount: u128,
+    metadata: vector<u8>,
+) {
+     peer_to_peer_with_metadata_v2<TokenType>(account, payee, amount, metadata)
+}
+
+ + + +
+ + + +## Function `peer_to_peer_with_metadata_v2` + + + +
public entry fun peer_to_peer_with_metadata_v2<TokenType: store>(account: signer, payee: address, amount: u128, metadata: vector<u8>)
+
+ + + +
+Implementation + + +
public entry fun peer_to_peer_with_metadata_v2<TokenType: store>(
+        account: signer,
+        payee: address,
+        amount: u128,
+        metadata: vector<u8>,
+) {
+    if (!Account::exists_at(payee)) {
+        Account::create_account_with_address<TokenType>(payee);
+    };
+    Account::pay_from_with_metadata<TokenType>(&account,payee, amount, metadata)
+}
+
+ + + +
diff --git a/release/v13/docs/Treasury.md b/release/v13/docs/Treasury.md new file mode 100644 index 00000000..09400578 --- /dev/null +++ b/release/v13/docs/Treasury.md @@ -0,0 +1,1230 @@ + + + +# Module `0x1::Treasury` + +The module for the Treasury of DAO, which can hold the token of DAO. + + +- [Resource `Treasury`](#0x1_Treasury_Treasury) +- [Resource `WithdrawCapability`](#0x1_Treasury_WithdrawCapability) +- [Resource `LinearWithdrawCapability`](#0x1_Treasury_LinearWithdrawCapability) +- [Struct `WithdrawEvent`](#0x1_Treasury_WithdrawEvent) +- [Struct `DepositEvent`](#0x1_Treasury_DepositEvent) +- [Constants](#@Constants_0) +- [Function `initialize`](#0x1_Treasury_initialize) +- [Function `exists_at`](#0x1_Treasury_exists_at) +- [Function `balance`](#0x1_Treasury_balance) +- [Function `deposit`](#0x1_Treasury_deposit) +- [Function `do_withdraw`](#0x1_Treasury_do_withdraw) +- [Function `withdraw_with_capability`](#0x1_Treasury_withdraw_with_capability) +- [Function `withdraw`](#0x1_Treasury_withdraw) +- [Function `issue_linear_withdraw_capability`](#0x1_Treasury_issue_linear_withdraw_capability) +- [Function `withdraw_with_linear_capability`](#0x1_Treasury_withdraw_with_linear_capability) +- [Function `withdraw_by_linear`](#0x1_Treasury_withdraw_by_linear) +- [Function `split_linear_withdraw_cap`](#0x1_Treasury_split_linear_withdraw_cap) +- [Function `withdraw_amount_of_linear_cap`](#0x1_Treasury_withdraw_amount_of_linear_cap) +- [Function `is_empty_linear_withdraw_cap`](#0x1_Treasury_is_empty_linear_withdraw_cap) +- [Function `remove_withdraw_capability`](#0x1_Treasury_remove_withdraw_capability) +- [Function `add_withdraw_capability`](#0x1_Treasury_add_withdraw_capability) +- [Function `destroy_withdraw_capability`](#0x1_Treasury_destroy_withdraw_capability) +- [Function `add_linear_withdraw_capability`](#0x1_Treasury_add_linear_withdraw_capability) +- [Function `remove_linear_withdraw_capability`](#0x1_Treasury_remove_linear_withdraw_capability) +- [Function `destroy_linear_withdraw_capability`](#0x1_Treasury_destroy_linear_withdraw_capability) +- [Function `is_empty_linear_withdraw_capability`](#0x1_Treasury_is_empty_linear_withdraw_capability) +- [Function `get_linear_withdraw_capability_total`](#0x1_Treasury_get_linear_withdraw_capability_total) +- [Function `get_linear_withdraw_capability_withdraw`](#0x1_Treasury_get_linear_withdraw_capability_withdraw) +- [Function `get_linear_withdraw_capability_period`](#0x1_Treasury_get_linear_withdraw_capability_period) +- [Function `get_linear_withdraw_capability_start_time`](#0x1_Treasury_get_linear_withdraw_capability_start_time) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Event;
+use 0x1::Math;
+use 0x1::Signer;
+use 0x1::Timestamp;
+use 0x1::Token;
+
+ + + + + +## Resource `Treasury` + + + +
struct Treasury<TokenT> has store, key
+
+ + + +
+Fields + + +
+
+balance: Token::Token<TokenT> +
+
+ +
+
+withdraw_events: Event::EventHandle<Treasury::WithdrawEvent> +
+
+ event handle for treasury withdraw event +
+
+deposit_events: Event::EventHandle<Treasury::DepositEvent> +
+
+ event handle for treasury deposit event +
+
+ + +
+ +
+Specification + + + +
+ + + +## Resource `WithdrawCapability` + +A withdraw capability allows tokens of type TokenT to be withdraw from Treasury. + + +
struct WithdrawCapability<TokenT> has store, key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Resource `LinearWithdrawCapability` + +A linear time withdraw capability which can withdraw token from Treasury in a period by time-based linear release. + + +
struct LinearWithdrawCapability<TokenT> has store, key
+
+ + + +
+Fields + + +
+
+total: u128 +
+
+ The total amount of tokens that can be withdrawn by this capability +
+
+withdraw: u128 +
+
+ The amount of tokens that have been withdrawn by this capability +
+
+start_time: u64 +
+
+ The time-based linear release start time, timestamp in seconds. +
+
+period: u64 +
+
+ The time-based linear release period in seconds +
+
+ + +
+ + + +## Struct `WithdrawEvent` + +Message for treasury withdraw event. + + +
struct WithdrawEvent has drop, store
+
+ + + +
+Fields + + +
+
+amount: u128 +
+
+ +
+
+ + +
+ + + +## Struct `DepositEvent` + +Message for treasury deposit event. + + +
struct DepositEvent has drop, store
+
+ + + +
+Fields + + +
+
+amount: u128 +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_INVALID_PERIOD: u64 = 101;
+
+ + + + + + + +
const ERR_NOT_AUTHORIZED: u64 = 104;
+
+ + + + + + + +
const ERR_TOO_BIG_AMOUNT: u64 = 103;
+
+ + + + + + + +
const ERR_TREASURY_NOT_EXIST: u64 = 105;
+
+ + + + + + + +
const ERR_ZERO_AMOUNT: u64 = 102;
+
+ + + + + +## Function `initialize` + +Init a Treasury for TokenT. Can only be called by token issuer. + + +
public fun initialize<TokenT: store>(signer: &signer, init_token: Token::Token<TokenT>): Treasury::WithdrawCapability<TokenT>
+
+ + + +
+Implementation + + +
public fun initialize<TokenT: store>(signer: &signer, init_token: Token<TokenT>): WithdrawCapability<TokenT> {
+    let token_issuer = Token::token_address<TokenT>();
+    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    let treasure = Treasury {
+        balance: init_token,
+        withdraw_events: Event::new_event_handle<WithdrawEvent>(signer),
+        deposit_events: Event::new_event_handle<DepositEvent>(signer),
+    };
+    move_to(signer, treasure);
+    WithdrawCapability<TokenT>{}
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(signer) != Token::SPEC_TOKEN_TEST_ADDRESS();
+aborts_if exists<Treasury<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+ensures exists<Treasury<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+ensures result == WithdrawCapability<TokenT>{};
+
+ + + +
+ + + +## Function `exists_at` + +Check the Treasury of TokenT is exists. + + +
public fun exists_at<TokenT: store>(): bool
+
+ + + +
+Implementation + + +
public fun exists_at<TokenT: store>(): bool {
+    let token_issuer = Token::token_address<TokenT>();
+    exists<Treasury<TokenT>>(token_issuer)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == exists<Treasury<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+
+ + + +
+ + + +## Function `balance` + +Get the balance of TokenT's Treasury +if the Treasury do not exists, return 0. + + +
public fun balance<TokenT: store>(): u128
+
+ + + +
+Implementation + + +
public fun balance<TokenT:store>(): u128 acquires Treasury {
+    let token_issuer = Token::token_address<TokenT>();
+    if (!exists<Treasury<TokenT>>(token_issuer)) {
+        return 0
+    };
+    let treasury = borrow_global<Treasury<TokenT>>(token_issuer);
+    Token::value(&treasury.balance)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures if (exists<Treasury<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS()))
+            result == spec_balance<TokenT>()
+        else
+            result == 0;
+
+ + + +
+ + + +## Function `deposit` + + + +
public fun deposit<TokenT: store>(token: Token::Token<TokenT>)
+
+ + + +
+Implementation + + +
public fun deposit<TokenT: store>(token: Token<TokenT>) acquires Treasury {
+    assert!(exists_at<TokenT>(), Errors::not_published(ERR_TREASURY_NOT_EXIST));
+    let token_address = Token::token_address<TokenT>();
+    let treasury = borrow_global_mut<Treasury<TokenT>>(token_address);
+    let amount = Token::value(&token);
+    Event::emit_event(
+        &mut treasury.deposit_events,
+        DepositEvent { amount },
+    );
+    Token::deposit(&mut treasury.balance, token);
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Treasury<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+aborts_if spec_balance<TokenT>() + token.value > MAX_U128;
+ensures spec_balance<TokenT>() == old(spec_balance<TokenT>()) + token.value;
+
+ + + +
+ + + +## Function `do_withdraw` + + + +
fun do_withdraw<TokenT: store>(amount: u128): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
fun do_withdraw<TokenT: store>(amount: u128): Token<TokenT> acquires Treasury {
+    assert!(amount > 0, Errors::invalid_argument(ERR_ZERO_AMOUNT));
+    assert!(exists_at<TokenT>(), Errors::not_published(ERR_TREASURY_NOT_EXIST));
+    let token_address = Token::token_address<TokenT>();
+    let treasury = borrow_global_mut<Treasury<TokenT>>(token_address);
+    assert!(amount <= Token::value(&treasury.balance) , Errors::invalid_argument(ERR_TOO_BIG_AMOUNT));
+    Event::emit_event(
+        &mut treasury.withdraw_events,
+        WithdrawEvent { amount },
+    );
+    Token::withdraw(&mut treasury.balance, amount)
+}
+
+ + + +
+ +
+Specification + + + +
include WithdrawSchema<TokenT>;
+
+ + + + + + + +
schema WithdrawSchema<TokenT> {
+    amount: u64;
+    aborts_if amount <= 0;
+    aborts_if !exists<Treasury<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+    aborts_if spec_balance<TokenT>() < amount;
+    ensures spec_balance<TokenT>() ==
+        old(spec_balance<TokenT>()) - amount;
+}
+
+ + + +
+ + + +## Function `withdraw_with_capability` + +Withdraw tokens with given LinearWithdrawCapability. + + +
public fun withdraw_with_capability<TokenT: store>(_cap: &mut Treasury::WithdrawCapability<TokenT>, amount: u128): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
public fun withdraw_with_capability<TokenT: store>(
+    _cap: &mut WithdrawCapability<TokenT>,
+    amount: u128,
+): Token<TokenT> acquires Treasury {
+    do_withdraw(amount)
+}
+
+ + + +
+ +
+Specification + + + +
include WithdrawSchema<TokenT>;
+
+ + + +
+ + + +## Function `withdraw` + +Withdraw from TokenT's treasury, the signer must have WithdrawCapability + + +
public fun withdraw<TokenT: store>(signer: &signer, amount: u128): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
public fun withdraw<TokenT: store>(
+    signer: &signer,
+    amount: u128
+): Token<TokenT> acquires Treasury, WithdrawCapability {
+    let cap = borrow_global_mut<WithdrawCapability<TokenT>>(Signer::address_of(signer));
+    Self::withdraw_with_capability(cap, amount)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<WithdrawCapability<TokenT>>(Signer::address_of(signer));
+include WithdrawSchema<TokenT>;
+
+ + + +
+ + + +## Function `issue_linear_withdraw_capability` + +Issue a LinearWithdrawCapability with given WithdrawCapability. + + +
public fun issue_linear_withdraw_capability<TokenT: store>(_capability: &mut Treasury::WithdrawCapability<TokenT>, amount: u128, period: u64): Treasury::LinearWithdrawCapability<TokenT>
+
+ + + +
+Implementation + + +
public fun issue_linear_withdraw_capability<TokenT: store>(
+    _capability: &mut WithdrawCapability<TokenT>,
+    amount: u128,
+    period: u64
+): LinearWithdrawCapability<TokenT> {
+    assert!(period > 0, Errors::invalid_argument(ERR_INVALID_PERIOD));
+    assert!(amount > 0, Errors::invalid_argument(ERR_ZERO_AMOUNT));
+    let start_time = Timestamp::now_seconds();
+    LinearWithdrawCapability<TokenT> {
+        total: amount,
+        withdraw: 0,
+        start_time,
+        period,
+    }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if period == 0;
+aborts_if amount == 0;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(StarcoinFramework::CoreAddresses::GENESIS_ADDRESS());
+
+ + + +
+ + + +## Function `withdraw_with_linear_capability` + +Withdraw tokens with given LinearWithdrawCapability. + + +
public fun withdraw_with_linear_capability<TokenT: store>(cap: &mut Treasury::LinearWithdrawCapability<TokenT>): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
public fun withdraw_with_linear_capability<TokenT: store>(
+    cap: &mut LinearWithdrawCapability<TokenT>,
+): Token<TokenT> acquires Treasury {
+    let amount = withdraw_amount_of_linear_cap(cap);
+    let token = do_withdraw(amount);
+    cap.withdraw = cap.withdraw + amount;
+    token
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial;
+
+ + + +
+ + + +## Function `withdraw_by_linear` + +Withdraw from TokenT's treasury, the signer must have LinearWithdrawCapability + + +
public fun withdraw_by_linear<TokenT: store>(signer: &signer): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
public fun withdraw_by_linear<TokenT:store>(
+    signer: &signer,
+): Token<TokenT> acquires Treasury, LinearWithdrawCapability {
+    let cap = borrow_global_mut<LinearWithdrawCapability<TokenT>>(Signer::address_of(signer));
+    Self::withdraw_with_linear_capability(cap)
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial;
+aborts_if !exists<LinearWithdrawCapability<TokenT>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `split_linear_withdraw_cap` + +Split the given LinearWithdrawCapability. + + +
public fun split_linear_withdraw_cap<TokenT: store>(cap: &mut Treasury::LinearWithdrawCapability<TokenT>, amount: u128): (Token::Token<TokenT>, Treasury::LinearWithdrawCapability<TokenT>)
+
+ + + +
+Implementation + + +
public fun split_linear_withdraw_cap<TokenT: store>(
+    cap: &mut LinearWithdrawCapability<TokenT>,
+    amount: u128,
+): (Token<TokenT>, LinearWithdrawCapability<TokenT>) acquires Treasury {
+    assert!(amount > 0, Errors::invalid_argument(ERR_ZERO_AMOUNT));
+    let token = Self::withdraw_with_linear_capability(cap);
+    assert!((cap.withdraw + amount) <= cap.total, Errors::invalid_argument(ERR_TOO_BIG_AMOUNT));
+    cap.total = cap.total - amount;
+    let start_time = Timestamp::now_seconds();
+    let new_period = cap.start_time + cap.period - start_time;
+    let new_key = LinearWithdrawCapability<TokenT> {
+        total: amount,
+        withdraw: 0,
+        start_time,
+        period: new_period
+    };
+    (token, new_key)
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial;
+ensures old(cap.total - cap.withdraw) ==
+    result_1.value + (result_2.total - result_2.withdraw) + (cap.total - cap.withdraw);
+
+ + + +
+ + + +## Function `withdraw_amount_of_linear_cap` + +Returns the amount of the LinearWithdrawCapability can mint now. + + +
public fun withdraw_amount_of_linear_cap<TokenT: store>(cap: &Treasury::LinearWithdrawCapability<TokenT>): u128
+
+ + + +
+Implementation + + +
public fun withdraw_amount_of_linear_cap<TokenT: store>(cap: &LinearWithdrawCapability<TokenT>): u128 {
+    let now = Timestamp::now_seconds();
+    let elapsed_time = now - cap.start_time;
+    if (elapsed_time >= cap.period) {
+        cap.total - cap.withdraw
+    } else {
+        Math::mul_div(cap.total, (elapsed_time as u128), (cap.period as u128)) - cap.withdraw
+    }
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(StarcoinFramework::CoreAddresses::GENESIS_ADDRESS());
+aborts_if Timestamp::spec_now_seconds() < cap.start_time;
+aborts_if Timestamp::spec_now_seconds() - cap.start_time >= cap.period && cap.total < cap.withdraw;
+aborts_if [abstract]
+    Timestamp::spec_now_seconds() - cap.start_time < cap.period && Math::spec_mul_div() < cap.withdraw;
+ensures [abstract] result <= cap.total - cap.withdraw;
+
+ + + +
+ + + +## Function `is_empty_linear_withdraw_cap` + +Check if the given LinearWithdrawCapability is empty. + + +
public fun is_empty_linear_withdraw_cap<TokenT: store>(key: &Treasury::LinearWithdrawCapability<TokenT>): bool
+
+ + + +
+Implementation + + +
public fun is_empty_linear_withdraw_cap<TokenT:store>(key: &LinearWithdrawCapability<TokenT>) : bool {
+    key.total == key.withdraw
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == (key.total == key.withdraw);
+
+ + + +
+ + + +## Function `remove_withdraw_capability` + +Remove mint capability from signer. + + +
public fun remove_withdraw_capability<TokenT: store>(signer: &signer): Treasury::WithdrawCapability<TokenT>
+
+ + + +
+Implementation + + +
public fun remove_withdraw_capability<TokenT: store>(signer: &signer): WithdrawCapability<TokenT>
+acquires WithdrawCapability {
+    move_from<WithdrawCapability<TokenT>>(Signer::address_of(signer))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<WithdrawCapability<TokenT>>(Signer::address_of(signer));
+ensures !exists<WithdrawCapability<TokenT>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `add_withdraw_capability` + +Save mint capability to signer. + + +
public fun add_withdraw_capability<TokenT: store>(signer: &signer, cap: Treasury::WithdrawCapability<TokenT>)
+
+ + + +
+Implementation + + +
public fun add_withdraw_capability<TokenT: store>(signer: &signer, cap: WithdrawCapability<TokenT>) {
+    move_to(signer, cap)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if exists<WithdrawCapability<TokenT>>(Signer::address_of(signer));
+ensures exists<WithdrawCapability<TokenT>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `destroy_withdraw_capability` + +Destroy the given mint capability. + + +
public fun destroy_withdraw_capability<TokenT: store>(cap: Treasury::WithdrawCapability<TokenT>)
+
+ + + +
+Implementation + + +
public fun destroy_withdraw_capability<TokenT: store>(cap: WithdrawCapability<TokenT>) {
+    let WithdrawCapability<TokenT> {} = cap;
+}
+
+ + + +
+ +
+Specification + + + +
+ + + +## Function `add_linear_withdraw_capability` + +Add LinearWithdrawCapability to signer, a address only can have one LinearWithdrawCapability + + +
public fun add_linear_withdraw_capability<TokenT: store>(signer: &signer, cap: Treasury::LinearWithdrawCapability<TokenT>)
+
+ + + +
+Implementation + + +
public fun add_linear_withdraw_capability<TokenT: store>(signer: &signer, cap: LinearWithdrawCapability<TokenT>) {
+    move_to(signer, cap)
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if exists<LinearWithdrawCapability<TokenT>>(Signer::address_of(signer));
+ensures exists<LinearWithdrawCapability<TokenT>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `remove_linear_withdraw_capability` + +Remove LinearWithdrawCapability from signer. + + +
public fun remove_linear_withdraw_capability<TokenT: store>(signer: &signer): Treasury::LinearWithdrawCapability<TokenT>
+
+ + + +
+Implementation + + +
public fun remove_linear_withdraw_capability<TokenT: store>(signer: &signer): LinearWithdrawCapability<TokenT>
+acquires LinearWithdrawCapability {
+    move_from<LinearWithdrawCapability<TokenT>>(Signer::address_of(signer))
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<LinearWithdrawCapability<TokenT>>(Signer::address_of(signer));
+ensures !exists<LinearWithdrawCapability<TokenT>>(Signer::address_of(signer));
+
+ + + +
+ + + +## Function `destroy_linear_withdraw_capability` + +Destroy LinearWithdrawCapability. + + +
public fun destroy_linear_withdraw_capability<TokenT: store>(cap: Treasury::LinearWithdrawCapability<TokenT>)
+
+ + + +
+Implementation + + +
public fun destroy_linear_withdraw_capability<TokenT: store>(cap: LinearWithdrawCapability<TokenT>) {
+    let LinearWithdrawCapability{ total: _, withdraw: _, start_time: _, period: _ } = cap;
+}
+
+ + + +
+ + + +## Function `is_empty_linear_withdraw_capability` + + + +
public fun is_empty_linear_withdraw_capability<TokenT: store>(cap: &Treasury::LinearWithdrawCapability<TokenT>): bool
+
+ + + +
+Implementation + + +
public fun is_empty_linear_withdraw_capability<TokenT: store>(cap: &LinearWithdrawCapability<TokenT>): bool {
+    cap.total == cap.withdraw
+}
+
+ + + +
+ + + +## Function `get_linear_withdraw_capability_total` + +Get LinearWithdrawCapability total amount + + +
public fun get_linear_withdraw_capability_total<TokenT: store>(cap: &Treasury::LinearWithdrawCapability<TokenT>): u128
+
+ + + +
+Implementation + + +
public fun get_linear_withdraw_capability_total<TokenT: store>(cap: &LinearWithdrawCapability<TokenT>): u128 {
+    cap.total
+}
+
+ + + +
+ + + +## Function `get_linear_withdraw_capability_withdraw` + +Get LinearWithdrawCapability withdraw amount + + +
public fun get_linear_withdraw_capability_withdraw<TokenT: store>(cap: &Treasury::LinearWithdrawCapability<TokenT>): u128
+
+ + + +
+Implementation + + +
public fun get_linear_withdraw_capability_withdraw<TokenT: store>(cap: &LinearWithdrawCapability<TokenT>): u128 {
+    cap.withdraw
+}
+
+ + + +
+ + + +## Function `get_linear_withdraw_capability_period` + +Get LinearWithdrawCapability period in seconds + + +
public fun get_linear_withdraw_capability_period<TokenT: store>(cap: &Treasury::LinearWithdrawCapability<TokenT>): u64
+
+ + + +
+Implementation + + +
public fun get_linear_withdraw_capability_period<TokenT: store>(cap: &LinearWithdrawCapability<TokenT>): u64 {
+    cap.period
+}
+
+ + + +
+ + + +## Function `get_linear_withdraw_capability_start_time` + +Get LinearWithdrawCapability start_time in seconds + + +
public fun get_linear_withdraw_capability_start_time<TokenT: store>(cap: &Treasury::LinearWithdrawCapability<TokenT>): u64
+
+ + + +
+Implementation + + +
public fun get_linear_withdraw_capability_start_time<TokenT: store>(cap: &LinearWithdrawCapability<TokenT>): u64 {
+    cap.start_time
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
+ + + + + + + +
fun spec_balance<TokenType>(): num {
+   global<Treasury<TokenType>>(Token::SPEC_TOKEN_TEST_ADDRESS()).balance.value
+}
+
diff --git a/release/v13/docs/TreasuryScripts.md b/release/v13/docs/TreasuryScripts.md new file mode 100644 index 00000000..68c60d2f --- /dev/null +++ b/release/v13/docs/TreasuryScripts.md @@ -0,0 +1,204 @@ + + + +# Module `0x1::TreasuryScripts` + + + +- [Function `withdraw_and_split_lt_withdraw_cap`](#0x1_TreasuryScripts_withdraw_and_split_lt_withdraw_cap) +- [Function `withdraw_token_with_linear_withdraw_capability`](#0x1_TreasuryScripts_withdraw_token_with_linear_withdraw_capability) +- [Function `propose_withdraw`](#0x1_TreasuryScripts_propose_withdraw) +- [Function `execute_withdraw_proposal`](#0x1_TreasuryScripts_execute_withdraw_proposal) + + +
use 0x1::Account;
+use 0x1::Offer;
+use 0x1::Token;
+use 0x1::Treasury;
+use 0x1::TreasuryWithdrawDaoProposal;
+
+ + + + + +## Function `withdraw_and_split_lt_withdraw_cap` + + + +
public entry fun withdraw_and_split_lt_withdraw_cap<TokenT: store>(signer: signer, for_address: address, amount: u128, lock_period: u64)
+
+ + + +
+Implementation + + +
public entry fun withdraw_and_split_lt_withdraw_cap<TokenT: store>(
+    signer: signer,
+    for_address: address,
+    amount: u128,
+    lock_period: u64,
+) {
+    // 1. take cap: LinearWithdrawCapability<TokenT>
+    let cap = Treasury::remove_linear_withdraw_capability<TokenT>(&signer);
+
+    // 2. withdraw token and split
+    let (tokens, new_cap) = Treasury::split_linear_withdraw_cap(&mut cap, amount);
+
+    // 3. deposit
+    Account::deposit_to_self(&signer, tokens);
+
+    // 4. put or destroy key
+    if (Treasury::is_empty_linear_withdraw_capability(&cap)) {
+        Treasury::destroy_linear_withdraw_capability(cap);
+    } else {
+        Treasury::add_linear_withdraw_capability(&signer, cap);
+    };
+
+    // 5. offer
+    Offer::create(&signer, new_cap, for_address, lock_period);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `withdraw_token_with_linear_withdraw_capability` + + + +
public entry fun withdraw_token_with_linear_withdraw_capability<TokenT: store>(signer: signer)
+
+ + + +
+Implementation + + +
public entry fun withdraw_token_with_linear_withdraw_capability<TokenT: store>(
+    signer: signer,
+) {
+    // 1. take cap
+    let cap = Treasury::remove_linear_withdraw_capability<TokenT>(&signer);
+
+    // 2. withdraw token
+    let tokens = Treasury::withdraw_with_linear_capability(&mut cap);
+
+    // 3. deposit
+    Account::deposit_to_self(&signer, tokens);
+
+    // 4. put or destroy key
+    if (Treasury::is_empty_linear_withdraw_capability(&cap)) {
+        Treasury::destroy_linear_withdraw_capability(cap);
+    } else {
+        Treasury::add_linear_withdraw_capability(&signer, cap);
+    };
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `propose_withdraw` + + + +
public entry fun propose_withdraw<TokenT: copy, drop, store>(signer: signer, receiver: address, amount: u128, period: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public entry fun propose_withdraw<TokenT: copy + drop + store>(signer: signer, receiver: address, amount: u128, period: u64, exec_delay: u64){
+    TreasuryWithdrawDaoProposal::propose_withdraw<TokenT>(&signer, receiver, amount, period, exec_delay)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `execute_withdraw_proposal` + + + +
public entry fun execute_withdraw_proposal<TokenT: copy, drop, store>(signer: signer, proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public entry fun execute_withdraw_proposal<TokenT:copy + drop + store>(signer: signer, proposer_address: address,
+                                                                   proposal_id: u64,){
+    TreasuryWithdrawDaoProposal::execute_withdraw_proposal<TokenT>(&signer, proposer_address, proposal_id);
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
diff --git a/release/v13/docs/TreasuryWithdrawDaoProposal.md b/release/v13/docs/TreasuryWithdrawDaoProposal.md new file mode 100644 index 00000000..0e13d8cc --- /dev/null +++ b/release/v13/docs/TreasuryWithdrawDaoProposal.md @@ -0,0 +1,320 @@ + + + +# Module `0x1::TreasuryWithdrawDaoProposal` + +TreasuryWithdrawDaoProposal is a dao proposal for withdraw Token from Treasury. + + +- [Resource `WrappedWithdrawCapability`](#0x1_TreasuryWithdrawDaoProposal_WrappedWithdrawCapability) +- [Struct `WithdrawToken`](#0x1_TreasuryWithdrawDaoProposal_WithdrawToken) +- [Constants](#@Constants_0) +- [Function `plugin`](#0x1_TreasuryWithdrawDaoProposal_plugin) +- [Function `propose_withdraw`](#0x1_TreasuryWithdrawDaoProposal_propose_withdraw) +- [Function `execute_withdraw_proposal`](#0x1_TreasuryWithdrawDaoProposal_execute_withdraw_proposal) +- [Function `withdraw_for_block_reward`](#0x1_TreasuryWithdrawDaoProposal_withdraw_for_block_reward) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::CoreAddresses;
+use 0x1::Dao;
+use 0x1::Errors;
+use 0x1::Signer;
+use 0x1::Token;
+use 0x1::Treasury;
+
+ + + + + +## Resource `WrappedWithdrawCapability` + +A wrapper of Token MintCapability. + + +
struct WrappedWithdrawCapability<TokenT> has key
+
+ + + +
+Fields + + +
+
+cap: Treasury::WithdrawCapability<TokenT> +
+
+ +
+
+ + +
+ + + +## Struct `WithdrawToken` + +WithdrawToken request. + + +
struct WithdrawToken has copy, drop, store
+
+ + + +
+Fields + + +
+
+receiver: address +
+
+ the receiver of withdraw tokens. +
+
+amount: u128 +
+
+ how many tokens to mint. +
+
+period: u64 +
+
+ How long in milliseconds does it take for the token to be released +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_NOT_AUTHORIZED: u64 = 101;
+
+ + + + + +Only receiver can execute TreasuryWithdrawDaoProposal + + +
const ERR_NEED_RECEIVER_TO_EXECUTE: u64 = 102;
+
+ + + + + +The withdraw amount of propose is too many. + + +
const ERR_TOO_MANY_WITHDRAW_AMOUNT: u64 = 103;
+
+ + + + + +## Function `plugin` + +Plugin method of the module. +Should be called by token issuer. + + +
public fun plugin<TokenT: store>(signer: &signer, cap: Treasury::WithdrawCapability<TokenT>)
+
+ + + +
+Implementation + + +
public fun plugin<TokenT: store>(signer: &signer, cap: Treasury::WithdrawCapability<TokenT>) {
+    let token_issuer = Token::token_address<TokenT>();
+    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    move_to(signer, WrappedWithdrawCapability<TokenT> { cap: cap });
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+let sender = Signer::address_of(signer);
+aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS();
+aborts_if !exists<Treasury::WithdrawCapability<TokenT>>(sender);
+aborts_if exists<WrappedWithdrawCapability<TokenT>>(sender);
+ensures !exists<Treasury::WithdrawCapability<TokenT>>(sender);
+ensures exists<WrappedWithdrawCapability<TokenT>>(sender);
+
+ + + +
+ + + +## Function `propose_withdraw` + +Entrypoint for the proposal. + + +
public fun propose_withdraw<TokenT: copy, drop, store>(signer: &signer, receiver: address, amount: u128, period: u64, exec_delay: u64)
+
+ + + +
+Implementation + + +
public fun propose_withdraw<TokenT: copy + drop + store>(signer: &signer, receiver: address, amount: u128, period: u64, exec_delay: u64) {
+    let quorum_votes = Dao::quorum_votes<TokenT>();
+    assert!(amount <= quorum_votes,  Errors::invalid_argument(ERR_TOO_MANY_WITHDRAW_AMOUNT));
+    Dao::propose<TokenT, WithdrawToken>(
+        signer,
+        WithdrawToken { receiver, amount, period },
+        exec_delay,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+let quorum_votes = Dao::spec_quorum_votes<TokenT>();
+aborts_if amount > quorum_votes;
+include Dao::AbortIfDaoConfigNotExist<TokenT>;
+include Dao::AbortIfDaoInfoNotExist<TokenT>;
+aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config<TokenT>().min_action_delay;
+include Dao::CheckQuorumVotes<TokenT>;
+let sender = Signer::address_of(signer);
+aborts_if exists<Dao::Proposal<TokenT, WithdrawToken>>(sender);
+
+ + + +
+ + + +## Function `execute_withdraw_proposal` + +Once the proposal is agreed, anyone can call the method to make the proposal happen. + + +
public fun execute_withdraw_proposal<TokenT: copy, drop, store>(signer: &signer, proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public fun execute_withdraw_proposal<TokenT: copy + drop + store>(
+    signer: &signer,
+    proposer_address: address,
+    proposal_id: u64,
+) acquires WrappedWithdrawCapability {
+    let WithdrawToken { receiver, amount, period } = Dao::extract_proposal_action<TokenT, WithdrawToken>(
+        proposer_address,
+        proposal_id,
+    );
+    assert!(receiver == Signer::address_of(signer), Errors::requires_address(ERR_NEED_RECEIVER_TO_EXECUTE));
+    let cap = borrow_global_mut<WrappedWithdrawCapability<TokenT>>(Token::token_address<TokenT>());
+    let linear_cap = Treasury::issue_linear_withdraw_capability<TokenT>(&mut cap.cap, amount, period);
+    Treasury::add_linear_withdraw_capability(signer, linear_cap);
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = true;
+let expected_states = vec<u8>(6);
+include Dao::CheckProposalStates<TokenT, WithdrawToken>{expected_states};
+let proposal = global<Dao::Proposal<TokenT, WithdrawToken>>(proposer_address);
+aborts_if Option::is_none(proposal.action);
+aborts_if !exists<WrappedWithdrawCapability<TokenT>>(Token::SPEC_TOKEN_TEST_ADDRESS());
+
+ + + +
+ + + +## Function `withdraw_for_block_reward` + +Provider a port for get block reward STC from Treasury, only genesis account can invoke this function. +The TreasuryWithdrawCapability is locked in TreasuryWithdrawDaoProposal, and only can withdraw by DAO proposal. +This approach is not graceful, but restricts the operation to genesis accounts only, so there are no security issues either. + + +
public fun withdraw_for_block_reward<TokenT: store>(signer: &signer, reward: u128): Token::Token<TokenT>
+
+ + + +
+Implementation + + +
public fun withdraw_for_block_reward<TokenT: store>(signer: &signer, reward: u128):Token<TokenT> acquires WrappedWithdrawCapability  {
+    CoreAddresses::assert_genesis_address(signer);
+    let cap = borrow_global_mut<WrappedWithdrawCapability<TokenT>>(Signer::address_of(signer));
+    Treasury::withdraw_with_capability(&mut cap.cap, reward)
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+pragma aborts_if_is_partial;
+
diff --git a/release/v13/docs/TypeInfo.md b/release/v13/docs/TypeInfo.md new file mode 100644 index 00000000..be768667 --- /dev/null +++ b/release/v13/docs/TypeInfo.md @@ -0,0 +1,192 @@ + + + +# Module `0x1::TypeInfo` + + + +- [Struct `TypeInfo`](#0x1_TypeInfo_TypeInfo) +- [Function `account_address`](#0x1_TypeInfo_account_address) +- [Function `module_name`](#0x1_TypeInfo_module_name) +- [Function `struct_name`](#0x1_TypeInfo_struct_name) +- [Function `type_of`](#0x1_TypeInfo_type_of) +- [Function `size_of_val`](#0x1_TypeInfo_size_of_val) + + +
use 0x1::BCS;
+use 0x1::Token;
+
+ + + + + +## Struct `TypeInfo` + + + +
struct TypeInfo has copy, drop, store
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+module_name: vector<u8> +
+
+ +
+
+struct_name: vector<u8> +
+
+ +
+
+ + +
+ + + +## Function `account_address` + + + +
public fun account_address(type_info: &TypeInfo::TypeInfo): address
+
+ + + +
+Implementation + + +
public fun account_address(type_info: &TypeInfo): address {
+    type_info.account_address
+}
+
+ + + +
+ + + +## Function `module_name` + + + +
public fun module_name(type_info: &TypeInfo::TypeInfo): vector<u8>
+
+ + + +
+Implementation + + +
public fun module_name(type_info: &TypeInfo): vector<u8> {
+    *&type_info.module_name
+}
+
+ + + +
+ + + +## Function `struct_name` + + + +
public fun struct_name(type_info: &TypeInfo::TypeInfo): vector<u8>
+
+ + + +
+Implementation + + +
public fun struct_name(type_info: &TypeInfo): vector<u8> {
+    *&type_info.struct_name
+}
+
+ + + +
+ + + +## Function `type_of` + + + +
public fun type_of<T>(): TypeInfo::TypeInfo
+
+ + + +
+Implementation + + +
public fun type_of<T>(): TypeInfo {
+    let (account_address, module_name, struct_name) = Token::type_of<T>();
+    TypeInfo {
+        account_address,
+        module_name,
+        struct_name
+    }
+}
+
+ + + +
+ + + +## Function `size_of_val` + +Return the BCS size, in bytes, of value at val_ref. + +See the [BCS spec](https://github.com/diem/bcs) + +See test_size_of_val() for an analysis of common types and +nesting patterns, as well as test_size_of_val_vectors() for an +analysis of vector size dynamism. + + +
public fun size_of_val<T: store>(val_ref: &T): u64
+
+ + + +
+Implementation + + +
public fun size_of_val<T: store>(val_ref: &T): u64 {
+    // Return vector length of vectorized BCS representation.
+    Vector::length(&BCS::to_bytes<T>(val_ref))
+}
+
+ + + +
diff --git a/release/v13/docs/U256.md b/release/v13/docs/U256.md new file mode 100644 index 00000000..7b3f3368 --- /dev/null +++ b/release/v13/docs/U256.md @@ -0,0 +1,946 @@ + + + +# Module `0x1::U256` + +Implementation u256. + + +- [Struct `U256`](#0x1_U256_U256) +- [Constants](#@Constants_0) +- [Function `zero`](#0x1_U256_zero) +- [Function `one`](#0x1_U256_one) +- [Function `from_u64`](#0x1_U256_from_u64) +- [Function `from_u128`](#0x1_U256_from_u128) +- [Function `from_big_endian`](#0x1_U256_from_big_endian) +- [Function `from_little_endian`](#0x1_U256_from_little_endian) +- [Function `to_u128`](#0x1_U256_to_u128) +- [Function `compare`](#0x1_U256_compare) +- [Function `add`](#0x1_U256_add) +- [Function `sub`](#0x1_U256_sub) +- [Function `mul`](#0x1_U256_mul) +- [Function `div`](#0x1_U256_div) +- [Function `rem`](#0x1_U256_rem) +- [Function `pow`](#0x1_U256_pow) +- [Function `from_bytes`](#0x1_U256_from_bytes) +- [Function `native_add`](#0x1_U256_native_add) +- [Function `native_sub`](#0x1_U256_native_sub) +- [Function `native_mul`](#0x1_U256_native_mul) +- [Function `native_div`](#0x1_U256_native_div) +- [Function `native_rem`](#0x1_U256_native_rem) +- [Function `native_pow`](#0x1_U256_native_pow) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Vector;
+
+ + + + + +## Struct `U256` + +use vector to represent data. +so that we can use buildin vector ops later to construct U256. +vector should always has two elements. + + +
struct U256 has copy, drop, store
+
+ + + +
+Fields + + +
+
+bits: vector<u64> +
+
+ little endian representation +
+
+ + +
+ +
+Specification + + + +
invariant len(bits) == 4;
+
+ + + + + + + +
fun value_of_U256(a: U256): num {
+   a.bits[0] +
+   a.bits[1] * P64 +
+   a.bits[2] * P64 * P64 +
+   a.bits[3] * P64 * P64 * P64
+}
+
+ + + +
+ + + +## Constants + + + + + + +
const P32: u64 = 4294967296;
+
+ + + + + + + +
const P64: u128 = 18446744073709551616;
+
+ + + + + + + +
const EQUAL: u8 = 0;
+
+ + + + + + + +
const GREATER_THAN: u8 = 2;
+
+ + + + + + + +
const LESS_THAN: u8 = 1;
+
+ + + + + + + +
const ERR_INVALID_LENGTH: u64 = 100;
+
+ + + + + + + +
const ERR_OVERFLOW: u64 = 200;
+
+ + + + + + + +
const WORD: u8 = 4;
+
+ + + + + +## Function `zero` + + + +
public fun zero(): U256::U256
+
+ + + +
+Implementation + + +
public fun zero(): U256 {
+    from_u128(0u128)
+}
+
+ + + +
+ + + +## Function `one` + + + +
public fun one(): U256::U256
+
+ + + +
+Implementation + + +
public fun one(): U256 {
+    from_u128(1u128)
+}
+
+ + + +
+ + + +## Function `from_u64` + + + +
public fun from_u64(v: u64): U256::U256
+
+ + + +
+Implementation + + +
public fun from_u64(v: u64): U256 {
+    from_u128((v as u128))
+}
+
+ + + +
+ + + +## Function `from_u128` + + + +
public fun from_u128(v: u128): U256::U256
+
+ + + +
+Implementation + + +
public fun from_u128(v: u128): U256 {
+    let low = ((v & 0xffffffffffffffff) as u64);
+    let high = ((v >> 64) as u64);
+    let bits = Vector::singleton(low);
+    Vector::push_back(&mut bits, high);
+    Vector::push_back(&mut bits, 0u64);
+    Vector::push_back(&mut bits, 0u64);
+    U256 { bits }
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma opaque;
+ensures value_of_U256(result) == v;
+
+ + + +
+ + + +## Function `from_big_endian` + + + +
public fun from_big_endian(data: vector<u8>): U256::U256
+
+ + + +
+Implementation + + +
public fun from_big_endian(data: vector<u8>): U256 {
+    // TODO: define error code.
+    assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH));
+    from_bytes(&data, true)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `from_little_endian` + + + +
public fun from_little_endian(data: vector<u8>): U256::U256
+
+ + + +
+Implementation + + +
public fun from_little_endian(data: vector<u8>): U256 {
+    // TODO: define error code.
+    assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH));
+    from_bytes(&data, false)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `to_u128` + + + +
public fun to_u128(v: &U256::U256): u128
+
+ + + +
+Implementation + + +
public fun to_u128(v: &U256): u128 {
+    assert!(*Vector::borrow(&v.bits, 3) == 0, Errors::invalid_state(ERR_OVERFLOW));
+    assert!(*Vector::borrow(&v.bits, 2) == 0, Errors::invalid_state(ERR_OVERFLOW));
+    ((*Vector::borrow(&v.bits, 1) as u128) << 64) | (*Vector::borrow(&v.bits, 0) as u128)
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma opaque;
+aborts_if value_of_U256(v) >= P64 * P64;
+ensures value_of_U256(v) == result;
+
+ + + +
+ + + +## Function `compare` + + + +
public fun compare(a: &U256::U256, b: &U256::U256): u8
+
+ + + +
+Implementation + + +
public fun compare(a: &U256, b: &U256): u8 {
+    let i = (WORD as u64);
+    while (i > 0) {
+        i = i - 1;
+        let a_bits = *Vector::borrow(&a.bits, i);
+        let b_bits = *Vector::borrow(&b.bits, i);
+        if (a_bits != b_bits) {
+            if (a_bits < b_bits) {
+                return LESS_THAN
+            } else {
+                return GREATER_THAN
+            }
+        }
+    };
+    return EQUAL
+}
+
+ + + +
+ + + +## Function `add` + + + +
public fun add(a: U256::U256, b: U256::U256): U256::U256
+
+ + + +
+Implementation + + +
public fun add(a: U256, b: U256): U256 {
+    native_add(&mut a, &b);
+    a
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64;
+ensures value_of_U256(result) == value_of_U256(a) + value_of_U256(b);
+
+ + + +
+ + + +## Function `sub` + + + +
public fun sub(a: U256::U256, b: U256::U256): U256::U256
+
+ + + +
+Implementation + + +
public fun sub(a: U256, b: U256): U256 {
+    native_sub(&mut a, &b);
+    a
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if value_of_U256(a) < value_of_U256(b);
+ensures value_of_U256(result) == value_of_U256(a) - value_of_U256(b);
+
+ + + +
+ + + +## Function `mul` + + + +
public fun mul(a: U256::U256, b: U256::U256): U256::U256
+
+ + + +
+Implementation + + +
public fun mul(a: U256, b: U256): U256 {
+    native_mul(&mut a, &b);
+    a
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma timeout = 200;
+aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64;
+ensures value_of_U256(result) == value_of_U256(a) * value_of_U256(b);
+
+ + + +
+ + + +## Function `div` + + + +
public fun div(a: U256::U256, b: U256::U256): U256::U256
+
+ + + +
+Implementation + + +
public fun div(a: U256, b: U256): U256 {
+    native_div(&mut a, &b);
+    a
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma timeout = 160;
+aborts_if value_of_U256(b) == 0;
+ensures value_of_U256(result) == value_of_U256(a) / value_of_U256(b);
+
+ + + +
+ + + +## Function `rem` + + + +
public fun rem(a: U256::U256, b: U256::U256): U256::U256
+
+ + + +
+Implementation + + +
public fun rem(a: U256, b: U256): U256 {
+    native_rem(&mut a, &b);
+    a
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma timeout = 160;
+aborts_if value_of_U256(b) == 0;
+ensures value_of_U256(result) == value_of_U256(a) % value_of_U256(b);
+
+ + + +
+ + + +## Function `pow` + + + +
public fun pow(a: U256::U256, b: U256::U256): U256::U256
+
+ + + +
+Implementation + + +
public fun pow(a: U256, b: U256): U256 {
+    native_pow(&mut a, &b);
+    a
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+pragma opaque;
+pragma timeout = 600;
+let p = pow_spec(value_of_U256(a), value_of_U256(b));
+aborts_if p >= P64 * P64 * P64 * P64;
+ensures value_of_U256(result) == p;
+
+ + + +
+ + + +## Function `from_bytes` + + + +
fun from_bytes(data: &vector<u8>, be: bool): U256::U256
+
+ + + +
+Implementation + + +
native fun from_bytes(data: &vector<u8>, be: bool): U256;
+
+ + + +
+ + + +## Function `native_add` + + + +
fun native_add(a: &mut U256::U256, b: &U256::U256)
+
+ + + +
+Implementation + + +
native fun native_add(a: &mut U256, b: &U256);
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64;
+ensures value_of_U256(a) == value_of_U256(old(a)) + value_of_U256(b);
+
+ + + +
+ + + +## Function `native_sub` + + + +
fun native_sub(a: &mut U256::U256, b: &U256::U256)
+
+ + + +
+Implementation + + +
native fun native_sub(a: &mut U256, b: &U256);
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if value_of_U256(a) - value_of_U256(b) < 0;
+ensures value_of_U256(a) == value_of_U256(old(a)) - value_of_U256(b);
+
+ + + +
+ + + +## Function `native_mul` + + + +
fun native_mul(a: &mut U256::U256, b: &U256::U256)
+
+ + + +
+Implementation + + +
native fun native_mul(a: &mut U256, b: &U256);
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64;
+ensures value_of_U256(a) == value_of_U256(old(a)) * value_of_U256(b);
+
+ + + +
+ + + +## Function `native_div` + + + +
fun native_div(a: &mut U256::U256, b: &U256::U256)
+
+ + + +
+Implementation + + +
native fun native_div(a: &mut U256, b: &U256);
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if value_of_U256(b) == 0;
+ensures value_of_U256(a) == value_of_U256(old(a)) / value_of_U256(b);
+
+ + + +
+ + + +## Function `native_rem` + + + +
fun native_rem(a: &mut U256::U256, b: &U256::U256)
+
+ + + +
+Implementation + + +
native fun native_rem(a: &mut U256, b: &U256);
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if value_of_U256(b) == 0;
+ensures value_of_U256(a) == value_of_U256(old(a)) % value_of_U256(b);
+
+ + + +
+ + + +## Function `native_pow` + + + +
fun native_pow(a: &mut U256::U256, b: &U256::U256)
+
+ + + +
+Implementation + + +
native fun native_pow(a: &mut U256, b: &U256);
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+aborts_if pow_spec(value_of_U256(a), value_of_U256(b)) >= P64 * P64 * P64 * P64;
+ensures value_of_U256(a) == pow_spec(value_of_U256(old(a)), value_of_U256(b));
+
+ + + + + + + +
fun pow_spec(base: num, expon: num): num {
+   // This actually doesn't follow a strict definition as 0^0 is undefined
+   // mathematically. But the U256::pow of Rust is defined to be like this:
+   // Link: https://docs.rs/uint/0.9.3/src/uint/uint.rs.html#1000-1003
+   if (expon > 0) {
+       let x = pow_spec(base, expon / 2);
+       if (expon % 2 == 0) { x * x } else { x * x * base }
+   } else {
+       1
+   }
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = true;
+
diff --git a/release/v13/docs/UpgradeModuleDaoProposal.md b/release/v13/docs/UpgradeModuleDaoProposal.md new file mode 100644 index 00000000..add8f904 --- /dev/null +++ b/release/v13/docs/UpgradeModuleDaoProposal.md @@ -0,0 +1,350 @@ + + + +# Module `0x1::UpgradeModuleDaoProposal` + +UpgradeModuleDaoProposal is a proposal moudle used to upgrade contract codes under a token. + + +- [Resource `UpgradeModuleCapability`](#0x1_UpgradeModuleDaoProposal_UpgradeModuleCapability) +- [Struct `UpgradeModule`](#0x1_UpgradeModuleDaoProposal_UpgradeModule) +- [Struct `UpgradeModuleV2`](#0x1_UpgradeModuleDaoProposal_UpgradeModuleV2) +- [Constants](#@Constants_0) +- [Function `plugin`](#0x1_UpgradeModuleDaoProposal_plugin) +- [Function `propose_module_upgrade_v2`](#0x1_UpgradeModuleDaoProposal_propose_module_upgrade_v2) +- [Function `submit_module_upgrade_plan`](#0x1_UpgradeModuleDaoProposal_submit_module_upgrade_plan) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Dao;
+use 0x1::Errors;
+use 0x1::PackageTxnManager;
+use 0x1::Signer;
+use 0x1::Token;
+
+ + + + + +## Resource `UpgradeModuleCapability` + +A wrapper of PackageTxnManager::UpgradePlanCapability. + + +
struct UpgradeModuleCapability<TokenT> has key
+
+ + + +
+Fields + + +
+
+cap: PackageTxnManager::UpgradePlanCapability +
+
+ +
+
+ + +
+ + + +## Struct `UpgradeModule` + +request of upgrading module contract code. + + +
struct UpgradeModule has copy, drop, store
+
+ + + +
+Fields + + +
+
+module_address: address +
+
+ +
+
+package_hash: vector<u8> +
+
+ +
+
+version: u64 +
+
+ +
+
+ + +
+ + + +## Struct `UpgradeModuleV2` + + + +
struct UpgradeModuleV2 has copy, drop, store
+
+ + + +
+Fields + + +
+
+module_address: address +
+
+ +
+
+package_hash: vector<u8> +
+
+ +
+
+version: u64 +
+
+ +
+
+enforced: bool +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_NOT_AUTHORIZED: u64 = 401;
+
+ + + + + + + +
const ERR_ADDRESS_MISSMATCH: u64 = 402;
+
+ + + + + + + +
const ERR_UNABLE_TO_UPGRADE: u64 = 400;
+
+ + + + + +## Function `plugin` + +If this goverment can upgrade module, call this to register capability. + + +
public fun plugin<TokenT: store>(signer: &signer, cap: PackageTxnManager::UpgradePlanCapability)
+
+ + + +
+Implementation + + +
public fun plugin<TokenT: store>(
+    signer: &signer,
+    cap: PackageTxnManager::UpgradePlanCapability,
+) {
+    let token_issuer = Token::token_address<TokenT>();
+    assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED));
+    move_to(signer, UpgradeModuleCapability<TokenT> { cap })
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = false;
+let sender = Signer::address_of(signer);
+aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS();
+aborts_if exists<UpgradeModuleCapability<TokenT>>(sender);
+
+ + + + + + + +
schema AbortIfUnableUpgrade<TokenT> {
+    module_address: address;
+    let token_issuer = Token::SPEC_TOKEN_TEST_ADDRESS();
+    aborts_if !exists<UpgradeModuleCapability<TokenT>>(token_issuer);
+    let cap = global<UpgradeModuleCapability<TokenT>>(token_issuer).cap;
+    aborts_if PackageTxnManager::account_address(cap) != module_address;
+}
+
+ + + +
+ + + +## Function `propose_module_upgrade_v2` + + + +
public fun propose_module_upgrade_v2<TokenT: copy, drop, store>(signer: &signer, module_address: address, package_hash: vector<u8>, version: u64, exec_delay: u64, enforced: bool)
+
+ + + +
+Implementation + + +
public fun propose_module_upgrade_v2<TokenT: copy + drop + store>(
+    signer: &signer,
+    module_address: address,
+    package_hash: vector<u8>,
+    version: u64,
+    exec_delay: u64,
+    enforced: bool,
+) acquires UpgradeModuleCapability {
+    let cap = borrow_global<UpgradeModuleCapability<TokenT>>(Token::token_address<TokenT>());
+    let account_address = PackageTxnManager::account_address(&cap.cap);
+    assert!(account_address == module_address, Errors::requires_capability(ERR_ADDRESS_MISSMATCH));
+    Dao::propose<TokenT, UpgradeModuleV2>(
+        signer,
+        UpgradeModuleV2 { module_address, package_hash, version, enforced },
+        exec_delay,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
pragma aborts_if_is_partial = true;
+include AbortIfUnableUpgrade<TokenT>;
+
+ + + +
+ + + +## Function `submit_module_upgrade_plan` + +Once the proposal is agreed, anyone can call this method to generate the upgrading plan. + + +
public fun submit_module_upgrade_plan<TokenT: copy, drop, store>(proposer_address: address, proposal_id: u64)
+
+ + + +
+Implementation + + +
public fun submit_module_upgrade_plan<TokenT: copy + drop + store>(
+    proposer_address: address,
+    proposal_id: u64,
+) acquires UpgradeModuleCapability {
+    let UpgradeModuleV2 { module_address, package_hash, version, enforced } = Dao::extract_proposal_action<
+        TokenT,
+        UpgradeModuleV2,
+    >(proposer_address, proposal_id);
+    let cap = borrow_global<UpgradeModuleCapability<TokenT>>(Token::token_address<TokenT>());
+    let account_address = PackageTxnManager::account_address(&cap.cap);
+    assert!(account_address == module_address, Errors::requires_capability(ERR_ADDRESS_MISSMATCH));
+    PackageTxnManager::submit_upgrade_plan_with_cap_v2(
+        &cap.cap,
+        package_hash,
+        version,
+        enforced,
+    );
+}
+
+ + + +
+ +
+Specification + + + +
let expected_states = vec<u8>(6);
+include Dao::CheckProposalStates<TokenT, UpgradeModule>{expected_states};
+let proposal = global<Dao::Proposal<TokenT, UpgradeModule>>(proposer_address);
+aborts_if Option::is_none(proposal.action);
+let action = proposal.action.vec[0];
+include AbortIfUnableUpgrade<TokenT>{module_address: action.module_address};
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+pragma aborts_if_is_partial;
+
diff --git a/release/v13/docs/VMConfig.md b/release/v13/docs/VMConfig.md new file mode 100644 index 00000000..973bf229 --- /dev/null +++ b/release/v13/docs/VMConfig.md @@ -0,0 +1,738 @@ + + + +# Module `0x1::VMConfig` + +VMConfig keep track of VM related configuration, like gas schedule. + + +- [Struct `VMConfig`](#0x1_VMConfig_VMConfig) +- [Struct `GasSchedule`](#0x1_VMConfig_GasSchedule) +- [Struct `GasConstants`](#0x1_VMConfig_GasConstants) +- [Struct `GasCost`](#0x1_VMConfig_GasCost) +- [Function `instruction_schedule`](#0x1_VMConfig_instruction_schedule) +- [Function `native_schedule`](#0x1_VMConfig_native_schedule) +- [Function `gas_constants`](#0x1_VMConfig_gas_constants) +- [Function `new_gas_cost`](#0x1_VMConfig_new_gas_cost) +- [Function `new_vm_config`](#0x1_VMConfig_new_vm_config) +- [Function `initialize`](#0x1_VMConfig_initialize) +- [Module Specification](#@Module_Specification_0) + + +
use 0x1::ChainId;
+use 0x1::Config;
+use 0x1::CoreAddresses;
+
+ + + + + +## Struct `VMConfig` + +The struct to hold all config data needed to operate the VM. +* gas_schedule: Cost of running the VM. + + +
struct VMConfig has copy, drop, store
+
+ + + +
+Fields + + +
+
+gas_schedule: VMConfig::GasSchedule +
+
+ +
+
+ + +
+ + + +## Struct `GasSchedule` + +The gas schedule keeps two separate schedules for the gas: +* The instruction_schedule: This holds the gas for each bytecode instruction. +* The native_schedule: This holds the gas for used (per-byte operated over) for each native +function. +A couple notes: +1. In the case that an instruction is deleted from the bytecode, that part of the cost schedule +still needs to remain the same; once a slot in the table is taken by an instruction, that is its +slot for the rest of time (since that instruction could already exist in a module on-chain). +2. The initialization of the module will publish the instruction table to the genesis +address, and will preload the vector with the gas schedule for instructions. The VM will then +load this into memory at the startup of each block. + + +
struct GasSchedule has copy, drop, store
+
+ + + +
+Fields + + +
+
+instruction_schedule: vector<u8> +
+
+ +
+
+native_schedule: vector<u8> +
+
+ +
+
+gas_constants: VMConfig::GasConstants +
+
+ +
+
+ + +
+ + + +## Struct `GasConstants` + +The gas constants contains all kind of constants used in gas calculation. + + +
struct GasConstants has copy, drop, store
+
+ + + +
+Fields + + +
+
+global_memory_per_byte_cost: u64 +
+
+ The cost per-byte written to global storage. +
+
+global_memory_per_byte_write_cost: u64 +
+
+ The cost per-byte written to storage. +
+
+min_transaction_gas_units: u64 +
+
+ We charge one unit of gas per-byte for the first 600 bytes +
+
+large_transaction_cutoff: u64 +
+
+ Any transaction over this size will be charged INTRINSIC_GAS_PER_BYTE per byte +
+
+instrinsic_gas_per_byte: u64 +
+
+ The units of gas that should be charged per byte for every transaction. +
+
+maximum_number_of_gas_units: u64 +
+
+ 1 nanosecond should equal one unit of computational gas. We bound the maximum + computational time of any given transaction at 10 milliseconds. We want this number and + MAX_PRICE_PER_GAS_UNIT to always satisfy the inequality that + MAXIMUM_NUMBER_OF_GAS_UNITS * MAX_PRICE_PER_GAS_UNIT < min(u64::MAX, GasUnits::MAX) +
+
+min_price_per_gas_unit: u64 +
+
+ The minimum gas price that a transaction can be submitted with. +
+
+max_price_per_gas_unit: u64 +
+
+ The maximum gas unit price that a transaction can be submitted with. +
+
+max_transaction_size_in_bytes: u64 +
+
+ The max transaction size in bytes that a transaction can have. +
+
+gas_unit_scaling_factor: u64 +
+
+ gas unit scaling factor. +
+
+default_account_size: u64 +
+
+ default account size. +
+
+ + +
+ + + +## Struct `GasCost` + +The GasCost tracks: +- instruction cost: how much time/computational power is needed to perform the instruction +- memory cost: how much memory is required for the instruction, and storage overhead + + +
struct GasCost has copy, drop, store
+
+ + + +
+Fields + + +
+
+instruction_gas: u64 +
+
+ +
+
+memory_gas: u64 +
+
+ +
+
+ + +
+ + + +## Function `instruction_schedule` + + + +
public fun instruction_schedule(): vector<VMConfig::GasCost>
+
+ + + +
+Implementation + + +
public fun instruction_schedule(): vector<GasCost> {
+    let table = Vector::empty();
+
+    // POP
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // RET
+    Vector::push_back(&mut table, new_gas_cost(638, 1));
+    // BR_TRUE
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // BR_FALSE
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // BRANCH
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LD_U64
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LD_CONST
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LD_TRUE
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LD_FALSE
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // COPY_LOC
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // MOVE_LOC
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // ST_LOC
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // MUT_BORROW_LOC
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // IMM_BORROW_LOC
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // MUT_BORROW_FIELD
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // IMM_BORROW_FIELD
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // CALL
+    Vector::push_back(&mut table, new_gas_cost(1132, 1));
+    // PACK
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // UNPACK
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // READ_REF
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // WRITE_REF
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // ADD
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // SUB
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // MUL
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // MOD
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // DIV
+    Vector::push_back(&mut table, new_gas_cost(3, 1));
+    // BIT_OR
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // BIT_AND
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // XOR
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // OR
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // AND
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // NOT
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // EQ
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // NEQ
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LT
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // GT
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LE
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // GE
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // ABORT
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // NOP
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // EXISTS
+    Vector::push_back(&mut table, new_gas_cost(41, 1));
+    // MUT_BORROW_GLOBAL
+    Vector::push_back(&mut table, new_gas_cost(21, 1));
+    // IML_BORROW_GLOBAL
+    Vector::push_back(&mut table, new_gas_cost(23, 1));
+    // MOVE_FROM
+    Vector::push_back(&mut table, new_gas_cost(459, 1));
+    // MOVE_TO
+    Vector::push_back(&mut table, new_gas_cost(13, 1));
+    // FREEZE_REF
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // SHL
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // SHR
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LD_U8
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // LD_U128
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+
+    // CAST_U8
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // CAST_U64
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // CAST_U128
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // MUT_BORORW_FIELD_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // IMM_BORORW_FIELD_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(1, 1));
+    // CALL_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(582, 1));
+    // PACK_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // UNPACK_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    // EXISTS_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(34, 1));
+    // MUT_BORROW_GLOBAL_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(15, 1));
+    // IMM_BORROW_GLOBAL_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(14, 1));
+    // MOVE_FROM_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(13, 1));
+    // MOVE_TO_GENERIC
+    Vector::push_back(&mut table, new_gas_cost(27, 1));
+
+    // VEC_PACK
+    Vector::push_back(&mut table, new_gas_cost(84, 1));
+    // VEC_LEN
+    Vector::push_back(&mut table, new_gas_cost(98, 1));
+    // VEC_IMM_BORROW
+    Vector::push_back(&mut table, new_gas_cost(1334, 1));
+    // VEC_MUT_BORROW
+    Vector::push_back(&mut table, new_gas_cost(1902, 1));
+    // VEC_PUSH_BACK
+    Vector::push_back(&mut table, new_gas_cost(53, 1));
+    // VEC_POP_BACK
+    Vector::push_back(&mut table, new_gas_cost(227, 1));
+    // VEC_UNPACK
+    Vector::push_back(&mut table, new_gas_cost(572, 1));
+    // VEC_SWAP
+    Vector::push_back(&mut table, new_gas_cost(1436, 1));
+    table
+}
+
+ + + +
+ + + +## Function `native_schedule` + + + +
public fun native_schedule(): vector<VMConfig::GasCost>
+
+ + + +
+Implementation + + +
public fun native_schedule(): vector<GasCost> {
+    let table = Vector::empty();
+    //Hash::sha2_256 0
+    Vector::push_back(&mut table, new_gas_cost(21, 1));
+    //Hash::sha3_256 1
+    Vector::push_back(&mut table, new_gas_cost(64, 1));
+    //Signature::ed25519_verify 2
+    Vector::push_back(&mut table, new_gas_cost(61, 1));
+    //ED25519_THRESHOLD_VERIFY 3 this native funciton is deprecated
+    Vector::push_back(&mut table, new_gas_cost(3351, 1));
+    //BSC::to_bytes 4
+    Vector::push_back(&mut table, new_gas_cost(181, 1));
+    //Vector::length 5
+    Vector::push_back(&mut table, new_gas_cost(98, 1));
+    //Vector::empty 6
+    Vector::push_back(&mut table, new_gas_cost(84, 1));
+    //Vector::borrow 7
+    Vector::push_back(&mut table, new_gas_cost(1334, 1));
+    //Vector::borrow_mut 8
+    Vector::push_back(&mut table, new_gas_cost(1902, 1));
+    //Vector::push_back 9
+    Vector::push_back(&mut table, new_gas_cost(53, 1));
+    //Vector::pop_back 10
+    Vector::push_back(&mut table, new_gas_cost(227, 1));
+    //Vector::destory_empty 11
+    Vector::push_back(&mut table, new_gas_cost(572, 1));
+    //Vector::swap 12
+    Vector::push_back(&mut table, new_gas_cost(1436, 1));
+    //Signature::ed25519_validate_pubkey 13
+    Vector::push_back(&mut table, new_gas_cost(26, 1));
+    //Signer::borrow_address 14
+    Vector::push_back(&mut table, new_gas_cost(353, 1));
+    //Account::creator_signer 15
+    Vector::push_back(&mut table, new_gas_cost(24, 1));
+    //Account::destroy_signer 16
+    Vector::push_back(&mut table, new_gas_cost(212, 1));
+    //Event::emit_event 17
+    Vector::push_back(&mut table, new_gas_cost(52, 1));
+    //BCS::to_address 18
+    Vector::push_back(&mut table, new_gas_cost(26, 1));
+    //Token::name_of 19
+    Vector::push_back(&mut table, new_gas_cost(2002, 1));
+    //Hash::keccak_256 20
+    Vector::push_back(&mut table, new_gas_cost(64, 1));
+    //Hash::ripemd160 21
+    Vector::push_back(&mut table, new_gas_cost(64, 1));
+    //Signature::native_ecrecover 22
+    Vector::push_back(&mut table, new_gas_cost(128, 1));
+    //U256::from_bytes 23
+    Vector::push_back(&mut table, new_gas_cost(2, 1));
+    //U256::add 24
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    //U256::sub 25
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    //U256::mul 26
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    //U256::div 27
+    Vector::push_back(&mut table, new_gas_cost(10, 1));
+    // U256::rem 28
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // U256::pow 29
+    Vector::push_back(&mut table, new_gas_cost(8, 1));
+    // TODO: settle down the gas cost
+    // Vector::append 30
+    Vector::push_back(&mut table, new_gas_cost(40, 1));
+    // Vector::remove 31
+    Vector::push_back(&mut table, new_gas_cost(20, 1));
+    // Vector::reverse 32
+    Vector::push_back(&mut table, new_gas_cost(10, 1));
+
+    // Table::new_table_handle 33
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // Table::add_box 34
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // Table::borrow_box 35
+    Vector::push_back(&mut table, new_gas_cost(10, 1));
+    // Table::remove_box 36
+    Vector::push_back(&mut table, new_gas_cost(8, 1));
+    // Table::contains_box 37
+    Vector::push_back(&mut table, new_gas_cost(40, 1));
+    // Table::destroy_empty_box 38
+    Vector::push_back(&mut table, new_gas_cost(20, 1));
+    // Table::drop_unchecked_box 39
+    Vector::push_back(&mut table, new_gas_cost(73, 1));
+    // string.check_utf8 40
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // string.sub_str 41
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // string.is_char_boundary 42
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // Table::string.index_of 43
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // FromBCS::from_bytes 44
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // Secp256k1::ecdsa_recover_internal 45
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+    // Vector::spawn_from 46
+    Vector::push_back(&mut table, new_gas_cost(4, 1));
+
+    table
+}
+
+ + + +
+ + + +## Function `gas_constants` + + + +
public fun gas_constants(): VMConfig::GasConstants
+
+ + + +
+Implementation + + +
public fun gas_constants(): GasConstants {
+    let min_price_per_gas_unit: u64 = if (ChainId::is_test()) { 0 }  else { 1 };
+    let maximum_number_of_gas_units: u64 = 40000000;//must less than base_block_gas_limit
+
+    if (ChainId::is_test() || ChainId::is_dev() || ChainId::is_halley()) {
+        maximum_number_of_gas_units = maximum_number_of_gas_units * 10
+    };
+    GasConstants {
+        global_memory_per_byte_cost: 4,
+        global_memory_per_byte_write_cost: 9,
+        min_transaction_gas_units: 600,
+        large_transaction_cutoff: 600,
+        instrinsic_gas_per_byte: 8,
+        maximum_number_of_gas_units,
+        min_price_per_gas_unit,
+        max_price_per_gas_unit: 10000,
+        max_transaction_size_in_bytes: 1024 * 128,
+        gas_unit_scaling_factor: 1,
+        default_account_size: 800,
+    }
+}
+
+ + + +
+ + + +## Function `new_gas_cost` + + + +
fun new_gas_cost(instr_gas: u64, mem_gas: u64): VMConfig::GasCost
+
+ + + +
+Implementation + + +
fun new_gas_cost(instr_gas: u64, mem_gas: u64): GasCost {
+    GasCost {
+        instruction_gas: instr_gas,
+        memory_gas: mem_gas,
+    }
+}
+
+ + + +
+ + + +## Function `new_vm_config` + +Create a new vm config, mainly used in DAO. + + +
public fun new_vm_config(instruction_schedule: vector<u8>, native_schedule: vector<u8>, global_memory_per_byte_cost: u64, global_memory_per_byte_write_cost: u64, min_transaction_gas_units: u64, large_transaction_cutoff: u64, instrinsic_gas_per_byte: u64, maximum_number_of_gas_units: u64, min_price_per_gas_unit: u64, max_price_per_gas_unit: u64, max_transaction_size_in_bytes: u64, gas_unit_scaling_factor: u64, default_account_size: u64): VMConfig::VMConfig
+
+ + + +
+Implementation + + +
public fun new_vm_config(
+    instruction_schedule: vector<u8>,
+    native_schedule: vector<u8>,
+    global_memory_per_byte_cost: u64,
+    global_memory_per_byte_write_cost: u64,
+    min_transaction_gas_units: u64,
+    large_transaction_cutoff: u64,
+    instrinsic_gas_per_byte: u64,
+    maximum_number_of_gas_units: u64,
+    min_price_per_gas_unit: u64,
+    max_price_per_gas_unit: u64,
+    max_transaction_size_in_bytes: u64,
+    gas_unit_scaling_factor: u64,
+    default_account_size: u64,
+): VMConfig {
+    let gas_constants = GasConstants {
+        global_memory_per_byte_cost,
+        global_memory_per_byte_write_cost,
+        min_transaction_gas_units,
+        large_transaction_cutoff,
+        instrinsic_gas_per_byte,
+        maximum_number_of_gas_units,
+        min_price_per_gas_unit,
+        max_price_per_gas_unit,
+        max_transaction_size_in_bytes,
+        gas_unit_scaling_factor,
+        default_account_size,
+    };
+    VMConfig {
+        gas_schedule: GasSchedule { instruction_schedule, native_schedule, gas_constants },
+    }
+}
+
+ + + +
+ + + +## Function `initialize` + +Initialize the table under the genesis account + + +
public fun initialize(account: &signer, instruction_schedule: vector<u8>, native_schedule: vector<u8>, global_memory_per_byte_cost: u64, global_memory_per_byte_write_cost: u64, min_transaction_gas_units: u64, large_transaction_cutoff: u64, instrinsic_gas_per_byte: u64, maximum_number_of_gas_units: u64, min_price_per_gas_unit: u64, max_price_per_gas_unit: u64, max_transaction_size_in_bytes: u64, gas_unit_scaling_factor: u64, default_account_size: u64)
+
+ + + +
+Implementation + + +
public fun initialize(
+    account: &signer,
+    instruction_schedule: vector<u8>,
+    native_schedule: vector<u8>,
+    global_memory_per_byte_cost: u64,
+    global_memory_per_byte_write_cost: u64,
+    min_transaction_gas_units: u64,
+    large_transaction_cutoff: u64,
+    instrinsic_gas_per_byte: u64,
+    maximum_number_of_gas_units: u64,
+    min_price_per_gas_unit: u64,
+    max_price_per_gas_unit: u64,
+    max_transaction_size_in_bytes: u64,
+    gas_unit_scaling_factor: u64,
+    default_account_size: u64,
+) {
+    CoreAddresses::assert_genesis_address(account);
+    Config::publish_new_config<VMConfig>(
+        account,
+        new_vm_config(
+            instruction_schedule,
+            native_schedule,
+            global_memory_per_byte_cost,
+            global_memory_per_byte_write_cost,
+            min_transaction_gas_units,
+            large_transaction_cutoff,
+            instrinsic_gas_per_byte,
+            maximum_number_of_gas_units,
+            min_price_per_gas_unit,
+            max_price_per_gas_unit,
+            max_transaction_size_in_bytes,
+            gas_unit_scaling_factor,
+            default_account_size,
+        ),
+    );
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<Config::Config<VMConfig>>(Signer::address_of(account));
+aborts_if
+    exists<Config::ModifyConfigCapabilityHolder<VMConfig>>(
+        Signer::address_of(account),
+    );
+ensures exists<Config::Config<VMConfig>>(Signer::address_of(account));
+ensures
+    exists<Config::ModifyConfigCapabilityHolder<VMConfig>>(
+        Signer::address_of(account),
+    );
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/Vector.md b/release/v13/docs/Vector.md new file mode 100644 index 00000000..5ad6187f --- /dev/null +++ b/release/v13/docs/Vector.md @@ -0,0 +1,861 @@ + + + +# Module `0x1::Vector` + +A variable-sized container that can hold any type. Indexing is 0-based, and +vectors are growable. This module has many native functions. +Verification of modules that use this one uses model functions that are implemented +directly in Boogie. The specification language has built-in functions operations such +as vec. There are some helper functions defined here for specifications in other +modules as well. + +>Note: We did not verify most of the +Move functions here because many have loops, requiring loop invariants to prove, and +the return on investment didn't seem worth it for these simple functions. + + +- [Constants](#@Constants_0) +- [Function `empty`](#0x1_Vector_empty) +- [Function `length`](#0x1_Vector_length) +- [Function `borrow`](#0x1_Vector_borrow) +- [Function `push_back`](#0x1_Vector_push_back) +- [Function `borrow_mut`](#0x1_Vector_borrow_mut) +- [Function `pop_back`](#0x1_Vector_pop_back) +- [Function `destroy_empty`](#0x1_Vector_destroy_empty) +- [Function `spawn_from`](#0x1_Vector_spawn_from) +- [Function `spawn_from_vec`](#0x1_Vector_spawn_from_vec) +- [Function `swap`](#0x1_Vector_swap) +- [Function `singleton`](#0x1_Vector_singleton) +- [Function `reverse`](#0x1_Vector_reverse) +- [Function `native_reverse`](#0x1_Vector_native_reverse) +- [Function `append`](#0x1_Vector_append) +- [Function `native_append`](#0x1_Vector_native_append) +- [Function `is_empty`](#0x1_Vector_is_empty) +- [Function `contains`](#0x1_Vector_contains) +- [Function `index_of`](#0x1_Vector_index_of) +- [Function `remove`](#0x1_Vector_remove) +- [Function `native_remove`](#0x1_Vector_native_remove) +- [Function `swap_remove`](#0x1_Vector_swap_remove) +- [Function `split`](#0x1_Vector_split) +- [Module Specification](#@Module_Specification_1) + - [Helper Functions](#@Helper_Functions_2) + + +
+ + + + + +## Constants + + + + +The index into the vector is out of bounds + + +
const EINDEX_OUT_OF_BOUNDS: u64 = 0;
+
+ + + + + +## Function `empty` + +Create an empty vector. + + +
public fun empty<Element>(): vector<Element>
+
+ + + +
+Implementation + + +
native public fun empty<Element>(): vector<Element>;
+
+ + + +
+ + + +## Function `length` + +Return the length of the vector. + + +
public fun length<Element>(v: &vector<Element>): u64
+
+ + + +
+Implementation + + +
native public fun length<Element>(v: &vector<Element>): u64;
+
+ + + +
+ + + +## Function `borrow` + +Acquire an immutable reference to the ith element of the vector v. +Aborts if i is out of bounds. + + +
public fun borrow<Element>(v: &vector<Element>, i: u64): &Element
+
+ + + +
+Implementation + + +
native public fun borrow<Element>(v: &vector<Element>, i: u64): ∈
+
+ + + +
+ + + +## Function `push_back` + +Add element e to the end of the vector v. + + +
public fun push_back<Element>(v: &mut vector<Element>, e: Element)
+
+ + + +
+Implementation + + +
native public fun push_back<Element>(v: &mut vector<Element>, e: Element);
+
+ + + +
+ + + +## Function `borrow_mut` + +Return a mutable reference to the ith element in the vector v. +Aborts if i is out of bounds. + + +
public fun borrow_mut<Element>(v: &mut vector<Element>, i: u64): &mut Element
+
+ + + +
+Implementation + + +
native public fun borrow_mut<Element>(v: &mut vector<Element>, i: u64): &mut Element;
+
+ + + +
+ + + +## Function `pop_back` + +Pop an element from the end of vector v. +Aborts if v is empty. + + +
public fun pop_back<Element>(v: &mut vector<Element>): Element
+
+ + + +
+Implementation + + +
native public fun pop_back<Element>(v: &mut vector<Element>): Element;
+
+ + + +
+ + + +## Function `destroy_empty` + +Destroy the vector v. +Aborts if v is not empty. + + +
public fun destroy_empty<Element>(v: vector<Element>)
+
+ + + +
+Implementation + + +
native public fun destroy_empty<Element>(v: vector<Element>);
+
+ + + +
+ + + +## Function `spawn_from` + +Spawn a sub vector from a vector + + +
fun spawn_from<Element>(v: &vector<Element>, offset: u64, size: u64): vector<Element>
+
+ + + +
+Implementation + + +
native fun spawn_from<Element>(v: &vector<Element>, offset: u64, size: u64): vector<Element>;
+
+ + + +
+ +
+Specification + + + +
pragma opaque;
+ensures [abstract] result == v[offset..offset+size];
+
+ + + +
+ + + +## Function `spawn_from_vec` + + + +
public fun spawn_from_vec<Element: copy>(v: &vector<Element>, offset: u64, size: u64): vector<Element>
+
+ + + +
+Implementation + + +
public fun spawn_from_vec<Element: copy>(v: &vector<Element>, offset: u64, size: u64): vector<Element> {
+    let len = length(v);
+    let end_idx = (offset + size);
+    assert!(end_idx <= len, EINDEX_OUT_OF_BOUNDS);
+    assert!(size > 0, EINDEX_OUT_OF_BOUNDS);
+    if (offset == 0 && end_idx == len) {
+        return *v
+    };
+    spawn_from(v, offset, size)
+}
+
+ + + +
+ + + +## Function `swap` + +Swaps the elements at the ith and jth indices in the vector v. +Aborts if ior j is out of bounds. + + +
public fun swap<Element>(v: &mut vector<Element>, i: u64, j: u64)
+
+ + + +
+Implementation + + +
native public fun swap<Element>(v: &mut vector<Element>, i: u64, j: u64);
+
+ + + +
+ + + +## Function `singleton` + +Return an vector of size one containing element e. + + +
public fun singleton<Element>(e: Element): vector<Element>
+
+ + + +
+Implementation + + +
public fun singleton<Element>(e: Element): vector<Element> {
+    let v = empty();
+    push_back(&mut v, e);
+    v
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+ensures result == vec(e);
+
+ + + + + + + +
fun spec_singleton<Element>(e: Element): vector<Element> {
+   vec(e)
+}
+
+ + + +
+ + + +## Function `reverse` + +Reverses the order of the elements in the vector v in place. + + +
public fun reverse<Element>(v: &mut vector<Element>)
+
+ + + +
+Implementation + + +
public fun reverse<Element>(v: &mut vector<Element>) {
+    native_reverse(v)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `native_reverse` + + + +
fun native_reverse<Element>(this: &mut vector<Element>)
+
+ + + +
+Implementation + + +
native fun native_reverse<Element>(this: &mut vector<Element>);
+
+ + + +
+ + + +## Function `append` + +Pushes all of the elements of the other vector into the lhs vector. + + +
public fun append<Element>(lhs: &mut vector<Element>, other: vector<Element>)
+
+ + + +
+Implementation + + +
public fun append<Element>(lhs: &mut vector<Element>, other: vector<Element>) {
+    native_append(lhs, other);
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `native_append` + + + +
fun native_append<Element>(lhs: &mut vector<Element>, other: vector<Element>)
+
+ + + +
+Implementation + + +
native fun native_append<Element>(lhs: &mut vector<Element>, other: vector<Element>);
+
+ + + +
+ + + +## Function `is_empty` + +Return true if the vector v has no elements and false otherwise. + + +
public fun is_empty<Element>(v: &vector<Element>): bool
+
+ + + +
+Implementation + + +
public fun is_empty<Element>(v: &vector<Element>): bool {
+    length(v) == 0
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `contains` + +Return true if e is in the vector v. + + +
public fun contains<Element>(v: &vector<Element>, e: &Element): bool
+
+ + + +
+Implementation + + +
public fun contains<Element>(v: &vector<Element>, e: &Element): bool {
+    let i = 0;
+    let len = length(v);
+    while (i < len) {
+        if (borrow(v, i) == e) return true;
+        i = i + 1;
+    };
+    false
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `index_of` + +Return (true, i) if e is in the vector v at index i. +Otherwise, returns (false, 0). + + +
public fun index_of<Element>(v: &vector<Element>, e: &Element): (bool, u64)
+
+ + + +
+Implementation + + +
public fun index_of<Element>(v: &vector<Element>, e: &Element): (bool, u64) {
+    let i = 0;
+    let len = length(v);
+    while (i < len) {
+        if (borrow(v, i) == e) return (true, i);
+        i = i + 1;
+    };
+    (false, 0)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `remove` + +Remove the ith element of the vector v, shifting all subsequent elements. +This is O(n) and preserves ordering of elements in the vector. +Aborts if i is out of bounds. + + +
public fun remove<Element>(v: &mut vector<Element>, i: u64): Element
+
+ + + +
+Implementation + + +
public fun remove<Element>(v: &mut vector<Element>, i: u64): Element {
+    let len = length(v);
+    // i out of bounds; abort
+    if (i >= len) abort EINDEX_OUT_OF_BOUNDS;
+
+    native_remove(v, i)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `native_remove` + + + +
fun native_remove<Element>(this: &mut vector<Element>, i: u64): Element
+
+ + + +
+Implementation + + +
native fun native_remove<Element>(this: &mut vector<Element>, i: u64): Element;
+
+ + + +
+ + + +## Function `swap_remove` + +Swap the ith element of the vector v with the last element and then pop the vector. +This is O(1), but does not preserve ordering of elements in the vector. +Aborts if i is out of bounds. + + +
public fun swap_remove<Element>(v: &mut vector<Element>, i: u64): Element
+
+ + + +
+Implementation + + +
public fun swap_remove<Element>(v: &mut vector<Element>, i: u64): Element {
+    let last_idx = length(v) - 1;
+    swap(v, i, last_idx);
+    pop_back(v)
+}
+
+ + + +
+ +
+Specification + + + +
pragma intrinsic = true;
+
+ + + +
+ + + +## Function `split` + +Split a vector into sub-vectors of size sub_len, + + +
public fun split<Element: copy, drop, store>(v: &vector<Element>, sub_len: u64): vector<vector<Element>>
+
+ + + +
+Implementation + + +
public fun split<Element: copy + drop + store>(v: &vector<Element>, sub_len: u64): vector<vector<Element>> {
+    let result = empty<vector<Element>>();
+    let len = length(v) / sub_len;
+
+    let rem = 0;
+    if (len * sub_len < length(v)) {
+        rem = length(v) - len * sub_len;
+    };
+
+    let i = 0;
+    while (i < len) {
+        let sub = empty<Element>();
+        let j = 0;
+        while (j < sub_len) {
+            let index = sub_len * i + j;
+            push_back(&mut sub, *borrow(v, index));
+            j = j + 1;
+        };
+        push_back<vector<Element>>(&mut result, sub);
+        i = i + 1;
+    };
+
+    if (rem > 0) {
+        let sub = empty<Element>();
+        let index = length(v) - rem;
+        while (index < length(v)) {
+            push_back(&mut sub, *borrow(v, index));
+            index = index + 1;
+        };
+        push_back<vector<Element>>(&mut result, sub);
+    };
+    result
+}
+
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+aborts_if sub_len == 0;
+
+ + + +
+ + + +## Module Specification + + + + + +### Helper Functions + +Check whether a vector contains an element. + + + + + +
fun spec_contains<Element>(v: vector<Element>, e: Element): bool {
+   exists x in v: x == e
+}
+
+ + +Check if v1 is equal to the result of adding e at the end of v2 + + + + + +
fun eq_push_back<Element>(v1: vector<Element>, v2: vector<Element>, e: Element): bool {
+   len(v1) == len(v2) + 1 &&
+   v1[len(v1)-1] == e &&
+   v1[0..len(v1)-1] == v2[0..len(v2)]
+}
+
+ + +Check if v is equal to the result of concatenating v1 and v2 + + + + + +
fun eq_append<Element>(v: vector<Element>, v1: vector<Element>, v2: vector<Element>): bool {
+   len(v) == len(v1) + len(v2) &&
+   v[0..len(v1)] == v1 &&
+   v[len(v1)..len(v)] == v2
+}
+
+ + +Check v1 is equal to the result of removing the first element of v2 + + + + + +
fun eq_pop_front<Element>(v1: vector<Element>, v2: vector<Element>): bool {
+   len(v1) + 1 == len(v2) &&
+   v1 == v2[1..len(v2)]
+}
+
+ + +Check that v1 is equal to the result of removing the element at index i from v2. + + + + + +
fun eq_remove_elem_at_index<Element>(i: u64, v1: vector<Element>, v2: vector<Element>): bool {
+   len(v1) + 1 == len(v2) &&
+   v1[0..i] == v2[0..i] &&
+   v1[i..len(v1)] == v2[i + 1..len(v2)]
+}
+
diff --git a/release/v13/docs/Version.md b/release/v13/docs/Version.md new file mode 100644 index 00000000..64012d09 --- /dev/null +++ b/release/v13/docs/Version.md @@ -0,0 +1,146 @@ + + + +# Module `0x1::Version` + +Version tracks version of something, like current VM version. + + +- [Struct `Version`](#0x1_Version_Version) +- [Constants](#@Constants_0) +- [Function `new_version`](#0x1_Version_new_version) +- [Function `get`](#0x1_Version_get) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Config;
+
+ + + + + +## Struct `Version` + +Version. + + +
struct Version has copy, drop, store
+
+ + + +
+Fields + + +
+
+major: u64 +
+
+ major number. +
+
+ + +
+ + + +## Constants + + + + + + +
const EMAJOR_TO_OLD: u64 = 101;
+
+ + + + + +## Function `new_version` + +Create a new version. + + +
public fun new_version(major: u64): Version::Version
+
+ + + +
+Implementation + + +
public fun new_version(major: u64): Version {
+    Version { major }
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if false;
+
+ + + +
+ + + +## Function `get` + +Get version under addr. + + +
public fun get(addr: address): u64
+
+ + + +
+Implementation + + +
public fun get(addr: address): u64 {
+    let version = Config::get_by_address<Self::Version>(addr);
+    version.major
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if !exists<Config::Config<Version>>(addr);
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify;
+pragma aborts_if_is_strict;
+
diff --git a/release/v13/docs/YieldFarming.md b/release/v13/docs/YieldFarming.md new file mode 100644 index 00000000..e1535fd0 --- /dev/null +++ b/release/v13/docs/YieldFarming.md @@ -0,0 +1,886 @@ + + + +# Module `0x1::YieldFarming` + + + +- [Resource `Farming`](#0x1_YieldFarming_Farming) +- [Resource `FarmingAsset`](#0x1_YieldFarming_FarmingAsset) +- [Resource `ParameterModifyCapability`](#0x1_YieldFarming_ParameterModifyCapability) +- [Resource `Stake`](#0x1_YieldFarming_Stake) +- [Struct `Exp`](#0x1_YieldFarming_Exp) +- [Constants](#@Constants_0) +- [Function `exp`](#0x1_YieldFarming_exp) +- [Function `mul_u128`](#0x1_YieldFarming_mul_u128) +- [Function `div_u128`](#0x1_YieldFarming_div_u128) +- [Function `truncate`](#0x1_YieldFarming_truncate) +- [Function `initialize`](#0x1_YieldFarming_initialize) +- [Function `initialize_asset`](#0x1_YieldFarming_initialize_asset) +- [Function `modify_parameter`](#0x1_YieldFarming_modify_parameter) +- [Function `stake`](#0x1_YieldFarming_stake) +- [Function `unstake`](#0x1_YieldFarming_unstake) +- [Function `harvest`](#0x1_YieldFarming_harvest) +- [Function `query_gov_token_amount`](#0x1_YieldFarming_query_gov_token_amount) +- [Function `query_total_stake`](#0x1_YieldFarming_query_total_stake) +- [Function `query_stake`](#0x1_YieldFarming_query_stake) +- [Function `calculate_harvest_index_with_asset`](#0x1_YieldFarming_calculate_harvest_index_with_asset) +- [Function `calculate_harvest_index_weight_zero`](#0x1_YieldFarming_calculate_harvest_index_weight_zero) +- [Function `calculate_harvest_index`](#0x1_YieldFarming_calculate_harvest_index) +- [Function `calculate_withdraw_amount`](#0x1_YieldFarming_calculate_withdraw_amount) +- [Function `exists_at`](#0x1_YieldFarming_exists_at) +- [Function `exists_asset_at`](#0x1_YieldFarming_exists_asset_at) +- [Function `exists_stake_at_address`](#0x1_YieldFarming_exists_stake_at_address) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Token;
+
+ + + + + +## Resource `Farming` + +The object of yield farming +RewardTokenT meaning token of yield farming + + +
struct Farming<PoolType, RewardTokenT> has store, key
+
+ + + +
+Fields + + +
+
+treasury_token: Token::Token<RewardTokenT> +
+
+ +
+
+ + +
+ + + +## Resource `FarmingAsset` + + + +
struct FarmingAsset<PoolType, AssetT> has store, key
+
+ + + +
+Fields + + +
+
+asset_total_weight: u128 +
+
+ +
+
+harvest_index: u128 +
+
+ +
+
+last_update_timestamp: u64 +
+
+ +
+
+release_per_second: u128 +
+
+ +
+
+start_time: u64 +
+
+ +
+
+ + +
+ + + +## Resource `ParameterModifyCapability` + +Capability to modify parameter such as period and release amount + + +
struct ParameterModifyCapability<PoolType, AssetT> has store, key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Resource `Stake` + +To store user's asset token + + +
struct Stake<PoolType, AssetT> has store, key
+
+ + + +
+Fields + + +
+
+asset: AssetT +
+
+ +
+
+asset_weight: u128 +
+
+ +
+
+last_harvest_index: u128 +
+
+ +
+
+gain: u128 +
+
+ +
+
+ + +
+ + + +## Struct `Exp` + + + +
struct Exp has copy, drop, store
+
+ + + +
+Fields + + +
+
+mantissa: u128 +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const EDEPRECATED_FUNCTION: u64 = 19;
+
+ + + + + + + +
const ERR_EXP_DIVIDE_BY_ZERO: u64 = 107;
+
+ + + + + + + +
const ERR_FARMING_BALANCE_EXCEEDED: u64 = 108;
+
+ + + + + + + +
const ERR_FARMING_HAVERST_NO_GAIN: u64 = 105;
+
+ + + + + + + +
const ERR_FARMING_INIT_REPEATE: u64 = 101;
+
+ + + + + + + +
const ERR_FARMING_NOT_ENOUGH_ASSET: u64 = 109;
+
+ + + + + + + +
const ERR_FARMING_NOT_STILL_FREEZE: u64 = 102;
+
+ + + + + + + +
const ERR_FARMING_STAKE_EXISTS: u64 = 103;
+
+ + + + + + + +
const ERR_FARMING_STAKE_NOT_EXISTS: u64 = 104;
+
+ + + + + + + +
const ERR_FARMING_TIMESTAMP_INVALID: u64 = 110;
+
+ + + + + + + +
const ERR_FARMING_TOTAL_WEIGHT_IS_ZERO: u64 = 106;
+
+ + + + + + + +
const EXP_SCALE: u128 = 1000000000000000000;
+
+ + + + + +## Function `exp` + + + +
fun exp(num: u128, denom: u128): YieldFarming::Exp
+
+ + + +
+Implementation + + +
fun exp(num: u128, denom: u128): Exp {
+    // if overflow move will abort
+    let scaledNumerator = mul_u128(num, EXP_SCALE);
+    let rational = div_u128(scaledNumerator, denom);
+    Exp {
+        mantissa: rational
+    }
+}
+
+ + + +
+ + + +## Function `mul_u128` + + + +
fun mul_u128(a: u128, b: u128): u128
+
+ + + +
+Implementation + + +
fun mul_u128(a: u128, b: u128): u128 {
+    if (a == 0 || b == 0) {
+        return 0
+    };
+
+    a * b
+}
+
+ + + +
+ + + +## Function `div_u128` + + + +
fun div_u128(a: u128, b: u128): u128
+
+ + + +
+Implementation + + +
fun div_u128(a: u128, b: u128): u128 {
+    if ( b == 0) {
+        abort Errors::invalid_argument(ERR_EXP_DIVIDE_BY_ZERO)
+    };
+    if (a == 0) {
+        return 0
+    };
+    a / b
+}
+
+ + + +
+ + + +## Function `truncate` + + + +
fun truncate(exp: YieldFarming::Exp): u128
+
+ + + +
+Implementation + + +
fun truncate(exp: Exp): u128 {
+    return exp.mantissa / EXP_SCALE
+}
+
+ + + +
+ + + +## Function `initialize` + +Called by token issuer +this will declare a yield farming pool + + +
public fun initialize<PoolType: store, RewardTokenT: store>(_account: &signer, _treasury_token: Token::Token<RewardTokenT>)
+
+ + + +
+Implementation + + +
public fun initialize<
+    PoolType: store,
+    RewardTokenT: store>(_account: &signer,
+                         _treasury_token: Token::Token<RewardTokenT>) {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ + + +## Function `initialize_asset` + + + +
public fun initialize_asset<PoolType: store, AssetT: store>(_account: &signer, _release_per_second: u128, _delay: u64): YieldFarming::ParameterModifyCapability<PoolType, AssetT>
+
+ + + +
+Implementation + + +
public fun initialize_asset<PoolType: store, AssetT: store>(
+    _account: &signer,
+    _release_per_second: u128,
+    _delay: u64): ParameterModifyCapability<PoolType, AssetT> {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ + + +## Function `modify_parameter` + + + +
public fun modify_parameter<PoolType: store, RewardTokenT: store, AssetT: store>(_cap: &YieldFarming::ParameterModifyCapability<PoolType, AssetT>, _broker: address, _release_per_second: u128)
+
+ + + +
+Implementation + + +
public fun modify_parameter<PoolType: store, RewardTokenT: store, AssetT: store>(
+    _cap: &ParameterModifyCapability<PoolType, AssetT>,
+    _broker: address,
+    _release_per_second: u128) {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ + + +## Function `stake` + +Call by stake user, staking amount of asset in order to get yield farming token + + +
public fun stake<PoolType: store, RewardTokenT: store, AssetT: store>(_account: &signer, _broker: address, _asset: AssetT, _asset_weight: u128)
+
+ + + +
+Implementation + + +
public fun stake<PoolType: store, RewardTokenT: store, AssetT: store>(
+    _account: &signer,
+    _broker: address,
+    _asset: AssetT,
+    _asset_weight: u128) {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ + + +## Function `unstake` + +Unstake asset from farming pool + + +
public fun unstake<PoolType: store, RewardTokenT: store, AssetT: store>(_account: &signer, _broker: address): (AssetT, Token::Token<RewardTokenT>)
+
+ + + +
+Implementation + + +
public fun unstake<PoolType: store, RewardTokenT: store, AssetT: store>(_account: &signer, _broker: address)
+: (AssetT, Token::Token<RewardTokenT>) {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ + + +## Function `harvest` + +Harvest yield farming token from stake + + +
public fun harvest<PoolType: store, RewardTokenT: store, AssetT: store>(_account: &signer, _broker: address, _amount: u128): Token::Token<RewardTokenT>
+
+ + + +
+Implementation + + +
public fun harvest<PoolType: store,
+                   RewardTokenT: store,
+                   AssetT: store>(
+    _account: &signer,
+    _broker: address,
+    _amount: u128): Token::Token<RewardTokenT> {
+    abort Errors::deprecated(EDEPRECATED_FUNCTION)
+}
+
+ + + +
+ + + +## Function `query_gov_token_amount` + +The user can quering all yield farming amount in any time and scene + + +
public fun query_gov_token_amount<PoolType: store, RewardTokenT: store, AssetT: store>(_account: &signer, _broker: address): u128
+
+ + + +
+Implementation + + +
public fun query_gov_token_amount<PoolType: store,
+                                  RewardTokenT: store,
+                                  AssetT: store>(_account: &signer, _broker: address): u128 {
+    0
+}
+
+ + + +
+ + + +## Function `query_total_stake` + +Query total stake count from yield farming resource + + +
public fun query_total_stake<PoolType: store, AssetT: store>(_broker: address): u128
+
+ + + +
+Implementation + + +
public fun query_total_stake<PoolType: store,
+                             AssetT: store>(_broker: address): u128 {
+    0
+}
+
+ + + +
+ + + +## Function `query_stake` + +Query stake weight from user staking objects. + + +
public fun query_stake<PoolType: store, AssetT: store>(_account: &signer): u128
+
+ + + +
+Implementation + + +
public fun query_stake<PoolType: store,
+                       AssetT: store>(_account: &signer): u128 {
+    0
+}
+
+ + + +
+ + + +## Function `calculate_harvest_index_with_asset` + +Update farming asset + + +
fun calculate_harvest_index_with_asset<PoolType, AssetT>(_farming_asset: &YieldFarming::FarmingAsset<PoolType, AssetT>, _now_seconds: u64): u128
+
+ + + +
+Implementation + + +
fun calculate_harvest_index_with_asset<PoolType, AssetT>(_farming_asset: &FarmingAsset<PoolType, AssetT>, _now_seconds: u64): u128 {
+    0
+}
+
+ + + +
+ + + +## Function `calculate_harvest_index_weight_zero` + +There is calculating from harvest index and global parameters without asset_total_weight + + +
public fun calculate_harvest_index_weight_zero(_harvest_index: u128, _last_update_timestamp: u64, _now_seconds: u64, _release_per_second: u128): u128
+
+ + + +
+Implementation + + +
public fun calculate_harvest_index_weight_zero(_harvest_index: u128,
+                                               _last_update_timestamp: u64,
+                                               _now_seconds: u64,
+                                               _release_per_second: u128): u128 {
+    0
+}
+
+ + + +
+ + + +## Function `calculate_harvest_index` + +There is calculating from harvest index and global parameters + + +
public fun calculate_harvest_index(_harvest_index: u128, _asset_total_weight: u128, _last_update_timestamp: u64, _now_seconds: u64, _release_per_second: u128): u128
+
+ + + +
+Implementation + + +
public fun calculate_harvest_index(_harvest_index: u128,
+                                   _asset_total_weight: u128,
+                                   _last_update_timestamp: u64,
+                                   _now_seconds: u64,
+                                   _release_per_second: u128): u128 {
+    0
+}
+
+ + + +
+ + + +## Function `calculate_withdraw_amount` + +This function will return a gain index + + +
public fun calculate_withdraw_amount(_harvest_index: u128, _last_harvest_index: u128, _asset_weight: u128): u128
+
+ + + +
+Implementation + + +
public fun calculate_withdraw_amount(_harvest_index: u128,
+                                     _last_harvest_index: u128,
+                                     _asset_weight: u128): u128 {
+    0
+}
+
+ + + +
+ + + +## Function `exists_at` + +Check the Farming of TokenT is exists. + + +
public fun exists_at<PoolType: store, RewardTokenT: store>(broker: address): bool
+
+ + + +
+Implementation + + +
public fun exists_at<PoolType: store, RewardTokenT: store>(broker: address): bool {
+    exists<Farming<PoolType, RewardTokenT>>(broker)
+}
+
+ + + +
+ + + +## Function `exists_asset_at` + +Check the Farming of AsssetT is exists. + + +
public fun exists_asset_at<PoolType: store, AssetT: store>(broker: address): bool
+
+ + + +
+Implementation + + +
public fun exists_asset_at<PoolType: store, AssetT: store>(broker: address): bool {
+    exists<FarmingAsset<PoolType, AssetT>>(broker)
+}
+
+ + + +
+ + + +## Function `exists_stake_at_address` + +Check stake at address exists. + + +
public fun exists_stake_at_address<PoolType: store, AssetT: store>(account: address): bool
+
+ + + +
+Implementation + + +
public fun exists_stake_at_address<PoolType: store, AssetT: store>(account: address): bool {
+    exists<Stake<PoolType, AssetT>>(account)
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+
diff --git a/release/v13/docs/YieldFarmingV2.md b/release/v13/docs/YieldFarmingV2.md new file mode 100644 index 00000000..f6d77651 --- /dev/null +++ b/release/v13/docs/YieldFarmingV2.md @@ -0,0 +1,1429 @@ + + + +# Module `0x1::YieldFarmingV2` + + + +- [Struct `Exp`](#0x1_YieldFarmingV2_Exp) +- [Resource `Farming`](#0x1_YieldFarmingV2_Farming) +- [Resource `FarmingAsset`](#0x1_YieldFarmingV2_FarmingAsset) +- [Resource `Stake`](#0x1_YieldFarmingV2_Stake) +- [Resource `ParameterModifyCapability`](#0x1_YieldFarmingV2_ParameterModifyCapability) +- [Resource `HarvestCapability`](#0x1_YieldFarmingV2_HarvestCapability) +- [Constants](#@Constants_0) +- [Function `exp_direct`](#0x1_YieldFarmingV2_exp_direct) +- [Function `exp_direct_expand`](#0x1_YieldFarmingV2_exp_direct_expand) +- [Function `mantissa`](#0x1_YieldFarmingV2_mantissa) +- [Function `add_exp`](#0x1_YieldFarmingV2_add_exp) +- [Function `exp`](#0x1_YieldFarmingV2_exp) +- [Function `add_u128`](#0x1_YieldFarmingV2_add_u128) +- [Function `sub_u128`](#0x1_YieldFarmingV2_sub_u128) +- [Function `mul_u128`](#0x1_YieldFarmingV2_mul_u128) +- [Function `div_u128`](#0x1_YieldFarmingV2_div_u128) +- [Function `truncate`](#0x1_YieldFarmingV2_truncate) +- [Function `initialize`](#0x1_YieldFarmingV2_initialize) +- [Function `add_asset`](#0x1_YieldFarmingV2_add_asset) +- [Function `modify_parameter`](#0x1_YieldFarmingV2_modify_parameter) +- [Function `stake`](#0x1_YieldFarmingV2_stake) +- [Function `stake_for_cap`](#0x1_YieldFarmingV2_stake_for_cap) +- [Function `unstake`](#0x1_YieldFarmingV2_unstake) +- [Function `unstake_with_cap`](#0x1_YieldFarmingV2_unstake_with_cap) +- [Function `harvest`](#0x1_YieldFarmingV2_harvest) +- [Function `harvest_with_cap`](#0x1_YieldFarmingV2_harvest_with_cap) +- [Function `query_gov_token_amount`](#0x1_YieldFarmingV2_query_gov_token_amount) +- [Function `query_total_stake`](#0x1_YieldFarmingV2_query_total_stake) +- [Function `query_stake`](#0x1_YieldFarmingV2_query_stake) +- [Function `query_info`](#0x1_YieldFarmingV2_query_info) +- [Function `calculate_harvest_index_with_asset`](#0x1_YieldFarmingV2_calculate_harvest_index_with_asset) +- [Function `calculate_harvest_index_weight_zero`](#0x1_YieldFarmingV2_calculate_harvest_index_weight_zero) +- [Function `calculate_harvest_index`](#0x1_YieldFarmingV2_calculate_harvest_index) +- [Function `calculate_withdraw_amount`](#0x1_YieldFarmingV2_calculate_withdraw_amount) +- [Function `exists_at`](#0x1_YieldFarmingV2_exists_at) +- [Function `exists_asset_at`](#0x1_YieldFarmingV2_exists_asset_at) +- [Function `exists_stake_at_address`](#0x1_YieldFarmingV2_exists_stake_at_address) +- [Module Specification](#@Module_Specification_1) + + +
use 0x1::Errors;
+use 0x1::Math;
+use 0x1::Signer;
+use 0x1::Timestamp;
+use 0x1::Token;
+
+ + + + + +## Struct `Exp` + + + +
struct Exp has copy, drop, store
+
+ + + +
+Fields + + +
+
+mantissa: u128 +
+
+ +
+
+ + +
+ + + +## Resource `Farming` + +The object of yield farming +RewardTokenT meaning token of yield farming + + +
struct Farming<PoolType, RewardTokenT> has store, key
+
+ + + +
+Fields + + +
+
+treasury_token: Token::Token<RewardTokenT> +
+
+ +
+
+ + +
+ + + +## Resource `FarmingAsset` + + + +
struct FarmingAsset<PoolType, AssetT> has store, key
+
+ + + +
+Fields + + +
+
+asset_total_weight: u128 +
+
+ +
+
+harvest_index: u128 +
+
+ +
+
+last_update_timestamp: u64 +
+
+ +
+
+release_per_second: u128 +
+
+ +
+
+start_time: u64 +
+
+ +
+
+alive: bool +
+
+ +
+
+ + +
+ + + +## Resource `Stake` + +To store user's asset token + + +
struct Stake<PoolType, AssetT> has store, key
+
+ + + +
+Fields + + +
+
+asset: AssetT +
+
+ +
+
+asset_weight: u128 +
+
+ +
+
+last_harvest_index: u128 +
+
+ +
+
+gain: u128 +
+
+ +
+
+ + +
+ + + +## Resource `ParameterModifyCapability` + +Capability to modify parameter such as period and release amount + + +
struct ParameterModifyCapability<PoolType, AssetT> has store, key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ + +
+ + + +## Resource `HarvestCapability` + +Harvest ability to harvest + + +
struct HarvestCapability<PoolType, AssetT> has store, key
+
+ + + +
+Fields + + +
+
+trigger: address +
+
+ +
+
+ + +
+ + + +## Constants + + + + + + +
const ERR_EXP_DIVIDE_BY_ZERO: u64 = 107;
+
+ + + + + + + +
const ERR_FARMING_BALANCE_EXCEEDED: u64 = 108;
+
+ + + + + + + +
const ERR_FARMING_HAVERST_NO_GAIN: u64 = 105;
+
+ + + + + + + +
const ERR_FARMING_INIT_REPEATE: u64 = 101;
+
+ + + + + + + +
const ERR_FARMING_NOT_ENOUGH_ASSET: u64 = 109;
+
+ + + + + + + +
const ERR_FARMING_NOT_STILL_FREEZE: u64 = 102;
+
+ + + + + + + +
const ERR_FARMING_STAKE_EXISTS: u64 = 103;
+
+ + + + + + + +
const ERR_FARMING_STAKE_NOT_EXISTS: u64 = 104;
+
+ + + + + + + +
const ERR_FARMING_TIMESTAMP_INVALID: u64 = 110;
+
+ + + + + + + +
const ERR_FARMING_TOTAL_WEIGHT_IS_ZERO: u64 = 106;
+
+ + + + + + + +
const EXP_SCALE: u128 = 1000000000000000000;
+
+ + + + + + + +
const ERR_FARMING_ALIVE_STATE_INVALID: u64 = 114;
+
+ + + + + + + +
const ERR_FARMING_CALC_LAST_IDX_BIGGER_THAN_NOW: u64 = 112;
+
+ + + + + + + +
const ERR_FARMING_NOT_ALIVE: u64 = 113;
+
+ + + + + + + +
const ERR_FARMING_TOKEN_SCALE_OVERFLOW: u64 = 111;
+
+ + + + + + + +
const EXP_MAX_SCALE: u128 = 9;
+
+ + + + + +## Function `exp_direct` + + + +
fun exp_direct(num: u128): YieldFarmingV2::Exp
+
+ + + +
+Implementation + + +
fun exp_direct(num: u128): Exp {
+    Exp {
+        mantissa: num
+    }
+}
+
+ + + +
+ + + +## Function `exp_direct_expand` + + + +
fun exp_direct_expand(num: u128): YieldFarmingV2::Exp
+
+ + + +
+Implementation + + +
fun exp_direct_expand(num: u128): Exp {
+    Exp {
+        mantissa: mul_u128(num, EXP_SCALE)
+    }
+}
+
+ + + +
+ + + +## Function `mantissa` + + + +
fun mantissa(a: YieldFarmingV2::Exp): u128
+
+ + + +
+Implementation + + +
fun mantissa(a: Exp): u128 {
+    a.mantissa
+}
+
+ + + +
+ + + +## Function `add_exp` + + + +
fun add_exp(a: YieldFarmingV2::Exp, b: YieldFarmingV2::Exp): YieldFarmingV2::Exp
+
+ + + +
+Implementation + + +
fun add_exp(a: Exp, b: Exp): Exp {
+    Exp {
+        mantissa: add_u128(a.mantissa, b.mantissa)
+    }
+}
+
+ + + +
+ + + +## Function `exp` + + + +
fun exp(num: u128, denom: u128): YieldFarmingV2::Exp
+
+ + + +
+Implementation + + +
fun exp(num: u128, denom: u128): Exp {
+    // if overflow move will abort
+    let scaledNumerator = mul_u128(num, EXP_SCALE);
+    let rational = div_u128(scaledNumerator, denom);
+    Exp {
+        mantissa: rational
+    }
+}
+
+ + + +
+ + + +## Function `add_u128` + + + +
fun add_u128(a: u128, b: u128): u128
+
+ + + +
+Implementation + + +
fun add_u128(a: u128, b: u128): u128 {
+    a + b
+}
+
+ + + +
+ + + +## Function `sub_u128` + + + +
fun sub_u128(a: u128, b: u128): u128
+
+ + + +
+Implementation + + +
fun sub_u128(a: u128, b: u128): u128 {
+    a - b
+}
+
+ + + +
+ + + +## Function `mul_u128` + + + +
fun mul_u128(a: u128, b: u128): u128
+
+ + + +
+Implementation + + +
fun mul_u128(a: u128, b: u128): u128 {
+    if (a == 0 || b == 0) {
+        return 0
+    };
+    a * b
+}
+
+ + + +
+ + + +## Function `div_u128` + + + +
fun div_u128(a: u128, b: u128): u128
+
+ + + +
+Implementation + + +
fun div_u128(a: u128, b: u128): u128 {
+    if (b == 0) {
+        abort Errors::invalid_argument(ERR_EXP_DIVIDE_BY_ZERO)
+    };
+    if (a == 0) {
+        return 0
+    };
+    a / b
+}
+
+ + + +
+ + + +## Function `truncate` + + + +
fun truncate(exp: YieldFarmingV2::Exp): u128
+
+ + + +
+Implementation + + +
fun truncate(exp: Exp): u128 {
+    return exp.mantissa / EXP_SCALE
+}
+
+ + + +
+ + + +## Function `initialize` + +Called by token issuer +this will declare a yield farming pool + + +
public fun initialize<PoolType: store, RewardTokenT: store>(signer: &signer, treasury_token: Token::Token<RewardTokenT>)
+
+ + + +
+Implementation + + +
public fun initialize<
+    PoolType: store,
+    RewardTokenT: store>(signer: &signer, treasury_token: Token::Token<RewardTokenT>) {
+    let scaling_factor = Math::pow(10, (EXP_MAX_SCALE as u64));
+    let token_scale = Token::scaling_factor<RewardTokenT>();
+    assert!(token_scale <= scaling_factor, Errors::limit_exceeded(ERR_FARMING_TOKEN_SCALE_OVERFLOW));
+    assert!(!exists_at<PoolType, RewardTokenT>(
+        Signer::address_of(signer)), Errors::invalid_state(ERR_FARMING_INIT_REPEATE));
+
+    move_to(signer, Farming<PoolType, RewardTokenT> {
+        treasury_token,
+    });
+}
+
+ + + +
+ + + +## Function `add_asset` + +Add asset pools + + +
public fun add_asset<PoolType: store, AssetT: store>(signer: &signer, release_per_second: u128, delay: u64): YieldFarmingV2::ParameterModifyCapability<PoolType, AssetT>
+
+ + + +
+Implementation + + +
public fun add_asset<PoolType: store, AssetT: store>(
+    signer: &signer,
+    release_per_second: u128,
+    delay: u64): ParameterModifyCapability<PoolType, AssetT> {
+    assert!(!exists_asset_at<PoolType, AssetT>(
+        Signer::address_of(signer)),
+        Errors::invalid_state(ERR_FARMING_INIT_REPEATE));
+
+    let now_seconds = Timestamp::now_seconds();
+
+    move_to(signer, FarmingAsset<PoolType, AssetT> {
+        asset_total_weight: 0,
+        harvest_index: 0,
+        last_update_timestamp: now_seconds,
+        release_per_second,
+        start_time: now_seconds + delay,
+        alive: true
+    });
+    ParameterModifyCapability<PoolType, AssetT> {}
+}
+
+ + + +
+ + + +## Function `modify_parameter` + +Remove asset for make this pool to the state of not alive +Please make sure all user unstaking from this pool + + +
public fun modify_parameter<PoolType: store, RewardTokenT: store, AssetT: store>(_cap: &YieldFarmingV2::ParameterModifyCapability<PoolType, AssetT>, broker: address, release_per_second: u128, alive: bool)
+
+ + + +
+Implementation + + +
public fun modify_parameter<PoolType: store, RewardTokenT: store, AssetT: store>(
+    _cap: &ParameterModifyCapability<PoolType, AssetT>,
+    broker: address,
+    release_per_second: u128,
+    alive: bool) acquires FarmingAsset {
+
+    // Not support to shuttingdown alive state.
+    assert!(alive, Errors::invalid_state(ERR_FARMING_ALIVE_STATE_INVALID));
+
+    let farming_asset = borrow_global_mut<FarmingAsset<PoolType, AssetT>>(broker);
+    // assert!(farming_asset.alive != alive, Errors::invalid_state(ERR_FARMING_ALIVE_STATE_INVALID));
+
+    let now_seconds = Timestamp::now_seconds();
+
+    farming_asset.release_per_second = release_per_second;
+    farming_asset.last_update_timestamp = now_seconds;
+
+    // if the pool is alive, then update index
+    if (farming_asset.alive) {
+        farming_asset.harvest_index = calculate_harvest_index_with_asset<PoolType, AssetT>(farming_asset, now_seconds);
+    };
+    farming_asset.alive = alive;
+}
+
+ + + +
+ + + +## Function `stake` + +Call by stake user, staking amount of asset in order to get yield farming token + + +
public fun stake<PoolType: store, RewardTokenT: store, AssetT: store>(signer: &signer, broker: address, asset: AssetT, asset_weight: u128, _cap: &YieldFarmingV2::ParameterModifyCapability<PoolType, AssetT>)
+
+ + + +
+Implementation + + +
public fun stake<PoolType: store, RewardTokenT: store, AssetT: store>(
+    signer: &signer,
+    broker: address,
+    asset: AssetT,
+    asset_weight: u128,
+    _cap: &ParameterModifyCapability<PoolType, AssetT>) acquires FarmingAsset {
+    let harvest_cap = stake_for_cap<
+        PoolType,
+        RewardTokenT,
+        AssetT>(signer, broker, asset, asset_weight, _cap);
+
+    move_to(signer, harvest_cap);
+}
+
+ + + +
+ + + +## Function `stake_for_cap` + + + +
public fun stake_for_cap<PoolType: store, RewardTokenT: store, AssetT: store>(signer: &signer, broker: address, asset: AssetT, asset_weight: u128, _cap: &YieldFarmingV2::ParameterModifyCapability<PoolType, AssetT>): YieldFarmingV2::HarvestCapability<PoolType, AssetT>
+
+ + + +
+Implementation + + +
public fun stake_for_cap<PoolType: store, RewardTokenT: store, AssetT: store>(
+    signer: &signer,
+    broker: address,
+    asset: AssetT,
+    asset_weight: u128,
+    _cap: &ParameterModifyCapability<PoolType, AssetT>)
+: HarvestCapability<PoolType, AssetT> acquires FarmingAsset {
+    let account = Signer::address_of(signer);
+    assert!(!exists_stake_at_address<PoolType, AssetT>(account),
+        Errors::invalid_state(ERR_FARMING_STAKE_EXISTS));
+
+    let farming_asset = borrow_global_mut<FarmingAsset<PoolType, AssetT>>(broker);
+    assert!(farming_asset.alive, Errors::invalid_state(ERR_FARMING_NOT_ALIVE));
+
+    // Check locking time
+    let now_seconds = Timestamp::now_seconds();
+    assert!(farming_asset.start_time <= now_seconds, Errors::invalid_state(ERR_FARMING_NOT_STILL_FREEZE));
+
+    let time_period = now_seconds - farming_asset.last_update_timestamp;
+
+    if (farming_asset.asset_total_weight <= 0) {
+        // Stake as first user
+        let gain = farming_asset.release_per_second * (time_period as u128);
+        move_to(signer, Stake<PoolType, AssetT> {
+            asset,
+            asset_weight,
+            last_harvest_index: 0,
+            gain,
+        });
+        farming_asset.harvest_index = 0;
+        farming_asset.asset_total_weight = asset_weight;
+    } else {
+        let new_harvest_index = calculate_harvest_index_with_asset<PoolType, AssetT>(farming_asset, now_seconds);
+        move_to(signer, Stake<PoolType, AssetT> {
+            asset,
+            asset_weight,
+            last_harvest_index: new_harvest_index,
+            gain: 0,
+        });
+        farming_asset.asset_total_weight = farming_asset.asset_total_weight + asset_weight;
+        farming_asset.harvest_index = new_harvest_index;
+    };
+    farming_asset.last_update_timestamp = now_seconds;
+    HarvestCapability<PoolType, AssetT> { trigger: account }
+}
+
+ + + +
+ + + +## Function `unstake` + +Unstake asset from farming pool + + +
public fun unstake<PoolType: store, RewardTokenT: store, AssetT: store>(signer: &signer, broker: address): (AssetT, Token::Token<RewardTokenT>)
+
+ + + +
+Implementation + + +
public fun unstake<PoolType: store, RewardTokenT: store, AssetT: store>(
+    signer: &signer,
+    broker: address)
+: (AssetT, Token::Token<RewardTokenT>) acquires HarvestCapability, Farming, FarmingAsset, Stake {
+    let account = Signer::address_of(signer);
+    let cap = move_from<HarvestCapability<PoolType, AssetT>>(account);
+    unstake_with_cap(broker, cap)
+}
+
+ + + +
+ + + +## Function `unstake_with_cap` + + + +
public fun unstake_with_cap<PoolType: store, RewardTokenT: store, AssetT: store>(broker: address, cap: YieldFarmingV2::HarvestCapability<PoolType, AssetT>): (AssetT, Token::Token<RewardTokenT>)
+
+ + + +
+Implementation + + +
public fun unstake_with_cap<PoolType: store, RewardTokenT: store, AssetT: store>(
+    broker: address,
+    cap: HarvestCapability<PoolType, AssetT>)
+: (AssetT, Token::Token<RewardTokenT>) acquires Farming, FarmingAsset, Stake {
+    // Destroy capability
+    let HarvestCapability<PoolType, AssetT> { trigger } = cap;
+
+    let farming = borrow_global_mut<Farming<PoolType, RewardTokenT>>(broker);
+    let farming_asset = borrow_global_mut<FarmingAsset<PoolType, AssetT>>(broker);
+
+    let Stake<PoolType, AssetT> { last_harvest_index, asset_weight, asset, gain } =
+        move_from<Stake<PoolType, AssetT>>(trigger);
+
+    let now_seconds = Timestamp::now_seconds();
+    let new_harvest_index = calculate_harvest_index_with_asset<PoolType, AssetT>(farming_asset, now_seconds);
+
+    let period_gain = calculate_withdraw_amount(new_harvest_index, last_harvest_index, asset_weight);
+    let total_gain = gain + period_gain;
+    let withdraw_token = Token::withdraw<RewardTokenT>(&mut farming.treasury_token, total_gain);
+
+    // Dont update harvest index that because the `Stake` object has droped.
+    // let new_index = calculate_harvest_index_with_asset<PoolType, AssetT>(farming_asset, now_seconds);
+    assert!(farming_asset.asset_total_weight >= asset_weight, Errors::invalid_state(ERR_FARMING_NOT_ENOUGH_ASSET));
+
+    // Update farm asset
+    farming_asset.asset_total_weight = farming_asset.asset_total_weight - asset_weight;
+    farming_asset.last_update_timestamp = now_seconds;
+
+    if (farming_asset.alive) {
+        farming_asset.harvest_index = new_harvest_index;
+    };
+
+    (asset, withdraw_token)
+}
+
+ + + +
+ + + +## Function `harvest` + +Harvest yield farming token from stake + + +
public fun harvest<PoolType: store, RewardTokenT: store, AssetT: store>(signer: &signer, broker: address, amount: u128): Token::Token<RewardTokenT>
+
+ + + +
+Implementation + + +
public fun harvest<PoolType: store,
+                   RewardTokenT: store,
+                   AssetT: store>(
+    signer: &signer,
+    broker: address,
+    amount: u128) : Token::Token<RewardTokenT> acquires HarvestCapability, Farming, FarmingAsset, Stake {
+    let account = Signer::address_of(signer);
+    let cap = borrow_global_mut<HarvestCapability<PoolType, AssetT>>(account);
+    harvest_with_cap(broker, amount, cap)
+}
+
+ + + +
+ + + +## Function `harvest_with_cap` + + + +
public fun harvest_with_cap<PoolType: store, RewardTokenT: store, AssetT: store>(broker: address, amount: u128, _cap: &YieldFarmingV2::HarvestCapability<PoolType, AssetT>): Token::Token<RewardTokenT>
+
+ + + +
+Implementation + + +
public fun harvest_with_cap<PoolType: store,
+                            RewardTokenT: store,
+                            AssetT: store>(
+    broker: address,
+    amount: u128,
+    _cap: &HarvestCapability<PoolType, AssetT>): Token::Token<RewardTokenT> acquires Farming, FarmingAsset, Stake {
+    let farming = borrow_global_mut<Farming<PoolType, RewardTokenT>>(broker);
+    let farming_asset = borrow_global_mut<FarmingAsset<PoolType, AssetT>>(broker);
+    let stake = borrow_global_mut<Stake<PoolType, AssetT>>(_cap.trigger);
+
+    let now_seconds = Timestamp::now_seconds();
+    let new_harvest_index = calculate_harvest_index_with_asset<PoolType, AssetT>(farming_asset, now_seconds);
+
+    let period_gain = calculate_withdraw_amount(
+        new_harvest_index,
+        stake.last_harvest_index,
+        stake.asset_weight
+    );
+
+    let total_gain = stake.gain + period_gain;
+    //assert!(total_gain > 0, Errors::limit_exceeded(ERR_FARMING_HAVERST_NO_GAIN));
+    assert!(total_gain >= amount, Errors::limit_exceeded(ERR_FARMING_BALANCE_EXCEEDED));
+
+    let withdraw_amount = if (amount <= 0) {
+        total_gain
+    } else {
+        amount
+    };
+
+    let withdraw_token = Token::withdraw<RewardTokenT>(&mut farming.treasury_token, withdraw_amount);
+    stake.gain = total_gain - withdraw_amount;
+    stake.last_harvest_index = new_harvest_index;
+
+    if (farming_asset.alive) {
+        farming_asset.harvest_index = new_harvest_index;
+    };
+    farming_asset.last_update_timestamp = now_seconds;
+
+    withdraw_token
+}
+
+ + + +
+ + + +## Function `query_gov_token_amount` + +The user can quering all yield farming amount in any time and scene + + +
public fun query_gov_token_amount<PoolType: store, RewardTokenT: store, AssetT: store>(account: address, broker: address): u128
+
+ + + +
+Implementation + + +
public fun query_gov_token_amount<PoolType: store,
+                                  RewardTokenT: store,
+                                  AssetT: store>(account: address, broker: address): u128 acquires FarmingAsset, Stake {
+    let farming_asset = borrow_global_mut<FarmingAsset<PoolType, AssetT>>(broker);
+    let stake = borrow_global_mut<Stake<PoolType, AssetT>>(account);
+    let now_seconds = Timestamp::now_seconds();
+
+    let new_harvest_index = calculate_harvest_index_with_asset<PoolType, AssetT>(
+        farming_asset,
+        now_seconds
+    );
+
+    let new_gain = calculate_withdraw_amount(
+        new_harvest_index,
+        stake.last_harvest_index,
+        stake.asset_weight
+    );
+    stake.gain + new_gain
+}
+
+ + + +
+ + + +## Function `query_total_stake` + +Query total stake count from yield farming resource + + +
public fun query_total_stake<PoolType: store, AssetT: store>(broker: address): u128
+
+ + + +
+Implementation + + +
public fun query_total_stake<PoolType: store,
+                             AssetT: store>(broker: address): u128 acquires FarmingAsset {
+    let farming_asset = borrow_global_mut<FarmingAsset<PoolType, AssetT>>(broker);
+    farming_asset.asset_total_weight
+}
+
+ + + +
+ + + +## Function `query_stake` + +Query stake weight from user staking objects. + + +
public fun query_stake<PoolType: store, AssetT: store>(account: address): u128
+
+ + + +
+Implementation + + +
public fun query_stake<PoolType: store,
+                       AssetT: store>(account: address): u128 acquires Stake {
+    let stake = borrow_global_mut<Stake<PoolType, AssetT>>(account);
+    stake.asset_weight
+}
+
+ + + +
+ + + +## Function `query_info` + +Queyry pool info from pool type +return value: (alive, release_per_second, asset_total_weight, harvest_index) + + +
public fun query_info<PoolType: store, AssetT: store>(broker: address): (bool, u128, u128, u128)
+
+ + + +
+Implementation + + +
public fun query_info<PoolType: store, AssetT: store>(broker: address): (bool, u128, u128, u128) acquires FarmingAsset {
+    let asset = borrow_global_mut<FarmingAsset<PoolType, AssetT>>(broker);
+    (
+        asset.alive,
+        asset.release_per_second,
+        asset.asset_total_weight,
+        asset.harvest_index
+    )
+}
+
+ + + +
+ + + +## Function `calculate_harvest_index_with_asset` + +Update farming asset + + +
fun calculate_harvest_index_with_asset<PoolType, AssetT>(farming_asset: &YieldFarmingV2::FarmingAsset<PoolType, AssetT>, now_seconds: u64): u128
+
+ + + +
+Implementation + + +
fun calculate_harvest_index_with_asset<PoolType, AssetT>(farming_asset: &FarmingAsset<PoolType, AssetT>, now_seconds: u64): u128 {
+    // Recalculate harvest index
+    if (farming_asset.asset_total_weight <= 0) {
+        calculate_harvest_index_weight_zero(
+            farming_asset.harvest_index,
+            farming_asset.last_update_timestamp,
+            now_seconds,
+            farming_asset.release_per_second
+        )
+    } else {
+        calculate_harvest_index(
+            farming_asset.harvest_index,
+            farming_asset.asset_total_weight,
+            farming_asset.last_update_timestamp,
+            now_seconds,
+            farming_asset.release_per_second
+        )
+    }
+}
+
+ + + +
+ + + +## Function `calculate_harvest_index_weight_zero` + +There is calculating from harvest index and global parameters without asset_total_weight + + +
public fun calculate_harvest_index_weight_zero(harvest_index: u128, last_update_timestamp: u64, now_seconds: u64, release_per_second: u128): u128
+
+ + + +
+Implementation + + +
public fun calculate_harvest_index_weight_zero(harvest_index: u128,
+                                               last_update_timestamp: u64,
+                                               now_seconds: u64,
+                                               release_per_second: u128): u128 {
+    assert!(last_update_timestamp <= now_seconds, Errors::invalid_argument(ERR_FARMING_TIMESTAMP_INVALID));
+    let time_period = now_seconds - last_update_timestamp;
+    let addtion_index = release_per_second * ((time_period as u128));
+    harvest_index + mantissa(exp_direct_expand(addtion_index))
+}
+
+ + + +
+ + + +## Function `calculate_harvest_index` + +There is calculating from harvest index and global parameters + + +
public fun calculate_harvest_index(harvest_index: u128, asset_total_weight: u128, last_update_timestamp: u64, now_seconds: u64, release_per_second: u128): u128
+
+ + + +
+Implementation + + +
public fun calculate_harvest_index(harvest_index: u128,
+                                   asset_total_weight: u128,
+                                   last_update_timestamp: u64,
+                                   now_seconds: u64,
+                                   release_per_second: u128): u128 {
+    assert!(asset_total_weight > 0, Errors::invalid_argument(ERR_FARMING_TOTAL_WEIGHT_IS_ZERO));
+    assert!(last_update_timestamp <= now_seconds, Errors::invalid_argument(ERR_FARMING_TIMESTAMP_INVALID));
+
+    let time_period = now_seconds - last_update_timestamp;
+    let numr = (release_per_second * (time_period as u128));
+    let denom = asset_total_weight;
+    harvest_index + mantissa(exp(numr, denom))
+}
+
+ + + +
+ + + +## Function `calculate_withdraw_amount` + +This function will return a gain index + + +
public fun calculate_withdraw_amount(harvest_index: u128, last_harvest_index: u128, asset_weight: u128): u128
+
+ + + +
+Implementation + + +
public fun calculate_withdraw_amount(harvest_index: u128,
+                                     last_harvest_index: u128,
+                                     asset_weight: u128): u128 {
+    assert!(harvest_index >= last_harvest_index, Errors::invalid_argument(ERR_FARMING_CALC_LAST_IDX_BIGGER_THAN_NOW));
+    let amount = asset_weight * (harvest_index - last_harvest_index);
+    truncate(exp_direct(amount))
+}
+
+ + + +
+ + + +## Function `exists_at` + +Check the Farming of TokenT is exists. + + +
public fun exists_at<PoolType: store, RewardTokenT: store>(broker: address): bool
+
+ + + +
+Implementation + + +
public fun exists_at<PoolType: store, RewardTokenT: store>(broker: address): bool {
+    exists<Farming<PoolType, RewardTokenT>>(broker)
+}
+
+ + + +
+ + + +## Function `exists_asset_at` + +Check the Farming of AsssetT is exists. + + +
public fun exists_asset_at<PoolType: store, AssetT: store>(broker: address): bool
+
+ + + +
+Implementation + + +
public fun exists_asset_at<PoolType: store, AssetT: store>(broker: address): bool {
+    exists<FarmingAsset<PoolType, AssetT>>(broker)
+}
+
+ + + +
+ + + +## Function `exists_stake_at_address` + +Check stake at address exists. + + +
public fun exists_stake_at_address<PoolType: store, AssetT: store>(account: address): bool
+
+ + + +
+Implementation + + +
public fun exists_stake_at_address<PoolType: store, AssetT: store>(account: address): bool {
+    exists<Stake<PoolType, AssetT>>(account)
+}
+
+ + + +
+ + + +## Module Specification + + + +
pragma verify = false;
+
diff --git a/release/v13/source_maps/ACL.mvsm b/release/v13/source_maps/ACL.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..c09c9cd5a1e85adf80719d60ea48c96c034736da GIT binary patch literal 2752 zcma)-&r6eW9LK-U^K80g<(3vBx|QLfzwL&7?QUXzTTByn0a%f z_vGHGgZy~($ZP(YJ-55jC@=ngK6g3q8B+k>|Gm7RSQ_NVE%E;gzA-&uJZ0X*x&=uc zG#ePx3C0h`CL$I11ZEBrV`2DE$!8I}!3(<1TvGA~Vg#mL@A(d1%?6fNHi{L3FU?7; zDF~z)@3cjl72?@5wMw&$W$lzS3s|oqEzK8LFX5;(r?FnaF=@uDw@Y)Ccy-7~a|P=Y zWTm-=^%;&!^DWi}bV$=$o8VAPo3v8{+*)ND^E)`T$}hw{8=4A`TW)PJrVVuYr?E1i z%l|KnXEAm8?_=gMlX9Quv95w{ln$(Gpc^G#T{nu|V=p)yzMCWU*xPq{242Lx0#1p& zj@V~In}km6eZ&W#6B}VY2A$X$tY@GTdmC#O9MpMc%R4)Xc=4g0?Q1wYpwIOIs|nne z3hHyADR4{L5zI6=B`t?|8hoe0g&0Bd-gJ2PsoHe`vmczs99|9dwT)thpvz$rYYKEZ zj9}Sw>F%u@n!0=A)9dbiLd<2*V{Q@aJ?JqvhqVNH%*CtgG53{t-$0MKFId~4$J`Fq lF6c4$5$gwZ%5JgNPcVL}TpFql7YC|bZn-)%Ts!>gnSW(ZJ^26t literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Account.mvsm b/release/v13/source_maps/Account.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..3faa751ae2d54e4271e1c120c5abb43d37b209b4 GIT binary patch literal 52990 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 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/AccountScripts.mvsm b/release/v13/source_maps/AccountScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..d626c5e80b926ebe9deb816267de43732c38101c GIT binary patch literal 875 zcmezJMQH!TH+Mt|k443F%AE+EepO6+<|*#8SDsFg=36eCrp&;=UC$p5HM>q(2z4AgBaNpA({#4I15yL1#C47VdHt37#Ku=n314E z#DJ=#ftZP)$`?S(Wq>M~391CCk_BQStUn7>^%NACM2EvOpyIb69SlT-gBsAyxYup#M)KaslXK4KoO3>%Ftx0_qPQ@z-=!ZJ_vehB z``LSW{i)E-_@CK(^V?RGyclYX8BPxU|Hp~;2J`37Hc`e*5Qn&lsU+ie{K{70LgWOL ze1NK<=xP37aIwNT~N@+GR4+DQ2h^`6>F`3Cit+DTcB`al^{+9zmxDZg>N-_$|M zuP7%b{7_bJg=AC;b&@g_l}??dY=~-25j^O9Zeu2qak*yat81MMoJy{F1&Yps<%f^U zLtI|(O5keJ@1=F9^`zfRg{ZZp-%FcNn@PWywxUWXT7IHp)E0`7as#S}Vx?SxDy0ZM zd~vKX+bEJ1w;i{G^olD%l~PQgAQ&uIsJ;UGphw6P!Hi4gTar!@%(!G&3b_OAFP3eg7=1xtyki7*vvXAFXKGy0+~#G zH&*a7yG#0Ryj3st-S_}mL;7yKhpHxhH6K{j6ulDdjiOiLe9pX(^h#WUT1t8) zEm~PH^w#8b-WdW86VKA-(uRsN19$e>v(YnJ9N|c9zSybNlsmo2Em2zA3{- dj`fZhHh9V)ug^E$F^T{GUCt<i=vi>sv zE`MZ8TWYRav)r_;TD3|{O_!Ukwzjgh;n;G8R@1FNj8(5^@kp(;_sRC+kK^@xzR!K{ z%lm!LwM*M(TPoJ<|Lv*sdmmZ5(!1d`(QM_Zrg*#;eTTSo=YF7jS05r&Uj`F@7-K!qJJIp;WIun4B6{ z3k100Zpcp$j3vhhMuz&-6=Cd0!IL$V99HsS#3NuT^&9vE?{jCc+?AtP=fEpXcl|7B ze$TugAX}P0Va-8~G%sQO2tH|kjkPS#m^^9vu>6oO%`40-$1IShyLzEC?`PgaaEmk> zvBFR!&33Ff6iYLL)dnTfti?JArP7?l+5=_M+<^50ERm+W`ci3n^EpT0mu5az0LrE5 z!^(qY(!9dE8OB^L%@(X)xJ{a?vHDlElPK8tk`bQqt;Is-b4_hD7@o^-^{V^(73%A+xhS%s;?*j-(R z@q^5ZgAQZ&lhR)_h5YpI*gxRFm)Ka|D8IFFEH~mRLEWW8S59&v3(ZnSJ1KTW!JMn$F>hE z7j$fAW95L3?LWB3KS9T~vvM8;NN(7{`R6#^Z+8?gF82X72(05TZbR%*;37>{RA?bQ(8X2@Cb z->S7o$C9bd-Tg^5q?QGI^Fc$JFz16QBGhMvubHJdqt@i6dZE>BDji z?`_bBp!?iC4!X~qn70;mpSuS~ z_jw!h+Cleu9IFF#pGUD`p!+<8RktLQmfnu}9O#zbiM0##!&Mq@lImq-!I;{#AlWVyAok5mWVV56Onk##<$z8SZg9o z>{zj`sPjsv9eg;x&a$2HH*O)zR9mrl!sb_3Yxr-iCEl?pcukG9z9SxMwf}dGZ1Wdh Cc(N-1 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/BCS.mvsm b/release/v13/source_maps/BCS.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..ca29a6bb46ca1c5992976b6af13756cc249b40c7 GIT binary patch literal 34843 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 F{{v`HxhMbt literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/BitOperators.mvsm b/release/v13/source_maps/BitOperators.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..b0aefd5834fe6e0834c1b21e1f52ae56cc1c55da GIT binary patch literal 1831 zcma)+yDx)b9EIPnE{Q}WqD>5J{sZ@zTG2E_#9~%bBBE`o17S5-smmZD5rfM_+$LG^&=IbXwT6I*ls-i!HoYyLelwzt;slZgzB7k+O~s{*x$ z>s`i}e(>P`$EysDrTdbxR5YDPO`39J!XoK_uOHb6pEsr4W3&_Srj>bybq>aq>JuK( zp1_mG=CNMEC(UQ97bubD1J)ZjJifzcOb}eU3gLBv7gt?%WA)fnm#(6SLpE0at`V$J z&|M8<#Xxs8h?N9~&>NK)jm((U4~^jdcC zc0s>c`&b7y)upQ|#A_QXkIiD`KzDV6bqBhuOROg_W%BU}Doxp19saQ=@zS7oHG?&4 eQ(d}RM9kP&dF%?-D(J43u$Do0wSct&#{2<76Wpf& literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Block.mvsm b/release/v13/source_maps/Block.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..496f52b178d1292b16b76122ee2d551612b11341 GIT binary patch literal 18845 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 xqN2hg@8rS~@6Q8Ok7@t_ literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/BlockReward.mvsm b/release/v13/source_maps/BlockReward.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..8b86f34d3ea36125161595d78cdd78b15aee7f82 GIT binary patch literal 9414 zcmb8!S!`5Q0Eh9@ZCdEG1*(*SAXv&Gq81EGd@Ai&Dt5qWp-6@6FifF#nKJDZ%BHO> zf>2N?D4U3pr9c%F^Z^y3iHSynf`UsBOw@oVY9z{H@EhSO@#TLd`9eZ}=bX6}7?y75m;@~Em%pwbtd z{N65r08SgTt6DcN!76{F8sug`H!>zwzovn}eA2f|J!&rLi{VAhqd0j+ zHlwytyp%go`zS%mC8+)6lJZm3SClAaVh3ZAqDk2kbq95jvJv$-b(FFY)kMisp5$nj zBi&LSM7~ccQm$aW7IJWlv?d#~gN)1R4c>;{L#csCI2^30w`wBQQ-fi3iyvUf2R9D8 z_Wwf-`aEIPqty@$sKxp+B8M_+!@-7%P^8Y98r^EF z>Ha#aJQ%D~;{%MHLuql@Svd;FbT+03xv#C^>~sVfFf%&HKKT_j8JQRe*A>*Cq_?h%sLQ0cuJ2H#oNT>yrJzQV-jMpBMv&f+>^b#@RKR>iq&K9Ms8>jD zNVTXY(i@U}OQz~Og!#UtG%1gwPE#i--$Q*vou#zjY`RE!f%)S2u$C@m5-N>uawK~q zyGq#`l|>m+_CnoC-K6Y?>Q9+c_C;k=cPZmhF6trWInL)4WFIN>Q4iB?QVv2*rYtG# z)%!~M8}t26*-~CcU7>zb{(-tg{iXaFRnGP?K+4{17{h6xly1}rx?Res8cBnsY(hOr zcSt!8)k1@%T!ng;?v!#3YAxL*N(1h(%!CzNZHPO2WY622T>o=J&xoj z$YD}`iu#O(OL-J^j7CWL7U~@uDdkpFGIw&Wl)oT5AV*1g0@)FnC#Ai5zLbNRZv=Uy z9DvHD`=rc6O`-xRGf`zUTFQl}%~U9*{SowjDchNE4~>y>ALr^CV8){pI zF#uCQrcexluKzpr%sph6i0K0W=MGyb(Simw7*4oRLV3SA~UE`O8Z&0O3E_kn@-hI zJ{nz_YNVWjs-TdRrKmMG8B;6eY2-zkDW(0m9hNek?=`ZhPRf3$AyhAAUsN_lq)bCC zqy{M`qpE3^lwQ;%nl0rfR2wx)xf|6^bEMpf+C_7vT!(ss>poA)bX0emFXb($0klBM z0`bCHAxvnRZ_E*d8jISLduhv$?C1nWJOixSMhT2chNcjcodwN#N7(UmyXtk8Xn6D?YRmzVzmvHB}VN@Nhld={ylh#W)3ROrO9LZATMn^LGIyXtV6t#?Aka7j8g*Hq16lyuWDCHv5 zV%j2Qbmf)wl9cu*>a9}RPg2{Z{D75D&<-izKz&YaQtn4Z^-d}Gq6YJOs$Ej1qx#Tp zDbFzHZOC>hD^ZQ~ij*r+8|hUk_o5Ec9w|?t&eC2f??+vr*QB(6@AtZtT{C%KqJ2_! zMrF}{DYH>I^oEpIIhrBJH>HfKp=1)=o}xmp$7gva78aMpnGBE5Q=03`x4h$vM)A*u z#a5|rthXTEbo1nm_xU{DlK=iF)?|8e$Cr#A>$9SNSz|m8MTdEc#+5u2W3vDGS$@9H WQ(SE2dh`EvMTNyhxg~j{jrj{{#WaWj literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/ChainId.mvsm b/release/v13/source_maps/ChainId.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..24fc09e8ad0b0a6329a22012edc5bb9e7beb4ed7 GIT binary patch literal 2200 zcma)+J!?~87>1vme4L_IOT|UeNd>8(lR}}wu?bC}A2z8mrD_QY+ALM^Yb!2}1?l2H z5Za-VUnLPuG;(DWT+&^%!f|FCl6*mHH0t zy@!X)?JMFo=s_H1tOKA2@rS&Vm}xn(b65q)NOKaa0$FK}U|ocqG|ylSK`hNG)+Goi zznC+748Axv>Set^eGPj48(5z}&;Je9I_UZP?w%Q-p5SDk^3%-<=v6_jf$nt~YYud; zX{;I0y?l4i3^-Vy(Z0L-&zA2iVp=iiUc0dlg6`FWwF`7F-`z6 z$)I~3!5RSF>k!sq(7k+j&kXp{o~F}ac(1Fd4bZ)=W8DYctBG|DbT8lCGXwr&7C3_s z!_VO|>MH179jsTNdp*T!gYMRxAU jUojaSElhXsMAmmcDUT=ReD{`F--Yr-tu&T&Z)NN+jpTLw literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Collection.mvsm b/release/v13/source_maps/Collection.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..da074d5a6ed5bc43096b0af738764b77db54613c GIT binary patch literal 4680 zcma)Epb$pDy%z`%6u1yd^waSth$Fj$a>6o_2!AwE2k;*Vj%j{*F5?usk zi!jR~3s*)3Q52OSlv)NwWzR)L5w))GN)thg-yQe{l+SbTJ^yo#_n-Ck^pc$ZvrTPt z!%3%xhX-dJY1~+PAf=`8|H_z0tO0V~&Bt^2gEI z!ShwB4RoM&+Nd?k?7=z*#_*-&L7a!6v-$w*F?cfO2-YYhN%I=k6L46*I^CECaLDQ| zv_`8YS8U$AU1gvZ^Dr1QNvCTJ@wp8xk2Z+)0(81=V`T*F(^6agftil!m*z{%0A`9b z6RW36Gf2D@kS5L9SPLLsnsKb%5Rhg$)*i@^<^a}pm?X_ZSa-qUA!ScCW+^z7-!in^ z2~{@rO0)uSYSkl%Z8okvS1r~-(6!fr)d#v&t#uh3)Kw|Q6oW&qqG%;nb!yde%uQf7 zA(LjLNkv*s1h!>tGFJm}%JA8Q=+cp1cc1$w;nW4#7FUJ|QM zmibJkru;BPn!oHGF{euNlij1ORh`i6RAUx`L#-}CTMS-W%&}OPVdsNCR#RWKRh9NS z%=O^Z;(HN0Ko{&5tWMAcTlL3usIHt0W7dL0+QMj&301ai8QKQ${5D@ZRKmJY&w#(K zAzmdfJKdPQV6yZ8?ZdkaI=k&y7eQw?vA!M$iF4^&(GV+-fUff!Sfii^$5pJi+z0io zD1bE;^sVSKF@J)-70n^u0?=ct2&)wI*vi2w13k79XV+t^n|QsT$5u1eG0 zCI{Rw))-_;a{%iZOqXWj><$m!<5e&P9J)UhEzPQ~|KKx`XMw|eVG~+2B)d%4Uc^g4 zy~tEl<81}q{>4~v(Cy!XbrN*@|2>x6=T+j}1l|6(uH1Sg`9Erw4Wd+4i O^Z)N7rQuMK&-?~_lur2o literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Collection2.mvsm b/release/v13/source_maps/Collection2.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..d25b69fe078d818dbce69ec3f84253855b7c6523 GIT binary patch literal 15981 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 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Compare.mvsm b/release/v13/source_maps/Compare.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..9a697c51f136b08cc14e2d1de907c5e620e0be43 GIT binary patch literal 7988 zcma)=ZA_JA7{~8(kXL!ps6m1t91ui|0I@f+h)&=%O~kEO<{Tay3zRU9Us|lSG&Mfp zW+8$`Mx`T3=4z&_*0;9iQZ%8QYcC%;{hsT&&-L8*bFTjx z`{u38?=G!hP=2#5=Ui!eN9qrsZajXzxnx~vyt5-|@=CxMQv^Qv|DP|mdPhs^mbQ?I zF=k8@>54Pv2pGRVT&m=wi2dLXmnrp2v|)&k$`8o8TM~?U9dMVc!ZmY^=>XgcfU zFeh9VC|95FI^qPFm3n7Pu;NMZ$vrfNbp!m;bWMwrW+I77ZyqLN38RZBh8<%E<&y}N3cdAAkA|TGf$fCb(=5E zX=>hu#nPO?;s~1pY2L*2VHQgBM#NkqP4}HpB+XpzoCiy#S%_5x#nQ~jDu89ubYJEV zNwb)GrBEVGSF==_tEu-qlu7ditU4%{=31Lo^OMcf7+VnjRIE=ceaBeIh?^WY^$T)>M@_7)>P zkGP&=L?0InfUijnEqDzazvE7Vr@&Foa)aP0aI_+} zfvMDiV~`b`1RXf~u!cYf4%ajtI4)3c6m;PD9_te5z~P>Q4jg|`?{Cn7V+v~;bl|v! zbq93daL-={jwGICGU&kJcD4>2_Sh~09XJA5`H(DMT{&2}preUs*Re4EIaZty2e%bm|T8YSV$^Ma%}!f#YSYO`rqEDy&yP2aei^sRM_5<>V}{+yRZ&`4jlH*hd~F98La3OJMqigpFle`t9tldeHigH zc=%oYEZT@wy@Z255d-sP2Yxv}UyQhn5AwtPY#q>3>s734pc^)h^(*M9)vZ)dt-n$4 zI_Rm@)zq`-Kh(PodKSHlH3NDUoyNKYdKPt0RL`RP?rh>g&!VoTo-os>XZMqyFkMYO zVY<$Hc;}E5d$IaKZ|Xx>he2;@dv{yY zLl)aL-oD M)d%Zl|Mi*w08xo@bN~PV literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Config.mvsm b/release/v13/source_maps/Config.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..9aa035a57646fd860fa657ed8d429898e233a38a GIT binary patch literal 7768 zcmb7}S!~o*6o=2ubT1%n1)&xcOhgp5n25pP1C{}bq-7~>NyK4nhYs3wkS>aXpaud6 zQLup++0=+^N;DKiC>jkFXo3m?E)PVEk)W0kB}T!-@2V4h``v$&@2TH8cRTmonRd(h z?qL(AHm6?Qlw4DD%cNwUC5wtjv`3D14r<@^*qv32&1@-z;Qv3Ntg=+ooVg7dW?Mvx zPl-JRq5OYBs^g8V2^DmjfNx!p62oD$TnNc|Jjq<2hd}dKMZkIpt9cwjIs?kPfOF9$ zl;$#4wZW|{$i8hPU>nH!oQ?9+u ztN{W|BuPNC3yRdm=c&o8L|hH-80EekLF{&!z07Z1TCL8?F>8T9YiuQ8i3`ez*VoTi zi(HTS3b?bEQ$K-t+NGA}UaW(lFMu=8fQNc~xLFSb+K!6^{NaKk9!Fk$tJxq3WhL4Y zO)br8_nyUF4wj`iZx!APF1OsgTC5eIH!nTDzPF3Xw*)fe=)18xAXAzzW9qPtzGTVG!o?kJ42Qx}fo$`aXo5et%Tn*M7&?mPYYZvH~bLK(N z=W!hCBxK1IwP2ltY-tX_`WbSh>8u{`D6#EB%#K2!YB)x~DHoI-ud7S7Hnpf@yNrC* z1@vj2+t8GlA9MXM(JU|ZoS}4Gu->{fR^qJzT^f&Ltp!~g>G5@Gd`G@ZpfB}1So=U1 z(FUw>H~ExC3D#)PrD0h2Lar>L^yqooB;O9mmu3uW9`ustVXQBqw=_Gjz5W)(yOGC0_PqFl##Fps zb<_#C72x$*>J7wgV10E>rtsQaVp)@`vD!h`0yc-kps82&S&y^eO4;T}Zy?KsVeySo=UX+&8h_1Kn_!V(o`MvO-$0 zo`P$n`99VG@YwoA{meE)p!>LmfSurdAG?uHfbV_$9``431u0kC+TUy;=sWf_)>6=S zYzEdc(0A+*)?v_h>_x0D@F??wo6SZ-pi{Yvfcsof#N!L$EX3L1YDDgE{xIqj^bR|7 zFz9_d&fsT3@7pNym4oh04`5Y*?oGq7Dna)qXH5Z*mUAH2><|PxwGRk52Htn+0`evB zy-S&Vbm|4+Jjx=LOf}Xg>G5^- zeNDdepsQ~i*4v<~?Dc?Popv%fUcqhBY@iR7CG z1Eg7oRSg5BS&CHy#nPOKH5;y%W(igtN~Gzmhr#3P#Ki(Gdttyn8X=$$c>PW74#bh* z+d~t$jV`&@x7N*=uR~Vd-~VJ%ov^gXY!pzGau>Ifc01^<>CFA0dtrLIx)=UHz8^vN z!fve3LBGTwV-02Xx^HD*-3YpG^^kK2rtVwm(RJUNO}={2eQPwc6fGM&W$gXslgq1S#wJ!y9v7YV->;{e{RKDK1k3;c literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/ConsensusConfig.mvsm b/release/v13/source_maps/ConsensusConfig.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..ff86691055213df89a3b25bb18a12771c72e102e GIT binary patch literal 9323 zcmbuES!`8R6oz*P+A_99@=5>Y@A9uUM3{dSv^G`{@1rOB7{;ah93v-dfBuXE3! zjT7F<%UYhcZFAI`)8|k0+4^F_tn_2qV`|O5^75gZGX2JwGKhete-ZH$O2d`GaAkER z|11g>A`B9_T16U@1g5Pr^RY@mdB<_iId~CK#-xDCSBA6J!8?j`#=#pHZA><(ad+Yz zbnqftaUG!Y<>6E~czbY;IC!^k?m>bcdP-Mg0$?Iy0u48YsX%PY0W4(9y!?txRjiUm<76IYv$XuF|y?4-Hq7-CL%2ytnmfQ zN&`i{g~g?TCBCXqNzhm2uP6*wscmE{8S21w+c}H-jUClt`#Xx^V;$_uOa9j^# z;z2(+iCB+-zF&W*#sQcnRu)>{)0khuL^^KMzad|T`&pyN3}e#4m^giqj7OXbdeW^q zAM{lEv0eZ@l?$+50sX|S#99aXMz`i3h?A?c0_#0!EzMzA2f!ieA$E|@>@MQ^h@3>O zw*f9&!=H$^KrfdyW9`YTuWnk3F|)w_IdlixQICMGp&aX|P25J#aAAxwag63mSMjHiPhmianM)cuX5eQHWRhiMmF69oyI&&)JaHL=&uYmfA{>B&}-1GNq9kM z(V|eGy0~houO<{OD6LUj@LfB8EXPShl8RuBzoNib7OZG2M@9D~aulThKe}-i$rA|b zxz8p;p{=1L6mI@BJWJ%7hG_qD&5zze*Z`ic@##z?hnDt=VHvh!j zK-}BV!gH^l&`Z#=BddJ}V|u~;9a%YKSOU#I^tTYT5AN&K{+a~Wp=Bp#mw00aLb5&X zn*Gw2M`RdUeqwGXx(-@&V*W(nO>jOjyYT~9A7~rZxA$Omyk>MVW(Y)ESII?5yqSQN zW#-k08-Xf@sKjHbAQy0lDz^Y{X`?$#xhwFtHM+xY(H*JWfAA6- z=OI(M-SLJtx{oP$9Ns)IQ*~dI!|mV$y(2Ef3V`m57GU{7_eGPjUIYD_x*Tgg=x!&7 zwE=Xu;(0e1vrsbPwZ=u6vk! zo$y( zrZ;+~G`)Urlr+7b>~U#&9a)w%y?$)0G`((YyfnRDY@#&1PHeI?y*_NJG`%h?Tbf?; zJYAYz=bR%=Z#AEkrnj0ir0K2ZQ_}Qiex@|Nb)O|oZ{250(_76s()3m{SDM~xJ}pge zHRnpxTg^OaM)9WbrtRo;V|S5n!&mJ0Vb>o}t|H&C0WLqFbmS9Vs?(=LYi58$hk36v y7iPc0yOtb}oNNPJO3p;g0{w<#%^5arMB=1rIl1GePn+l)H*?CICnn|0Hs(KumY5&_ literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/ConsensusStrategy.mvsm b/release/v13/source_maps/ConsensusStrategy.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..c3fbc6435c0a5ebc95c2bb903b37e9ae13ddd2ca GIT binary patch literal 913 zcmbQw>}nxp5%Slfy(8|N$l}+RHnDVs?m4a)J>}#&sXDt)c?=8;^+3!B#K?eA&^bS^ zI5n@hv^cn=D6u3py%MNoJ^|BQfNDZPMlljnIR&U{CJ-|bHdLIAfk6t0fu=I6DjO0q zSsSRd45XZyu+gDFb)`VeNYH06Q(1^oSp%}4u%UiH-$wv30~32OVm5**zX09X160XQP~~l)Dh?JPCa4mmiW7(#7yw>0 BQCI)~ literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/CoreAddresses.mvsm b/release/v13/source_maps/CoreAddresses.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..bcef7eaf89994ed4fc1535c3dacf75790d9e24c1 GIT binary patch literal 799 zcmaEMw{eRG$8pcM9SdKIItEK96)k&Qn)lehPB^F8=v{$o1Oo#@DiAXQF*0D}b%go rc7iG$fU5FLFN literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Dao.mvsm b/release/v13/source_maps/Dao.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..97084ad8d465730af1a6af36f15116ac6e461a69 GIT binary patch literal 50523 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 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/DaoVoteScripts.mvsm b/release/v13/source_maps/DaoVoteScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..0c199202aabfb0c7f88b9f7954177cd43ce16f5e GIT binary patch literal 5825 zcmbW3ZAevj9LLW+-ludk-O_EXM{F^AAc96CWNdB_N?9!RjZ-o2$$NXa$L_slj?wmF zPq=6s+oHkjfgUDok(%IgQW0h__F^L`8&On}#P%kOn$zJv*Eq0u-~Ubcy!-rro_qf1 z_x=4YhIfRD&)mu#`{PP?&o9I7_?)AymEqTWnv-viM$dm+S!7w(a`3_b|9rV`)w@-0 z%GuD6h&82>R=~0@idrs3c7YwJaJM*drMIB&hR_=gshAtDQ2sZ#-$5Xlj5Wrcg!21v z&qH2Q!fkSsPNJ?p5=l78q&hgrp<&2*e6W6NT`Z!`Ji@na9 zr=`1v=sz{SgZ|MRwLNKsUaz+UKBSDrc?4G+&z$GI3<6? z?ShP_WIu-nA(JUNfk7ShGP#fcO7(1gxRn+n^($0xJSK z0ybf72OR;gVkJOFfOi2p0+vv3Dd-6J0jmpi1axEdgN}d!tlvRLz$L69&=K$%)>Y8E zsrOOq-Sh$V{sFz4PGI?&etI{(jTykyyJ^}Ag29Z+nZ_yuhM_hO^(8P2wPMr~@Eh(O z8*!tMaj3n^p;pKw)Y|ad!7QSBF#EtZj==0}?g|V;ZHVI6fiG5u+5^0C(4lq{YXWqr zdH-LB+AI91V$h-X8df>zP+N~x4La0nur`7YwF0aL(4ppCl@7Jt)cX*0sC|sJ7j&p? z!}=U_sHLqhz~I%NKsybFjopiS77QEvGU_!j-Bu=W?VKlQ>=_(d0GTxQO8gS=8MkT; zwgX(N?7ddJFVoef`4!d?(7ksIs{?fJMX@?T_n!Bgbno4u-W|}r_bb*2=-#`Fbq{p! Q{fspVy7$u7eXy+m000u>x&QzG literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Debug.mvsm b/release/v13/source_maps/Debug.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..c9280d8381d0ede4f16bade7da9df5a909481d6d GIT binary patch literal 246 zcmezT+`~|1P0Z?~N3y)@6Eytfvv({|sT2*)p1Xiy-l@3W00stzP#|UmVr0O`>XMpN zn$Ez)!0?%X5s!fSo&zx>V+bLoFM!Hkf|XVfQu+y~>@yGp0V5+pH|PP~Zx8bWBLe`m CiBD1h literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/DummyToken.mvsm b/release/v13/source_maps/DummyToken.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..3be6adc988c1576a508041dc98d9ab2d48e65411 GIT binary patch literal 2528 zcma)-J!n%=7>3WyZxcy0a8b3YQXKZl-`hTpB9G{)q>f&U*TI$9|ds@c-?RMBrtL&SV$ZPTuI zyqb>8yvUxG?7n2?J*)@dlbL>>Fa;fsjN zpzC!Os|>md&#_*EU)Jjl)_Vv@^FG!G2ujmh4e;|-9M*Y=O7jcWH`pf4Cs<9`F3r{%iAnP> zd4Yg2?b6(X)eAeM8N%8RJEi%Hw{Jj)H2cWw2M-5y9&HJn$kq=eTb-FwGj$Dp*{0i3 zk$ZWJxo&Me0&y(GNl>SMYM@451#eZ{S$SonJ+~4*EX0iM0ayKDdEZ z16_;-tXH6?ypHt}^pvk+t%08M*4y=zZ;}@adztc2m|sCp`5<`-&{KXGYZUa9cVi{N v!v%W@ZPBVc9!~gO)E8FwMUEX$j-*bcGHJ)OC&yFiteeeb-0_K#F=PG#n!Y?p literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/DummyTokenScripts.mvsm b/release/v13/source_maps/DummyTokenScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..178119a6ad13c2f4337ecad109f5ddb692f7651a GIT binary patch literal 990 zcmajbJ4?e*7>DtbXw#dix)uB+LWd3_g5siE2PsVkktEWlgF~h0;AJfi4t|9$LO~q7 zEH0uFL~#{5DuSSkgHMnSPXEBO{m%R5oaFZCZN5-he)(zC%0ajDHAoH@I`0+td-fu# z-oHL(jTw?<{(si=TssK1R-+9+Txm4dH{(`n5;1N&XUq;6+iCfs=Qq`XUGM=p^&o18 zvEn`GG1FeI$?#Pl4^MHCHTgn0InZ~3X{pq-r zPTm-oGE#oBxrB729KC8*$|~~~DJSI&YKihvmQg(_NZCd0QBleoYM&;g?4!=emGT^Q RNhK*yP**f5WvZ^pm|r})t<(Sj literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/EVMAddress.mvsm b/release/v13/source_maps/EVMAddress.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..aca4d08e4dbd2f7a56163d15a487694085e48ae7 GIT binary patch literal 3461 zcma*qO-K}B9LMozoORcAwfEIZOKn@rZ2vK$qifOosb_lW}qQEe) z7YZUFOpQ*RG77S?Ylor|It5Ws(Vz-WYQmbDb>n|Bsbie_&5-I6M%EM){pzjM?cirj?AP z~cG?CpK=~MP5E0`c}Uu38wu8Z*-?Pevuf1e11)KNNF zO%IuBy_xSb{{iW}aT_&DdT%&qY0F*oig|CyCFKI@GbKv-7WIzYQaby=Bc+!+kV#2W zI`_*fWr%s@lq{vQ8+}qXFmE@dNZE`!M5$6XqMB%tl(neWv_#4g)J0k<E{ z>I-E`={#|3rR1?NHf2faL8Vc)lrEH;a-?+LD(j>SGOv&VQaUq(QnoN}FXc+gOF4y_rVUbFL0zR1DMwM2{Dn{|DZ{94 z+A3u|s)wqj97c^$jg-z)yiH2yyKcLb;~e=R8EY~BId#<5)$QwOu5a1Z)?myZhY*Cz literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/EasyGas.mvsm b/release/v13/source_maps/EasyGas.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..34dcba80ace1339e608aa91d144fc9ca281cebfb GIT binary patch literal 8532 zcmb7}X>3$g7=}-$otB}?v}Gwviy??0qyk10BLvD)Dp6aIx<`g#W+-FnwDeA`HA09Q zAW^_VOb7%OqXw0Nf&^j!V~j>N5sL{S1S>%siNGIOg19`F_M-96d+sF9zvrBD=Pd92 z&P?Z_6XgYgxuuUzIWm3vsdtYo|EWB6BCu@l>_OwllvLbRa=S5REM&lcKN&fdQKzjc z>SP+zDf)=xECCZx=Brp6Eqd(0`4}?f*dGOq*$XC1jeQcU8TbKa9? zNpmvuPz^z8mSNREwluxXkRwfR`TIz74I{6EkTg?R>!GhSy?u}?&3*KD81kff6ze$T zOLH^U_fR0sK841VKv~+^L4^wAvG1hR<*;|BF4mx`a zdrh6a`IuqQ+3W2}oxRocHxG37PQY3OI(t)COF?IE1D1PwboMUpHFfqTG3!BRuQy92 zGMik}J-LIVxf!bi21~OYYdZ{)=BHR+!cb}M!g8OpRGK?`%`$23!2AS;NzY3h~r0w-Lhci8sjaC6OmN3K~DcTT2=hp(n&YB z#L`wRAEQ+rpbYi{tfF-(2M;yR$cjB`W(ZT?O}y3Bca!_* z?*Y(vlX9$CpzkInSY@E^CjGEBfxeq8!&(FSZsK6A1${Sp3M&TsZsMA+gT9+|VC@I} zyU^!Y--7;K=sm1$pnn%ShV>m-Y^HgnYyu?RA7Whu9ZLl~~(lr%tb(RZ|_A PSy>sWt$DDr+L(U;uOktk literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/EasyGasScript.mvsm b/release/v13/source_maps/EasyGasScript.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..542d275bf104a5f527fc31776a76acafd1d7e68c GIT binary patch literal 1928 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 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/EventUtil.mvsm b/release/v13/source_maps/EventUtil.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..76f76ef5d13d8446a741968fdd5bcadd0d40c534 GIT binary patch literal 2461 zcma*o&r1|x9LMozCU?!&cGW{c)F~q9V1bngT_mQOSa)r9q%JZL4pG($>yNUagAf!# zQB(w;>QtSAeo)aLP-H)#4%MMTyL1q}c<|Qy8CdA{d4%^xU;E7C%=4WczEu2OD9_!R zo^O2YTD;l4bfEjq(KGK$cf5s*tM~T)*MJ4t^2WMgbJZK$nW!Ol`HwKqoTyT~~*Ca<^N zo-?M4Jb9ykvg9)PQtoEG!?aGy5LKZTDYv1jl#|k`L2~$)PQe=F`rO8`)0uaBZr89k z$leOM?+?H)c5x{mqn?m{5>|dC2YQa9e%{W7;~ZVUUe5e@S|8D8_&WAB8B^5v;vMjl zU0mLa7pTvq@5LhOFX>acfU;Vj${(m+-&gC({grvQlf8^x&Ai)NVHYoh zJ>)V7hj3-mgV2K-AUz1p>+3<7VZE!Q2O&YFq+id+QLm|0KH~eRm!yYl7WInsa5b;4 zhiemGbz4af*9uo&BRyPiQA?zUYbRGOlO8Us2FUmwK@=rnC5)3O7!3O3z?jYUS5Z)_ T4n+rpq*9HO;6zx9Yo7TBX-UL5 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/FixedPoint32.mvsm b/release/v13/source_maps/FixedPoint32.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..caefda270dbac2f6d24a7bbec9e70354e1bf28f5 GIT binary patch literal 5001 zcmb8yU2Icz7{~GFwCl>YGGS#ZY@$){1@Hwlnka@0>9Df3%Um}!XxY{#c5dz1+Cdbz zsWalm5)$W@p(dE18|W3vh(@#B_<~3v1~X9Og)euS81a&b-;;QZcfaG3@6|s2pVQO! zIsY>={AzS=Wa4tonuXBpOk~UXr{CM$vHR;E?`t2tv{*lTsl&{=$)W%LIg!TPzHFwY zkjoeE-o$@r#6shkX?GPz$>XS#6w-@ssxfOM3smGwec6G|Vqrinza8H~RhewQ(3i{m zc})kti^_s)Z`!C1uz!Ww>$GG~sZh*i^F{T7`@vhOX0W@nH=9ZSj}toMNuhtqIzhBl)pYxV@) zDrG0?DY{L{CsDg;os`X}N!lRg^QZ~BUCJKRYjlT{-qG)r@+9lc(_K=|p+2XLQXWQ~ zA|E%oBP-25By&PToxP>3y1jpdop(LAMR^{-0skO`k}MG9jMe#8 zA*(5z$qnTO^@gezTThPf4bQHnW*M?o`hxVZ@*a0}dFfoam-Lq6S=4^gTZ(FUAHwxa-^+sVc*L@4=jlu({he>Y~notSS8-+M(2UW{Yb1!O` z^p?VvW283w$X!;CoryBD!{l#ZzlA(Pm3^h&Vy?e8mz58}@4`=z6Yd``$4TG9=1>cyhr263BR#TDpw5zh3Va{+0qNmB$~Ag{^l*O;H9|gy zJIcNGdbodz`ik^$KZjZ*J>1Wr&XOMPpP-zupOO7L@(Ssvz>6p@yN}`S9bFIi2|$k=V9aBH0{IG_)mKdE>F>R8w2Lr78YU oLmMDy%m2mct&gQ2kF_QP7LB#K|4k=TZRuoVy0sy(JyvFa12VPz(*OVf literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/FlexiDagConfig.mvsm b/release/v13/source_maps/FlexiDagConfig.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..16fe85326ce572e177b817932374391cb3afc167 GIT binary patch literal 1116 zcmea?(Y=Vd;#o<^HB)~pHZ!g}4R?%q!YT_tx}Mu35~J&+&cMK63dD>+j0_n0+;UPY zGF=kWo%8e3GSh+b-UN&)1*&NVnZrm(r63angCYPfSkEFU>0< zWcWUy>Z3r+D3Av7L3~PLdVDh24}^3+2kQC`vWu0lyA;_O7&L&Gkzla=0-C4^RLMk8 zCCq+if-22{=D7ng3sEW~fGUY_s0A=OoPd~tiP)fa2CDV~Vu94OwAAF1%(B$@jMU8Z z41#eK3e=PevWfv1IE12Q0Z`#`ASN8tRX|lMfS7PlKLo0J0mOuZ`X5jg9}6)-{R*g( zAE=U*ppUizRSE!A65-GZz-+P@h=IwO)IeSW)V2kr6=)4XC;bAd;Q~5~a3J3Vs+0t( HWMBXQ$1!}b literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/FromBCS.mvsm b/release/v13/source_maps/FromBCS.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..0ae0e602a1269b0ffaf543f0e374c23826d6806d GIT binary patch literal 1090 zcmaFf?G=-7B4BP8=cG+l3x7m?>huwfoBSxt`^M?Q=E>c)bD0G zT4G#V0aREC#Dra&4pdbIGM1U3Yqfx$G6Z>yh_E#RsxtYjkq660Dyp#4Hbxt0;AN*Lr?R)Vgb2(*0~k*=K%R5ycI l*B%BcJOado!*&Z$)lrbKjJ&R%eqoM2o-XmBA#N573;-?}x!wQ( literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/GasSchedule.mvsm b/release/v13/source_maps/GasSchedule.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..dc80c7b7301d6816700c10cbf94789bfee5ff2cc GIT binary patch literal 37488 zcma*wcUaE**jpUiagcTF zbr9d@ef=)i_51JTT-Woz_qiXhKA%sH=IJ^#uVcjlNp3!4T>VW`2lEZib; zV0M{yC9c@DFc=K&$b|m?KPClQ1;=&_i3kfF78Pb{Fmx5KxJ83@^xFrl!trYA`G%{W$%6 zqfF$^rfl>k6Zz18W21vJC*{s`Hl86<`Pj#CEvJ#G+-YEAGcuJs9ogtirgG;wHeMt% zxpNsCQ^-v2d{Dw*XwFVExzm-6)yYimT+YTzWG;86vT+@m%bl@oj3aZo^CkD)jh*Il z=V&%wCJVW90~^!GLhhWy#!Rx1J1?@+ot+kP=SwzzCQG?<1{*h$rQErdjXTIv?hIvP z3|Y#Zg}iw}D4*OpfQ{*tPww2s#@&=p?u=*SYRV^fy0ft+S;?K(*m$3;6yzv#^W7@H-WfJA1Nm z9u<~5>#(sY6_z_c@N8CRXJNUs4IA51VY$V2ijA|WnB4h* z_n`oG7Lz-TAIKEugOlQNXEQd2Q*pU-E*s}jak+CL8&^^BU)pK>fUAVuY0t)fR6_1t zz{Z7CLhjte#vHPd`ZDBXvXS}#jeLh}rG5=N=v;Va)eR;rK@E8q)8dM^D`Sw zEjTH6o?+t)DkFFHXJZtVm3ndH%2ZbBo00#evQm#h9!TY+ZjbCh<)m(BYcN!ya#F93 zJc!Cm-4VGOm6y6FauX^q^}@)5jk|Y{SNIsw#K3WaD(IDt9KaF`25$ojuq%gR07%8Eo7`j&kR2HfEEf+&PYo zYsgXVoW;gDz*i*;t4#vN*||FWLBt zoaD~SY`jfQa;F~~7m$hdZ@b0^1V5hs>If-jInLOmq05*0c54p1)8+((7+_{IH zHth6}JAYo!8gi!x8#_@Axw8)&gQBq({R8#83kULXNsfQqkQcbCcBhNPK@+!^a zPR=J!xpN8|=aHw}>CMJ4@{~L0vT-4K%AG&&W-Ylhk&T&DOYW?~#&D`7cP?h*5~?M4 z{`@n!w%oaujoYZU+_{vENmN_z?8e5WR9o(B%{}i&b>z++Y}`q8}5Se?A&&LM1EO_DyMPE$5|QERy~n~g`QwcPoH>sgMSZRE~AY#c#ty>a_4DwmS?A*+&PMkqsdS19Ky!2rw})??6689i$$Qyp=jgy*_dS@|XGrkQ-Bg)SnPL|OrA|_JMs}f2QXh;whB`|<1^Fd) zmU?w$H|i|)S;(8Hi_{(S^VxCgBK3FNb9eMEQs07{L0zTpjoh8ON<9bN1HG%%vyit^ zH>vkT4y0~U4?`YE-J~9eyp6g`y*F|Yb(i`$OsicsfW}(k^4{&siz@tq#jbw zMSep)rEY^9Og*K(33)U1l)6bxzK4YZrM?0=g#x8M7gV0zCgXD{s{RM^_KcO?zuC1kkl_BU#1|b|3I!*mXlJ?L3cs#BlT3| zE7V8o&d9FRN9w(h`%$pery*aZV5z$yyHl{#M<6e!zEbChnGDv{SL$!L@*e1YrTz!< zDhiQ$8DtL%k@^+%8t5TXPe4wjP^s5Mu0x?xAB;SPLZu#woJ3(#uZLWp!lXV6`5=W! zy$y0Qg-g94asvvN`eEd33YU5g@;&M&^_M*F4bl5a{TT9b>L>MA$VEN*o^Pp#BM+ho zsmCGzNfA;nj$DEwr9K`xfg+_IgnWV`rCt)*mikLQ2|1biOWmp*-|<5IrT#Zpz7+ZZ zsiz>Xr2$f}g4~$~Nc||f9eR}1hajg?l+?Q-cc&<+`yqFsXsLHXUPsYV?};2p(NYgb zo<=cJzlwa9Vx(?^+>2tQJ_C6s4V3yzq*@gy7Jq!6Z4VHRCi4e=YF z=&@3Nfcy`|O1)q$KJQCIrS6N|frd&w1^FQjm3nJrKN=?WKFAYknAE2rKcZn$Z-?BT zhD&`i@)Q~_^>XF;>OT#a`giVm2lNqApN2f0Mo7IbauAJ>`h9eN^pR2zK%PM(r5=nN zLL;R<6L~R>l6r0AnKVl3VaVY$O6qHo@6%|h??XOLqowYI+>b^}{Q>er8YA@_ek2+G)C%=k#lLR)W0BqrLj_9ft*5PrM?vT3B^f05BWRANqrmgIf|3|NaUv!FZC11 zKPX=67mzPeywvS$^La%YC-pRBevN}+oYb!%U!`$U_d*^`Jry~J#!G!H zay(6tdP`(~njrOQ$k%9s)W;iTnke;-$en1S)GaFTby%7xbq}LVlce4SxhqYQdPU^g zG)d~kj51A@dOhTBG+F9(k?YfBsUJtaKvSe%8o4`7k$OYqMl?n0_mJ~ws?;YV&!wqS zFNWNhrb_(>GT%sSm?rfEhE~oz0jvg-4xl3rb~Sj@@ASY^;qOMnlANAyzS=b zGo+q@oJljJJ_k9CW=MS-x&``7sn18wqM1@pN6w&`Qg4F%8_kmX5ag{iOX^w3TWOZm zyCILI*;2oQoJ+H%J`Q;s&6avR@;I6!^-suVg*YkoVC3yIN9q%hC(>N0TOeD~T&X`p zeou3y-Wqul&6Bzna(CbCIger87Mb&qAx$^nZmqYtH|SK_49Ya`F2 zRZ?Gxyq{J{-3GZ7t&;jVT$>iXtmT!BbTAoQqM&$T92>yNc}nT2TG9oGp>AD z^aQCFN4B9vsaq80Bqd7yEP6TgM5)^%m!c%8+ai~uB&oMU?nX&czrmHaLr<1^Y2-4L zEcFQFIg~8*edwjp*GT;n_q;6n8mZ4iUPx=C9*7)HDN?_IUJgA)>Wh(=P>R%tBQK$~ zQg4IYnbu0Z2l7%{EA?f_D=1a!VaUTMRqBnAmr<(JS0b;Xby6RJJd)N){RHwQS|{}g zZ6gz(0Zx=jr@t$OT9I60&S3bSLCs@LF)e@=g|hKKR|v#X;N>197kzV|AEXe zi87=~{Tp(*`uuG`>Kl-^(nhIYK{r9)DD?`+l_*{6*~sT9UFti~P0`b(UIp2nHc9;= z@+I0N^@_;Ov`OkOx$+L^o27mQ`6_LedK2Wfv{~vG(W|0wk@|Mz9NHrF_Q)M*i`0XW z2T+F8mm*)I45_;!`%{M0#~`nzOsVsWeht=?DfL3g0hB5Ab;#=}OX_8it5TNKV~|Hu zmekXbH_}$AS3`E9tx}(Zyo$C;JsLTkwn^Ou*_F0QJpnn9wn@D`@+R6Y^@7ONX}i=% zBPY>zsXsz~MLVSalIPtGeTUQok&|hM)PEp5HQ=WcrQQv>FYT220pt_3Q|d0ruCz<) zLy+TXm(*_~zo1=GcSClk-BKTqJb`vg{U!1%+AZ}rTzL=lJyM^9Jel@L{S@+R+9UNV z=rz#yN<9>L3hkA8I`SLZEA=7BV`-n%eUYcqKB*U~!pB^+PwKOgchP>SXBlPMFZJrk zUbJ88dyx0i0jZxszD@_E-W1uJ4oH2!QKo}Zzkz&{4obZ=ax*$8^?0L9hopWR`3@bD z`d6N~=IDo{-p44@VW}TLzDtLt-WxfB4ojV1#A2|fBT`R9zDGx-9)~=aj!3->a%;+# zdj6t(-!ElLeLnI6%9gqxa$7nob$jHdbX4m7kr&cYskcY&K*yxs47oWSle!=BB047Z zg2?`KTenbVBNzkIfu?lJsvre&Psh0@)$ZRb=yXK z?t;!qy$^C0os)VTay*@rdJW_NIxqEG$dBl})P0c0(RrzNLhei#r2YZfP>hpOcSIgf z7o^@5xf@-Sx+$_5U6lGRQ#`t(pAY@A z)ITGCq03TViJVGTq<#wB3jK=Izai(*6{+t){yZ!;-C`amFkiXJ3sdq>2LD!_-%z@uWLf53e9{C$xmwF&_FS;)Ep2+j*y3}VN z=h0tMZ-U&L{*wAaXnd#=!VpnA}^yGQg49Voo-5f2J#}hDfPC< z%ju@ndm;zYEvcs35YJrg;LZcDvaRepAWZcE(?xi{UB`Znb4 zbVuqVkk`>2sgFjUOn0Te1bGMDmHGzcbh<0`70Acwp43Mm@1%QD-;BJ4?n(Uw@=3Zc z_4~-r=)Tk=ku&JN)Tbh!qQ9m71=*rFC#Bv7Ig|dDdIa)mdLZ?D$X4_~>bb~o=z-K9 zBfqA9q;8E|fc}xXi6g(og8q@Zg%`iqh#pG)1y{Zx`a`KZAUo1Ssn@k>g|!& z(!WyAMYe9j@5z$-0px@9QtG#mAJI#x7ep>XucUq$`3Sv|`Uhm&YMhk%Ro?cZ=&z-o zjGRrcrEZ5@j$TWBCwejTH&UO3e3afuy#jJYdLwl=Ti(0(p#zLa^)+bzm>Wl zay-40dVv!B=}qsXehR%Z`a7wQN1j0MrS698LGPu082L24mwE%_iS$A0HIY5(gVb*# zmv-W$)XO4IqK{I~ zJsNogeU|!Ju6$+m&r-KQwxs{0J`H&*{U`M;=vC1Fllpny_I&7Hq`n<_Cw-B6AaXc; zk$NV&75Z1H??&E3U!^`Ac?Eryx&yL1eUthqMM~G=$q7AAP=BCsrN+QM|o0D zLQbYUsYfHn(08f7NB(Y1>Ji9m=)2TwAP=M;QZH=7M?LgI>aCGe=!evcBM%~jiR2Ho zMrVjECNm!rKc38MYZ}dtN*Q07iy#;O z&OtxY_n-%-dXc^do}7xHU$_ZATm^qJnElFC2;gLA${!gMJ9J1852m^nA)Jn)e9>Xi zzj8j7v!ls)v*oqh#K8>G*Djk=XGmYW^PI{d{rsNg)H%}6?-EYkr(Zal$-{ft_yF^d zslEbv94*l5SFXTKPTF$v7v727IOc0S%AZwXF++z$hRNG}jN@m>!gyZ3Glg<8(g^S? zNz?;0opZ}b-{Xy(N+*4fqd2vb^gaH$RNv$Cyxtwse@6YhR+jQ@|Ihe(zwyo^Pv+xP dL9&u3b9v1|oXjszdUC1(S<91lobn-q;eRe6sv-aY literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Genesis.mvsm b/release/v13/source_maps/Genesis.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..41d1e279bdb026d066772bdf372151237ece8bbc GIT binary patch literal 25235 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 HZds{sZEvBt literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Hash.mvsm b/release/v13/source_maps/Hash.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..ecc3c9d3956c9b8ef93d311817707d81e090adaa GIT binary patch literal 437 zcmaEIZC|7QTqT~!9eHP;Y81AeE)EX-q!DuWYs_WeV;j4jq8S(%;(?eEh>-y!i$`K{ z1_KKN!xI7~xC6BYg0wTTq$HLk5>g%nR2l}cjggU{;q5?`6Noo_B2ej6sNqZm4L=QZ l^ktBziF5fCpvoH{E~ULd3vHp43Iqfx1}LI{Xo(t# zVNft61Z9kXG8inAjA9HBA2gAnCIkZw8vS%CRtZi0}y=7UJzKqGy7XD2y#3CtIL8Tl8mUi3ZO8VJSCjTGfYO4PMS zz2RIPaIT)d`aXz>pg)}Fu#zB3evBDdB@ivmbS!VjNOL6CJ*Xwk3aqsdE6pFUeuCQ4 zT#xlT)RE>gtW{7~n!z0zrhWjQehQddY$S3PSX-4Xm>=5O*j%#jK1+p9-c~*^79@*O#-h8|#=at5fF0 zbhaum&&qk^t6-g#ySVrL05Rd*oY|^PVrP)yP>ZJ0x&JEW>kx{~&kGxx@R4`(nU@6J zgNJaBdSA}=daRA0*Kh^a9nc@kHLP2p!~Yo8ZP4K#jIP7K7jx7Xboj?$C4dh9VD9V5 z`J6(%X;5F9VXOjZAk8$anGh$KO9xu&f)H?+U(mafH z2AWHA7uH#5AA9i`@q#ZdKf0Y*7eU8>w=RKUef5~_Tt6`9bARMyu;%k5+*}CRj(_t|7eZ8Y=Z-zp z$#Ux)UJ8|%(>ViuEU;_J$$r2!{OvDWn&+{u_$!v?IV^AMbgsf0#FgrFj>qZ^I-TPl zoBB|>3iCbC={x~zI_Pu`=3b}sLFyd^oz4faj)P9;FR)I4PUoPd^r5nvdiO!+_+6}r zpmY2NRt@MJkEiXsfX?ySSY1KqcyRCfP?=1<0?>!bpk^z%I^Lq*GB7mLh#cqAz#LlX z$Ya48T1B|?AUfLce7gd%0*o&<_n;o|wG9uqr}55#pATLkMLypHP0KG#7b8pxosdohQ4!Ixe80a1HbFAZ_ zcgW3He}dklZera9y+@tIss{b65sa>%HR?yWM$oTaV!Z`=hirk>8uSiX!`-yO)URE< z)fNm#qm+rxWrI1oMk7xGYjn-UT?ocweL3n%@H>gz$W9~v=xa-J3)T+MdEw0qU|0%k zi+NiJ=DFL5ycw)>w-5I)80YSL)YIT^Q_e^{PY$g>&)q+iY>jDH@@cnT<4fHHdA6kvD+u-|1L|p!+wB z^&RN0+=X=%bXQhleGB^Z6pXGuU)<`QVmEz!++MdFT{2zi{yWhP!kVGWCKoXI4uI N4m^;mlR(VC008z<8W8{h literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/LanguageVersion.mvsm b/release/v13/source_maps/LanguageVersion.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..e8e96ca7a30b05d9e0a3578d27042e22e6870ed8 GIT binary patch literal 520 zcmX@M;@qn}le9ALRcAAMnItIWW_UU%?geKB7#H%s8An>3A-7j I(iChg06>=1D*ylh literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Math.mvsm b/release/v13/source_maps/Math.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..aa3cb9ab04b99302472ee6aff7411159ee5e3e6c GIT binary patch literal 7919 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 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/MerkleProof.mvsm b/release/v13/source_maps/MerkleProof.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..731fab4046a67b3de8e7a7aa939abfc0cfe6ad84 GIT binary patch literal 2603 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 azIju#)3&8K-nh2OX=#l&wl+0yH|94~!og<% literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/NFT.mvsm b/release/v13/source_maps/NFT.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..20e778d33f4838649ef6d2755c7d35fdf45d4ae8 GIT binary patch literal 34306 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 N3BBV-{K*J${|_Pep@0AY literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/NFTGallery.mvsm b/release/v13/source_maps/NFTGallery.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..6125477ba1f4791cfa8e4989593befb516b0d68c GIT binary patch literal 18809 zcmb81c~Dl@8HW#BK-_VO1hH<2D@H-gxNo2Wf+D7BL(mFFtb!55U^Ee;;ua0Y)O}K0 zr4!uHy2PMnqIITmX^oj!9ciqi#<(^ut*v{X8#y!WU%z8!o`2%wd+vA7Iq&gH10aCB@%baD2;})|c)!sc6(;Oqu^IW9osA`TzfXf|KLZhEAL| zEo)|>pD_g@OxSE=BEct+zcwN(f1>&eFC+H^UnNdKnhwgFk5ddj(%gWx6?|QbW=%tCc3zsEfZeoDN9^azyK{Vih#fbwSH%mH6%t}ig=x8OWq703rb&e!)ycR*dM z;dA>!L#-CgF{T8ZCu}kDN^qU9GTa^D^Fm%$PG;6jb?y6c4|#sz8_#x#`U}I}HYNp3 z1N~|55%`f8T;9SfSdT$ZcOAx#0Y4eDHkN1mOEVB_#av?oq*;NvA6}5=e5?ZyD9s>7 zt_MNVyg5vnt8-4gu2pv8><-VN%I$2GoijT?QA+M zyXrz?o`UmsG_27;56Ar30yhF&w__A;40!8Xe$a`CQ@r5P9EOz*dV6`+RB%wYenhGP z=bN_^c^|mmyi>SegHJ&2>>QoSs!%V3x9a5`iTb56(V*{LBdi$E_bvp>vvq2!k2MB# zYD&OL1f7}&*O)prZNmID=+rbF>mAUk=@8Zl(5Yz$)=6- zwGs4kEW+9Z4nZ%Y-2&%nzKvWBuG1X6gysxIC z*J=ZqzU)d3k*2-QM$)t~8%xt(XA^18;B!|%Q)v#w+6^yC^DNc{XeQ0mSeGDFnwPPz z!b{Su#JUDy()6tFz+of#uV5*Ib3$%_{35s}8cm_DUHW@DLQ=d2>P0dZs0MXbjA_?g>7xgGK1pSiKhP2^geefZ-w^i*#3N@H5% zx>kfY@N>W?TScDBRm=nb>`YzoW^s#WgI{*$TPkpWyg{BjEh|U4m0ao(aH-I{xY#{V z``I&*jER|<^1;Xf*3eNfgLQ#CkM}L;0(l(k66gYH$JgCk5O<*w=u&!zksD*`QhFQH zvvn!Gfi;epx|DXrN&#I;+tir4ly1h{4!V@SiB$}`l-iA;pL2Xgyz`)o?is9aK^NUG zur7gq&S7_eF38 zC~4Y;qN_ANAl_PdS(@{))kuu?i&%FcMw)-a`T=@Kb05~$@({n3Vl z^Kmf&c@(%F7pLIndIR`OQpbWKv|>-yC&le(J3ZCuXtJ843Ah|hz9Hy&FcJFba1-wq z=%d3$tlOZE4t9Kfba+6#$Dof6K74jx&_{T)wgkVL2J`jY~nEF6q zW9kDz95IK1J`f~gC4oK=497|UeIV$M<*ht@ASlLq5A=axA=YBh2ZB7TC7=%k8?d&4 zJ`n7}+70^2-gc~=pr7om!MX+d=x`kCFQAVO7qF^8A01BB#MDOzJGwqPJSL{$b*4T# z_+tftK05ed`GGz<+-LMYnEL1tiWLR=K+v+r)CU3^v#l&sBZ)a0^wHr}te=8DI;3HZ z0ey5xz#0Mi=-`b!795gY{=3F30_SpCg1iD;%js6!?cM-x@70f>9`kfvQqQ5C2d7tI z(M6=yVlLb9n@8*B8}lpB4=5)Pc_O$J_UlBv3G5!Z*aqOmfiBh&Sn;5Xbz3aY*2TIN z)-uq=`ZcT~(8YR8jj4$RE95YS~k7^@lRvi=fQbI@h| z4xc6*Q66msSca$#c`NW$Gx~ykn%>!N5?XJ^h{SfhvfiCNn zSYLvEc6bu&6zB%vBdpV)U)X(*^#F9Ma1rYv=vKkbkuKJuuWi?xlZpWdYsFC82< zXF1woa4thfkdK3F8LGm);tk+dhW>^609=xKz4z#C!Q0$2tG|o50CZL#k2L{wR!_zH z6m+iMgtZ@Zt}ekk06JIO(RHpi3m6%6u0F%amqF+10mMrNovTM;jRuEYjgWuSL(0oF#) zJ2zg zp{49rBC*LP};UTEQ!7CGTK9(S^@M23d6Kg8yD&?6g!J#oayM}M|fpZUY9r-S}-n)Rctafny z1xpj$Fz~CFnKdIfFFQXYs~{^UUv?a=*YR!{00vYZ*&dis#1ZJDd%bm zUJmG49fOq%dRFcDy7wp}-fqynM-f&D=-#6c>l)~e;sn+eaOfzou7d6;?C83qn8d8+ zcrz>Ks5jOS&>clJ*Z2yi?kMcK(jA3euezgH$jHY)cN7n>g4VmdmN|`C3sZL#iC7~+ zcN8tKMuF}qJS!C(Zhd1?P1N(`r>@Ac&yk--;HH6VeoDuk1Ww6)58^>DxLl0Ous#Ew z20W`099HAedHkpfoRj-WaS3J>B&uH=U7Vyx1=1 z$jOM=5WtyJe+Ri5^B%AT%x~9-&is+Y>k2yacf*PS zo%x$%^#F&XY!yF(z6s7r;TG~gz%?n>x{gYt-A^9W6)c7Gu9`dw{9U;Iq0qHS=+#21>IY2%oA{)?5D^tyzf5Q;ka$V^_MuY zxP3fdzYI=68wK7ik#kpuxE=J|Rbm|mJ$E~?j)0!K^;n;S!%m&NjDLp!oM$8tc@DU4 zzf#<_;M&lX<5qaSOWnMW_y|aya!SHkN^L+-Nd#6j=qY*1*fE%TO6-;D?er?~#)Gbe z@mN0tT?zYPm4L2hYn0iic1~$KYwP-e*upN6&?Tp literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/NFTGalleryScripts.mvsm b/release/v13/source_maps/NFTGalleryScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..8b6bd42e18dc97941405360635a2b36f056777bf GIT binary patch literal 1205 zcma)*Jxjw-6oyX{tqv|ybP*S~PU+iz}&w84`9pVjNR`E0RV4x-v@DGFDr6>&sjW!&+m$SK%e9G?oRMeV>D@&zRR z__ANq{2SZ{uu_#^$qypUf5UBpnA|?IB{B?_`kz0H9Kp0zGqFa&VCca%S%7hPm&gq; z4et^66->kXz-@t1cw;*v6QGBe!g4_mFR`*6=ItRLf@yeHxYytqHt!zy z8SK#4O4>sEg6=3N1!1hWx{d7oEv8d{laq+kpf6?yD-Zf&=CKOksQn+rT7VAKOsqu^ F`31%4>AwH~ literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Offer.mvsm b/release/v13/source_maps/Offer.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..60f93aa00153fb9407de63e1031ce5e6944fe0db GIT binary patch literal 4119 zcmb7`OGs2v9EZ<5oGEn-df8jbidrNYN#&vkI!0+TIM{P@wV69&nqxDDK@{X7%IpPE z6jT&N(Sx9sv=PEpuSIQI6cRnO$0jNgqUgKPjds85z_%H`^E>DM?>YZ-2S?UfpXQhO zn~rVoEl#XG*t_?@qtzEapB#Alqpfwz@rqJo%mVPi|36<|Je{_){5>cVF5+APU--`m zJEaC(MZN_ACH5ipgYq8WJoex{$9V;LI&xKkG3&tdL#;=ycLqcLoezsV!tzotjH;>OW^lp4q$o+-O3Uz@LZEd+>} z-bvlKhar&8WL5SlyfaYHmPxi+9d@=QBX{a${M+Cg+u5?yww#e_n)~Pv!BA7>KEZqE z#7px%)>qK)a|mk~0y5KGX;7NwL1UIfo-}K*5)hJR1J-5;OLHsMb{HegN~{!&mF7aM z#gH#e8!HVSNm_^|Ee3T(qI0Hu4GgdOB7CiNgeTY5I9P&xiSZ$#9m}4FR51T9% zGG+&Ou1PC$7W`g&#$M!Z7+npIGU6PB0`p4C)j2&8Hl`1}w3)Yr4nv?l)1`77$xMRR zcK3qZ*UqAIc6-W}9j}b&rQp4JeIWb`m=fK*#*mlYh(9O$Tscv5G z3(?K%UwP$GSFO~>pe`9<~^(rFkPDN z>@%eKlRP%3nJLX6Rs?2A(}xv+5@~*8_Damz(wv929Og)K9M%dbm8LuUTxnL5R|`hB zn{=Tu9pL%G+l9Ob{GnV+bGz>9J-8=ebobq5M%)3P*SqE=@*AMb$nt#0`{jg7ldfSR zps#`<@`^C^Rp72vzng{REe3rRM6v2Xf5$Gt+5q}0h+}O6eHBc>+6?+T*0HvL@lS}x pYigniD;96CHpc4WRkhJ-pPBsk-|AS@s);A8HC0vdjj;w}egjo?gO&gQ literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/OnChainConfigDao.mvsm b/release/v13/source_maps/OnChainConfigDao.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..a5978b1242d79384904eb66c7e17bd8ada9294ed GIT binary patch literal 2756 zcma*pKTH#09Eb7uT3SHLA1f{nLon>#uKExWBykbLh{J za?9$&$5WG+=k7IjcRgvnHhg`xGqG}WC1;GeKo& zVzciUD@fHFt5Rw~09@-WP_PXY_n#xm9x-N`{GNFR`;`2ic@F!|+rO!=Sm-O1+@kGdGDWvkQYTyUR@EC*x3SR4+1ZR* zvlYLctk5|p*Y7Gm2)#(APQR#C+%Ioy`AXMOp#}~w|WXlrK=TR3qhU)Ew1HIfi;eo22yAJo)&NKJnZ5On&G73-%lNo%>)F2PP|A z%J$~nq8h~=*j*F|rky^8+e600D00@jXY6dL)UTh=#_os7MD?&IaA!yldu3NW>}B>F zAwBFvs9U6m{Wj_W>0uv5jgcPq0n`%dahpXgQk@*kDbxpwNLhJ$y_9v1$|x#zp+*ggP3;*?DW6?h1A8+3~%w4xPxxm&bT?}yjs!<-%s98L%z*2aD?=| z@Cr3g`d%1Ey(N7wETg`Xz88|HHPZKjr+$#JqVZ(X?oOoa_T#C}M6#RZ*8n%5Hb>+?l!U%)R5>8E01t zqoN|xABBJFM}kzMk!x7AScVwNVhZNR_Cfi9L>W|;MPXsjncV>k;yoig;*aM&=bm%k z^WM3y_SW^g-v05$?%OMdnlHq6HVrQPBJ$J0`Q6EuzwdgecW~J>rPN%Az_ouOttS7Ivc8LrEFoum6MbTAW}IR+9L&|k@GOF(srC6=VzsWEy!D;Hk}F5 zL1-r}FDk{nj=vL>x=vog6~wYmy(!YL-(i+xjuXuatR^TE&3%m7j9D(4+G+uV2Ynjt z4H#G56ZE-$&p_Ih*7hd)ZZJK^L%2uv6pf?j;$|#68qK(2D9v<%sLN2wfnLS0nXC`A zTt3hT5Z8iypbulkKt9k;tT@OAs;vYV40?roIB6Vez3FA>#GVRGIp0aTR>sb{R@TnM zUGW;lh{{8IuN}HpZ!&QDtgM$Z4gY}9W6)Lz&$xLz6SdMDdSN8#$Q#O(nhsO`8$G%V z#&KM^62utc8EA6Tfs+_pgHa9ngs4+6`I^N?y;#h1a>?v~mG}H;ke3$GPU>|*TgvlG z-@uT_7YfmKf9cV~M1BJug$1M-qOfzJ`4QYeC7cJX*K9%D4y~k@^2FpBAaFBOg;||) z@d0VCjv=3h8n@qdtf-r`#gO(2rEY{sqZ9a{>xa3};$OUuq{(Izbswl^xiP2&Il~VV@c+p&lwF(+Ua}CxyXcWzhtmaY7 zCehTE1qNw%V4_kNL6w=lXMVu`1!{aZZzWtWo)BxqU+5JbC0+S?^a&8DFuUk8aJzuK z6t`zBo}k3`f{V^ea$8MvkDLgGh6>-!D#S1?j9oHT|8q zsycRtZI>$V61>$Qr)3XT3gon`#qvQ;%i@#DX*t4pXFyKNb6CHEoR+^~T?IKU`>|BL zzUR_@YAXT;gRVz=S*yms&tAcP6&j;CKFG)fD|D$;QL*`QmY|=Zgan*5Ua7lbGy!$b zAjoA6Kh0JX7X_2LxD9Vm&m(Sa9BU8A30Rz8PQXbGbXGu4!0A|XKu*AUSc^bTz`|b*2SaPC!y8z`O?ohqnYI-TwU&@gl}q8>Sk#0$;b_^6&l9H zh{-``JQ?)T-c7lwATu!9*%+X|4Qv# zPWnV%DwneST&kB=T@Wh_W3-4zh|fd2-iCC>b9mb^L~#?ON7zH?;X*jAs?x(FEvz1< z=uX$QhY)%jT}!v$*aq<+RxyIFM=CxwDQPG5+d9UX1{rA)JBa-lTBB~vrcr2({f~vE zpF#@$lfe4ck_zqp=&K-7y&+{-UlZu-L4ou{FX3zhxxT)G^%2PR^$6CtAlKK+SZ!@4 z^>rH7e30wwGOS*Z>uVb8d64VtR;)pgU-0{}PJ-O}I*;`S$gQu6cBQ6)-1?e{wG`ym z*MnG(gWUScaz=faa_g&@cXI1%FXMd(a_eh9)?tuaU&B}@pjpiM9M(x_5lwBK0;T=| D;CfLm literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Option.mvsm b/release/v13/source_maps/Option.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..aec9b2a8febce25cb3b6f28a723497fa10d33cbb GIT binary patch literal 8759 zcma)=ZA{fw9LLWE-1K(i{ zfzCi5)-dP{gwb^d?o!X?Su$`7a|));KnhkAGUO_aQZt5WSo$~9o$Ca1TDp*rL6S~O z5881^Ym9H&ur0B*VM~0I+G5V&U-0FVi{~#>a#{v`4$n6O#EOgGp_&VoB)LRHsd<^6#j3aIWo!3UJ7SMT3 zU_B2yuhm#vz!2Eq=5RRy^ZH&#zU?2-JI-A+H`lKib5Xm;62u2UuUIiw3Fs9o#99lw zZ=b+g1G;ZZv1&ozkizKtbbOI|yFl*+%~(4??*)6Yj)37K70!0x8Nl}hwC}4R?y+9#rgnrxb|Zm1|6<;toK2O zD~ztg)la=IL5J%o*5{zZ71mx~y?&zJDCq0=MXbx9uU;V~`k0Hc1EqmJ=Kl60W9nlr zA8R%kUQ)$OPDC&_Ry}eY42M@MS{ph21o8@|vpdckygxPtfx=(LPrT?Ip0ux8D$e7TKb6@Y%T ze^GNLrru$PCP&v9D5Ks=&>2{c^$6$;%*R>BtzoR1Y|HCi zfaOh{!*Z-@&^f$+vZl^q7+s(A8Pv=LebVP+6@WhJCs?JKnEDHCSWiP^?;>yq!Q3y0 zklzMFzZ^sR6s&iG^SFb)wB=5a&2QuD!P;RrD0~O_g-rHM5_OY7cUZ*F0Cb0i@pXqS zpxzSDH~BoQrJ#E;td>3#N~pI2^qCN9>JEE`dUc>XtRAZYbca2L<=?;Vu<}V$cUbsD zhVA9+6z9%?xo^%R5Bdl6UE>F|OW>~sGOMvD?+SEQqgWZBvwEGur(+s6&(mmU!MqLw z$QS$rdL0JQz6T$0xen17=LhI@NWn@6y$)jxo`I=*_8&}d>z?(duW4w8F<$>oFt6<` zFY|LC|C02IEya8o^okW>t@3qsTUPR_R)cxY)yTE}0e!2gLt6)?zUV~k@^xi$-ookz zorhPkj)Gy+$;o#vAI$4efIJTj=V}q!J-)WQhn8Wj^hHzK6O9eqHzc;nM+VRb!FsNC z;T{97C32;k@R~ud^m?oo(4F@z)_b78@$SWX2lN@3z?kj zeOiXK*KIjMz28BfmY1-ufIcllQuKW^TENJVEfbREEy$7P7<0_QoFUD*SjFIyrk7Ve bRZ~$_*-%m4P+eZbhYWwHtg7*UiMam&u;B0l literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Oracle.mvsm b/release/v13/source_maps/Oracle.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..2e3f18638c4d963c5b63c3d150af69827b3ab988 GIT binary patch literal 13219 zcmb80drX$+8He8wkb@Q#trZm!#Ht{J)hdf_YeZl|3qk;Ki1ynTzORl+fpQpg^K5F{ zxHxU*+HJKZo4U2D(?6_PCxxut+H{I1>?VzN8!W4*ZZ0vf)}`6?Sl(>^{qB)m|H$>; z&+|Ud{TyF>u4g!>?r?4Hgs!Y#RQ`5Z&9&sTJAqdxU)|UDhl>^a7sq6Ho|g#$_}`yE zYR(S&hqXW!U-h%uj#FR8W)~uTDdBhi7 zbR`ZUT?geQlHy4)Mw*9s{S#n*v0mi2!PplAsDEzJ|8CsV&$uCBX##e zz&d(=h}`8KP<1_x)DIJMPuxr;-mL$l5>dzr5Ea`NX$nVLRb6J_ro-5dmT;&&608rk zs7JEV^T6{G^$T<&ZU#MDhOxGQo>X>VeHZjp;mq%YPUNjv+d=2WTC58&R%XyqtaC6< znm@og5BEsZFFjG3e+unwPPLV4^ffu>J*xjxUV&yc%HXZ);fJq;qyP z@;di`XV_QtBMyL0z#~}igHFIX37(e)Isucg7JyzN{!Ymwpi^}z@m7OQ)%9540K+S- z80UGlV4ld=Acw%TLVXKy6Y#@it|pj|F{j;Q>9W(9SHRF^#QOpm`fMfIIxsiIqsS33 zHN_^xZNQIVx%w0{m1$OI?|IBY&`ps=yf1>z-pobqcF1TW(b!q|qUhW6k$-T6c1=tt-y5FOpr+^OWLtn|}iT=U)2P_V(UsXH>> z^L_>6K3m6wp>S9(=IIkXFB{xhOx3BF*k1>oS#ztmQC&0SdWWawmRR=aqZ_e!%6^AVUL&E>=^hWn(Mi&X+srRk5kWNFqBF9g%1 zxex0Fm~Ju;Vx~y*Bvv=fl;)Hq&zk|M(j0IlW6qLhJ?1>jG-+00u7PxEE+yVFm@Ul+ zRtscEb2-)%Fh`mTv6jI7(tH-{0L(R+hcM?$^XFJEL#8wjWBm-Wq`3*}DOg}KzlWJ^ zGF?4CCrxL)0)`Fn7PkFQ14r|q?Uefr_Fne{%bl#rj}d?3WW9{VPa^%myj9FV&I02` z<{{KV2*ickOgn(p$d7{C-N_d{fOybFm*z&St)RC6&O8K$mHpjh&+7wo*?gUNxVCtN2~u%`W7gWmKqOwk@CAt zpS5NYFAelrD+6mT=xk5NnhpA_m5enE`UF*h^;OU(s5Mx1pifZwSZhI_pq7oA`UKU9 z`4Z?8l%MS(f$d~{eRD@syPB0#cxVAIDacti2d~Z*B27Q4o@E~=-e%CV>`|;^pl8`0tT#c= zvRkqGK+m!ftVYnY>=~@HV7OGOA~83B`5R;-a+`a=`1$Wi+}(EzFs8#Fkv{-tY1zrQ z@jh|ErTG`EJD}6SFJGraE}u^GK&L|@)@0D>Fb1m`bSJOEdK~mpx&*5U^it}Vu9wmm ziFXL}wdF>v9iSIoXC4NFT9(Eg4p{$|rw%uC*SGBy+i|}Qrb+3Sh{r)^p)wwJ^r?;buK%BLw1%Gu~^+-M}7F&SMwwF1g^+?8O=YJ>&W1>#R(?m(3pNth_($9f&~F{2CX*PxFX z&N>MOHFXO2reGdtImnB_IL?YuSGxGohCliVA%?*=$aZ1wh8XK0dkgvZVELMQ@IG#| z!T*~2SR^9v7T&}EGsLzvceK{aue&v*8tAU1APtP z%!fc<131&wQ(ptLV{L>Pa%|ROg+YIEb>;@ppIn{!1n5t$&fEz4lj~2h4nvxJqn%iL zAl+o{$DD04yD&3MrmN>1Y5oT59k}0Qp2eIe%?nulFkhPIu+BrKG>>7OfGm^QgQ-8c zx|pt>*)ryBtWQ9Ha{UKZJRit%WXwXWhauNwmSH|1%?MTtER<##s}mlSX8owSNSX7Uoyy2dm0gRTdNlyyVe;Tvfq87X=IQEAp3@ zl$KQ2MtLdjSLK!Y1*Jv7>e`ATo~;g67Og0$sxIQcBBZ-t|JM)Z7ZjAQT3H<|E2*jq MmgQF$6nox(0DSBFegFUf literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/PackageTxnManager.mvsm b/release/v13/source_maps/PackageTxnManager.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..c59be094a8299f7eabaec656769d424d843b4b33 GIT binary patch literal 25290 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 D0uh2p literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/PriceOracle.mvsm b/release/v13/source_maps/PriceOracle.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..663fa9904b1707dc2430aef8c93b2e591d2030ff GIT binary patch literal 4190 zcmb7`O-Phc6o&8U%$PrzkcEbe(X6yZA`+3C)D~%rk}@GOY?>KkVwxFe{8^+B1Qk() zQAyE{n{=UO3u)62Mq#uFjK&rgAxcrC5s{@>)N_j#t9hFtXgYGZoAk@9CBbyDp<0abP&?Y^CI|~1i^ceaCsFHTk zX9mbgXJX}mob(4Co{K3bZLO7{P-oEG96)u_Dae_>7x?3iUcX-)>H_3quq}$Gu@$ky zRu|1JSe>@4Q&h8xjL8OdkIRws>;k8z!4k|eP&If6F>FhVyWWl!v1MJNdK|6G7S-P7 z=a4Vi1*!)7F^53a;5_1YTUy-pIMxqa)-9^p#m0C*-C#a)kzL@jZ!j+1qUETYLDk`9 z#Ot=Uxa~Hq9$Pj=R6_;E907HQ9mvN(d*fZiy#lGxSil#I2P0uAls@cR;K+>oyrE$D zU}KZl*AfvA{6p3}1Cu77_t$un_8DS8(^xYg-;+~VUqHSm6IgQ~Um<^clFwo(xAaDk zhq@li5Atwq!ivBWF{Ph$6U9swO=~rSqUadkly5*in{Sb4K|7m0P2wUA^SlaayxD(=t4e$c^Xt94du2mHP literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/PriceOracleAggregator.mvsm b/release/v13/source_maps/PriceOracleAggregator.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..25b41ae7e8a9afb27e7b342b9016d9d11890f937 GIT binary patch literal 2538 zcmajfNoW&M9LMoDP14QQDrvQ~E{S$CwW$le2^uwML2L-6AUzCYGR8=;VT?sY@Zd#I z3LYdE0~M?yZU?uMUKA0eH>uvl6-5t<;z33HrZNRjzrgqQdH&$?isD4pQTswmmm9?q%gx^)r7n zRnM)Gd;)r$=6BX9s{0z_o+ilj>4VYE=m=Tz2sNOhR3)XqivcP3F)v3!DYu{wP)N%8 z{gv_r^CqcAO8+I)N;$>63sfhie=h5#e9XKzv_Q)Ds4vtYBls|czflbDQr5s@1PHL921GS4l%rfZ zLv2!CLEWNdQr<&7rFJQAqwdmjDW_3k-q8vvzaoFrN-6)K0?b?`#yTFP!z53P|hTA4>3QdX|qOPx}dQ5UI8$}^~G>Xz~}s-kpF literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/PriceOracleScripts.mvsm b/release/v13/source_maps/PriceOracleScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..c9e747a447efe008a2f1cf856ab4ecc489294d9a GIT binary patch literal 1159 zcmb7?El2}l7=Yi~Zi*rZTEyZIEV`ef-D0sgR0N$M^ZdYraUOTO8O&xej1|L@Wovem zm|Rj=*SqD(&SH1-ZguB(L%ux!Ny9k zv9L;EV__KtD{DKIV5MT?nW$iQ;=)($chB6JxzoOD&N#ux(YahK_us6SlRHcAXRm|l zk;KEn;dtvMCn6qD;P0p6*+R_;@{<+cD;4p#O@j8|G<1q$W(U?Mi15%(6oIktzCv72 zLR|rhb~_Bq(ZO7`v2Y1U$Z%Y@vgvQI4X(njf_Tt9LOWk5J6o)18wGW}jP&u1HX&XC z-u)x2ClI1Xat-SlgsC|i78wH(YUW^hAWF??SVa({<{Nsf!ZfIR?hNti@0q^`b im5*BsdAERXQJeQb)KDs8Et<2LDcj7Z7v@sdyvP^T1@p!L literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Ring.mvsm b/release/v13/source_maps/Ring.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..3a77b9296afd79ae1d2bef813625653e3c1fd612 GIT binary patch literal 11866 zcma)?du)zp7>D2X`%3AV9<-=dOR2KfX|s`)DJr5%$1Dyh(GPWKY0HK%Q$1idDvVgH zTe8K_vBhB+MY3vXX|ZH$6a2A_*-Sf8lpU^T*_-UY-z&NPk?Xsk?>*i3?|Hu#ByOAe zXno|`zTQo1?tWKPw7-1R@_lo&AGST1v}$ta>-WxEmQ@X2@c(~a?#!Ir`TTEzD6kLb zAb535TkKil$t_eLs6;*jE+y6?)r0cf-j>xBloyAS0=`;3j&m9uAJiG-Z^7FuUww@W zXf>vGjxw9Dn!)Aj6PKdoxt%O)C*TfNZW7*yopBd?a+T|g>j&0AecEF1V!=yZi$JX2 z;4MvieU~(osh0w7M`kK!2Wh^7H4ZvTGaYLp_)2p;)&%Gz&Cyt6ptCgXE9xgrbDv~` zzcd$M5 zLYf<}ilLh{?IY?b&FR#;3bE4s3abHnOLI3?Bg9G5UOir#E!1m;KGM98)dqc~`55a7 zBuMia*5A-in(bImp}#b5VetrCiPE&6;v{MIrCtIIlxCu_V30KXVfBaSq}dZI2Zl&9 z9cw-em1Z*50vIMud-dVcETvutS#_@G~dVC3L~WXCRRDTC{6piI~bh9{4DEb zaGXq1k;j9BWRi|H(bSg7WH#0uaFk5$A;$PSOD4x~hX*)ICgr$0z)3RMk9Poc-q?k8 z5Om(K*VlRDB=t^#kGvC%c@cEpsK;smoj0ywT?d^v8nLc|&KsAo>OkiW`-upU65JfFt&=HAnJ!w1V3blz}bxk2ZR`>fsyI&av|h|U}StQ-J3ZvnZ5G(Tw#3bly0R)ebsu*sJTj5zCD04LWc1z)Ap}H~M2Gg3cSAu#(^HB$H`EWh(E#NDQ@G(W)F3py2)VpV{HSWw6-rZRAR9yTIx zH6L*DI%YfKPVjbT&ncXvUf!I*JZ(zLMAwG(2-xw;({>i`j;Sh5dwqR^+o|^ybnLRf zsg7NK+${c}V^2Q(k7m7rtS5Ui1)W7o@AuY-~0|)ORZwHZh z!Evj&kKATHpj+l+v?t)>s8LJ`wyak{H;N{#W^mH1zQj8M?!2X09@VQxgjm)naINsn zRqj2CwgCA~_MngPJ^|gW60r7y?pEbk+d+4$Wmx&3yOn(jbhoOe-X+l8>Nr*%=x$|S zD!rY&LA{%x`P3U@Yq41Ip!-@ctQgRJEetEQi<54Z zi8%vww@SsD1-e_=&ywy|>!?=@dONuks|56RauHTE$F5&=S7IIoz45HWY5=|QJdV`} zQL;1a!MX}Pr0K`e1c83d-bTG(Oug+*#!7)+a`mBD!yrbQgRzEye#xJNH4yZs+pIhs z^rm|@RyOEO_e3lY=uLMXRz5fgajooVo`B>k{ZWR)JLqdX6<N$2B^A6}a_AAzJpy!w|pMsuFzhK=3J)Qo-^5WR_bb5yQCv=z3 zdlQy9pL&kj=TpzIQ0j$&o@3pxB0b1WDu1oRv;D@TEzV}r0pgM%iL>$a@r z;CPa(Kwe`$peM=OXzRdy4|!$JBAzpKrCEhl4Z4%pVAX=|AS0M^H797m;c(gvIww&i9u||QTpE|E0?&#=n!@C4|nW>!bDNq~Udb|eU zCk1&ce2VuO=$obj>j3DRrV{H5&^L`S&w##Z3bCp{-!%4_(nGzKdJjQwPQS-$13lF3 zi>iluD3`t)=%F5k)gAOu?|{_<^iWU48V!1=+ef5F^*hun20f}vvC2SiP7AO$f*$HK zu{MJq>h=-oEvNk?>7jmc*@FJ*sQ5E`lD_7qDtTkLsIPw?L2T8(2Sq9@ST{ zeg-|N>#;6_9@QUVRe&DV#ykvq%V|vWJ@uB;#UIkTL2o&Y*%cCGrwzx70R8K2C{`Hg zUvFDDnpQ}Zs~gk&G4lXNrum*p(u~E52g@ruEi*GCGb=NF^7yRu$z#*r$jX>HB`afG O)|iZ`lgGYhS^oe(qwZ<| literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/SIP_2.mvsm b/release/v13/source_maps/SIP_2.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..203f1efe68b4cc9bba224a6176bec33a04818f72 GIT binary patch literal 66 zcmdluWwND4$=|n4j3-l!s+sySQxe(&cOSiBcJSTgqb(l=zc4T``~+e~AVvm^tihfE I@kT%)0E9La6#xJL literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/SIP_3.mvsm b/release/v13/source_maps/SIP_3.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..6cd8b35c11a7c290f775eaf4e1493509054028da GIT binary patch literal 66 zcmdluWwND4$=|n4j3-l!s+sySQxe(&cOSiBcJSTgqb(l=9T^!I+<+K}Pyi!quxCKL HF;ENuSGW?g literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/STC.mvsm b/release/v13/source_maps/STC.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..b3995b5ed6ada3d9ebfc7f1fffb8710e0235167a GIT binary patch literal 6236 zcmbW5Yiv_x7{}js*KQrO9pE7brxcumvYSPTNHQ7^tE%%<{0M=YReRF$WV$z)v{DgO znxV{HV2rOf8Vg#XR5TuQwo)HOwcsv(GM$VCLsmjvstzEnEVowUM{V4}xzR5;6% ze-%uF{snC30y{uIq@7q{&=2W)tO)3b^lhy7K|iGXu|5F(kY=~7P(IF|(eFzrlI9Os zzd*4xzry+zJktCa>m-y&vz)W6f>LQVVciK{X>P`9gEDD$VZ~vdGzYOpVZJo4bKl1> zebSu7ItPAfzJv8G1fnT_)%?GdsV2LzOVSNMD(maTD7HXvF_pn2-RGJs)SBY6G z%{122P$$g>tU;)krfuy92d~;*FIx|$(CL_c2KxwjQ}LA56SR7r%;q;JIBpl^GMi6Q za2j%(&C^s|f?Jr)zf+c1b_=uFPf;D@JD$yF<{2{up8s~SFBMYL{2cu+*o(_`nz#6j zX$9}zXlhqDY3+5A9p|%Y!P*Qu0+eC}Ku3VxSV_oVvF@Gw>ebOcz+t85wQ2ylab%Q1BX7{D3^9RVJ~8UY;v zvaeko0luK$BUJ81{n!<157X{v+d9Er;_CI7I>BX+K_|El`gPhXkUQUnwG(uL zyAP`ybb`yCyiRcM((gFv1UH0r0(63#z?ud95$9*DIpDprZF}pMt?gUe9x>)$ZctPJ literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/STCUSDOracle.mvsm b/release/v13/source_maps/STCUSDOracle.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..25b7a549d7434c5eedb54cd7e99bf0578594e930 GIT binary patch literal 961 zcmbQf@0(uqvPgaY1zM|vjyQz9lu-E1xJLNJ#Ix6~1WYw$*`&$9un&kC8BhTuPjHBH zXt0ZaQDSmVDo}Ph0fPdy7#PBVn1PX4l`Mn}eF-%1E!a@@l;Zfrl$0VuhQ9-<{tD8; zz(m-1Eo}w{Lm*}(=sN+RDkC5!La8TESqNAuv2G3ps*VBaAjZv$feKdvF=0110adLA z8Oub_dxwC^&ViINazMkmm{35U2P(e~(n5@*4Rjb7EP$A>qxpcUEP1k*+bP;nnPZ4i<4jsq2*1!BTZJ`YrN0f-3)^CF+ E0Mo2%UH||9 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Secp256k1.mvsm b/release/v13/source_maps/Secp256k1.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..f7144ba955a19c6f7f757a7bf82a805291b8626a GIT binary patch literal 2969 zcmb7`O-NKx7>3WCt4`xzmIl%`g0Naxq)-xQ-eO3l94B!$7agx6mQHh3a92>YXyL+5 zQd9#`5(q8&qc(xdXv!#PA=si8F3MH@)TU>|3+~?Qg=aO-eD|F1JMWxX-;g6)qLOL*zbu@eo$^$}y%MU^Jon07Fh zGDom{uw=~_So5K3{=iy>61~uy#l}1VV-@#Jj(NUX?kw(H!8fJ4_zL15(0luiwF(j0 zg}+#P*_bWOHOvhtlIAz8CTf;Q^C;Fyh)S~t>lEygX7KiyG*i@bp;Ve@v3emy>z|`7 zY^ssWup0ko#4iPz{>w!~qBI}$_${nb(Br4`n`Q`gDrU?*Fn08c=li{bp4#1G>^UgQ zdg;*#FFWZD^{em9P_N2gBWAT_bVkqS5NaJn{qb~~ z4Xe^eaF2tj(xdFaOM)I{H&!3$Q4U~@f=;rBH4Zw-{aa?SJe-Y~6QDC6^hswvn1Igw z4c>ekbmoHtpfmrTdLN)n?tK<359QLli}evIq#3Mpw={oIuaYBOCC#8_h$Hfwf<@&! z340~>KG;dv592pL_^`KPw*!x*kMG4IV}>E@ZG0K`YQZ=3ROS5{;!DsO&SAX*o#D4w zdC(btjr9g}6K1g1K__z=YZY`dKVhwbPG<0Soy=F{)f3Rg5yTWl>orKdFZ*GgH9Al~z@pB!`UCB8IdS0D&6lNnPy2crKaQSywZ$>pO?>|Ob7I-?LZw_vmiG7d?&}|_ojHH5m?}4L zF)`#@*X%2qtK{~8*-lb!1#_QTG@Xc=&5$|4La9_yBUhnw9ycFf;|cINIr0lHqwbLF zOTIw*81!JoY=C^e+933>$1SLr?J@8f=~ugkx=s4kmQYO!$VFKED}4-F=L}pTbK45V z;)U8&Rc-NQ^c4zBmK(}m$1RiN$YCGC9+7qG)%}3`>4q|7j0mRhCEp-xhplyTGuZIW^lRiSn%tEd`3MC^!sf$zXyq>tkl)Nj(qv59(3`Z&7XW?|CD z@d4vSkoq`!DoQ>Eoo+XqCv!tH>;K{WEbjsjT&4fqmAgE$>dj?gy(|48voz^liJ>y2 zcf~>7Abm}%s72D(bQHBj`kHRcuCM7Q#`{M4ntnvBk-nyTJIvzLDeprNm7vX1t}t^N z*(K#!RE@f&97c^%*q1CJBfg|JdsIqK)ybT#$xJ+b=-Ba0axg!XOQeqsw*9P literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Signature.mvsm b/release/v13/source_maps/Signature.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..5d15d441a8e76027abfe31865d6a865e305a26f8 GIT binary patch literal 2185 zcmb7^J4_T&6o&8Y%<@=78VH54A{5$LiHTTfL@F&vj2O*k9~YJ&u$h@fNr0$93NS{c zWGg8Q)LPj|VJxjENN7zcmJlGJgKt7^Lif*3@^#-mbME8(J-z?0y{=s!*p5zCzAxY1 z4EDbK8u9-;*ga?*ekN z6c>M+QF@$=lb5U3imxV0`AIvc-ry4!j9$#3r(etx=GVmb(+|)ZejS=VoTfzC~L$T~MG)SCyLo9@1KZVpi| Zc^Nu4-(h_QotukTZ$al~^7o{sG3P$&b&CK1 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/SignedInteger64.mvsm b/release/v13/source_maps/SignedInteger64.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..882a4e967ca1a65d26ec175f2e4dcfb26e70dc6e GIT binary patch literal 4668 zcma);OGuPa7>55D@3%~|)FG`jr63SYBD%SXp>Uu+(7dV$p-I&0rNFQ$ z;#KBTr01Z#Nu2i(qt&-jj`IN=Z$zlIQ5F7(`3a)y{Qf}5uk>%IKfxQ3ms_ah(r9MO zjB$&Un}hos*U8pjn2);xJhE-ZTn!P@bjOdBW;yk?LX2%B;nVm1ZT@c8HUv z+x>WHc2KVq5~O(y>m(#vnP)KPNV5y;C?res71kuomF5W66r@Pg?b1AHCa^nGAkE55 z$6O#yA66EmOEUv26EdV(gH>m2X%=AZ1)ntCE-jR%dycZDIl#z+ut=K2SXW@Nl{t!; zBh4YK3y>?#X{_(CRGJU5en6fy-7Z;NVU@9t69C5>)mGQg8c-MMKHU9~5NxRp1?ua< z!8ZAyX8d+D1{bBA`whf9pl{!MSkJ&KYYt&efQ5R|>p0iI?s*%FgE$Mi6JGin2f7o+Oa}c9nYHqOeuv7iDnY+P#@r419m>So0~SwfQXE$y zFk6d2l8)&!HqDazW*uTN=oK(#i7BfadmOFTs8;hmi`i#voB7^Hd<1&F#(ZJQ>gDYr zk@lO|Y8ChfFb5&Nv9%!_JlGHn$U|`neasACb11$d{sR4p#+(5i&StT^YzMt|e=z@o z?%G=Fm4H4J#@q(_P$Xhifkn|%oSi;%eykSl9A-a6H3mbiE$R{*#=HzBq_0%+p-A=v ziQXopzoF<=T$_+Sh5HWlJ}~Aq=zZXhulGR=Ulk8}A0%O=g5C$l%mBR)60j0Mhx8p- z)u2OqKGrVKA>Hj#lDt0Ksn-D(Aswq5bV%>Q>H!_S4`X#gs+_00M|DUaqux!>A^kSi z1DG#IH|7)2A$=U{7U+=f;S@!K4(YF{7mKMwy4xik($`S07_#KI8?yv-NH4|O3_7H5 f#M%T))p!9h10!QGA+_E>bv_`q49tWLt^z8o24Y5nPRItTssUmqf-1A1 aDv2=kAuv$hg93&Ke|-R|`v?g{Mg{<@goyJ1 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/SimpleMap.mvsm b/release/v13/source_maps/SimpleMap.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..ab20871bf121a3dd9420d8ff62183b1b0785b9d7 GIT binary patch literal 10685 zcma)>drXyO9LL|o0X^LDh9F`lAt|CvK@nx?24>ULKoKtu4{*G3@mP498e*lWb83ig z$=bwgnc8Got;p-5v}Rs%sk7xwvzn%9cG0rWd)C|5U*CuM`Nw_uz3+25-{13a5?V9L z8jf5!xhK7GYQ@wOT~^##SU)U2x-q<|Zl&wpapzK8mX!|t``?c%v|v`Hzry#d*B@kA z38KmtoF)izkMb>2@;1bs5K`!^nCDaWZp^)QX(gUQIs?kPf^!{Q(oDx13`V2MM$7@T zQ9Xs33oiAx(~)LFm>$^qP|LaiMz4Dj@iLgb?sd$c!0oQ|`qeA{g=oL8yIk*uo_M_= zWWLE>$imElAa`<7fAt!(5$8c@rFT(@uXtA3LiHPyu}i^fuP3`4uL|@o@?%v)klb(1 z8;3}9I`!*OQCJ2>g4b~Zmlx7Romk=e*?O3NFTAI$&W2AYH zdcQ$CY5t7$5ZX)A6K+}I&_SA!SnZ*sH2>zw9Wgse^D<^9%vfm#EKGx~yeinT)`3yN ztVgT|vxI5H+!`otkTA`N2f-v^zQ(&0C~S}bH6fO@9LzK05v4u+hDm0`;B^3<8J)1= zKxalcRy?@nIy-L~EX^U*%LAQ5saPXG=TH*XTnLj-_hQX~aA}Uj@x#I)^^P`W$o)?Z^58bPnyqItvCHG`Wps^#h~K zNJkt1W|=V*b9kV%L1q*n7J^A;EWxX>U6XUhdx%GD*&tt1+FDj`Fwd7=RDK6oKDo=^ z$NLa;zO-N+2Awa?=yVn|Q_r3UodwRA^qJ%;^=^Vblbpr61^P^K5-XlH&{+_Q)fsda z+@@w6rp^NA={gH?s5c697NlW~2Au`Y{?l3TBK78j&Vnke#h}k5OR<)LK9fwrs)f#S z&lh5?1cL^68SMu!N}?YTZ-QA8-N$?oC~c5LksewBm?Tkuyi9PJC&ondX}||j&fZMC za=W}VE3y2b6QdMsF6a}9^QQVlvW9vMpi^iu)+VrY(U06TTQJ%W#}GdOv;A-i^BnNQ z-Cf-~yK#n01HB52%E|(RiMYiiJOHE7Jw$v2W~1|P!H)!&$zKCv5##N@2-xqgW?}+j zkzHAu!?5x}@5d6XrJ(ntZM_5rE$rJE%lZzCX7?K64KSPCJDB$ar46#g(~g5Om}E&B zUOEK1W~p^phqfMqD|}Tml6uN_EE?2>LLSft3kyGX7Hjtr;&( z=jmOfSxC)^kRZ*;SW}>@G>fn%L83JCu?nD@H0>u(g~z1n$9fqIK5`*+>u@j%^a#Xg zFbniJ%tSD1mpu`CfgNXZd?h$O&}r($nhiQl^RddoAbecW%q$qqnFlc(%;u~kW_+Nu zK@&_x>6-&4c+OSSQFAq1CstGz0)rXiMrzD2x+wFlhXB2?Aoc&|d+!03`Plz%XizjcC@sbjN(x^qCs z<_xTA(6Q;vg1&TYrrs9N0b7UF2s&W@n=RQg_EB#?=zw)rO9$*>>Ky_7UCwc=R?wG@ zqgcm4UphX(dOFG^wC`d54mz~|#CiZaw4INN4%lndvp-ZiV58W_T|ftHH>@6@12zFG z5p=+YVI?!4I$#H4`aoYLMq-TyeU&J}ngaSN@jO-u=&QsStTND731>w5D)9>S>Y%&) z#I43!1CL8{E!KMIApUb&a~D<%^pvKP$|=&kO+6R8?n!CJ zV0D6C(sX0RLT_o_;OU()Q>8fwD+~Haa|qT@NR#GZtZe8j%>h^$&`+B7lXDh!K#5wY1U$`fPvC{0jmxMNz)m7mNYj~uL%ZAb34`n$d+b3 uRx?;ZQF){CCKZnvJHB|t*a>5DT~>#{e+(a;pEo>rQgL3)dEbAXaS`OL( literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/StarcoinVerifier.mvsm b/release/v13/source_maps/StarcoinVerifier.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..273b3b0bfd3ee7fbaec5956d610d0bbdf8ea004a GIT binary patch literal 16198 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 Y{q+M(_U4ZFPx# literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/StdlibUpgradeScripts.mvsm b/release/v13/source_maps/StdlibUpgradeScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..60eb9a5c2b2c54d96f13b5be183ab965c24e1b41 GIT binary patch literal 7177 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 DVm>%- literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/StructuredHash.mvsm b/release/v13/source_maps/StructuredHash.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..c2e4809030db047835c0cb2836a78c3e8a3c46e6 GIT binary patch literal 1456 zcma*mze@sP9LMqRb7x+cXAQO1P}mav+%gFyG##wa45yA$FDwG>psHJym`y4!=7~O$p#P8PPdQd8=aeinA2aL%NknyKt-A%H2Sk!op5^c(;1iO{a~y4h zy&>Vr8;-&0Z%8?WT`2sH6*v_M_H5oiDY4T1zRb!|tT}-^tek|JMm?+?gqlHKRtBLK zQ5T253=%bvP!q+nxnb;X>65M5QfjarL+`kp+JBFWe=O|0W4HZOAD5kMOsJ!5m|~DYXs9aRLYJ46c8jR zQ6vzl76pL_Doaxr_#wfVXcYp28^J0XBT8g(dnS4l|Go1i&kvF(bI+M`X1?jig6XSj z2af&V`|I0|+`r?@`^V4K_Fa>A@!g7Lg)aF4Ru6I2fd+wSp6X`zRXTlEq5U5P}3hNsZ?$rUV*t4vrCnGA6^lJ&`c+y z5^)*mJFo(4HALk(tjF2_angJeYa=w0=3J~z5HHPFvGze@m-!}UqBP&adK;QZ^Dx#C zNRsAute2pv%iM$6%w^g-9mkp7K7>4o(ozD=@ zgYE=hV0{TXVJEP@0^JFYV_gP^x|8#&vGdh8cQ4v&piki_)-f~X%{_rt3(oVZLp=$e z^Qy-?3p^3s60cj-4z4^jLW>8ThgMjv&6Ig)gVh$Cc}PR;1fDz$!5apa2i@?~n}*N} z997vHtq-`B;nop`oVJuN+tWp;vG=T@u+&~w!(tka<9sxw&i zpy#U3u`Yt1tKP%91bVLe6Dyix$Ei-f5mo}+A4@a|qT*(6!YKD-(40 z?22W!ewD}eq-(2yc!i*AD;87V?#0Ag3i@_0$65>eb}zzO2Prc1v2{AObg5+sSHMvR z-=Q^tu7lsPZdg#?oBkH+-{7f(6uv~Hf?XDwhit^LpzmrPRsra{+7oL$I2vp*^VU3@ z&-7GXf;Jy?Zp*PM%#_pQVysGVp28B;72r9A&3IdZC!${;L*qlp2FD#6jg|vC4~1Ao zX8P{fRMZ*Z`hru1xYAj$?fTy2BATYdQHKIgL?>(t=0o7v+XA$QLGNubR;8J8Z%eSM%=GPT8R}}Vz3C(VjnA?- z!O>xEq1^_(wYY?nC-Q+JqbtkIx5%sp6HpgWAM(_%Wt zlOZHE!*>QF&_=q>U>sJynZ8>y9(6LSIo=>J@ed)l?Qs}8G|(z^vu%-YXIn($IM}% zU*TrjI`s>&5Nj%gR9P!;Fvq`RbHDy8uAnx&!`Rd!zS-kVWO_M2p0&h9!ZnP3>J?L%}TdVFIi->2t(w$==mf8C6s#2`B z>|FPlotQ6!?lIL^`$6}Z16YSa_m~&3j)3kQ4Ol;c{vP!+)-}*W(M7CZK@ShH+oWId ziDW$)bc2gx#e;4Ek^f@0k~i7Tyd8wNq}&M;i)Q7HpHwt068`}cHBYf+>H!}yFB65AKa!xzsf@fANV@Y5^?xcUX~ZemqyMjEqm(O7#m-J~925 z4q-{AO|%BE#F(>Kk3fzYm|=ON$z~kTqej-xpq4=1?J(9I2#I-J!@31kqFKSZ4b`F< ztX?CUdXIO(Af?YCrM`l)!y}`k#p#KPRNQaa8_+bCo5+>(Wxo>ikTi3XS&=GsRX3h5 z6!KdWOVXsPOt=mzB3E(}@4Q|>JfWjl7r++HMXWa<*Zc<7TaarWEh8np;=r4C>n2DwuEv9v8$N}H2lpw2{T zKhT5rmGW9gt*bZ5>lNk-$a!gVCov5g>s+l;)1Zez6&|84fLw(otPddXb`k42$W_p* z>zD>tpNc8f0?IPIrCPDu^bE!6NmV=NA?~PfkeT^nx z?hdSWh={q{SRGI+n!)OIqUjJX1yRxTu!f;QG!J3*Kuk1!tW#icX+GfZ!5o;se$TL% zAY%OLy~bVvD?U~zo*pUq|MB=0`L{CzipxrB;tsq$AUAOcs}tlVevI`FJ_kk12l`KQK2y{xDXtx``<_aXZ#QkefJ$)dh`W-GkMe zMDr~1rXVhwy;vup*~rXcwiuau^;Xf;RtZ#9)bY|;|A^x`88>68#;u>O=VskR%021y t*edS0-XK4E{H)vOWU`6AV@hrBb5kkTPo}*=XCULIJ-;`R%%%rI>Muobzy|;T literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/Token.mvsm b/release/v13/source_maps/Token.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..6bf0664a752692ac6a627169520ba256955295fe GIT binary patch literal 16442 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 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TransactionManager.mvsm b/release/v13/source_maps/TransactionManager.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..2d9cf9915d3a66a35fc57844edb193159384abb6 GIT binary patch literal 19100 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 literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TransactionPublishOption.mvsm b/release/v13/source_maps/TransactionPublishOption.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..1d450f220d6985c4d5e17e60fae5db24f9cb5827 GIT binary patch literal 2360 zcmbW2O=#0#7{{Nq>*`1CJ`b)JMMV+WVK8sv3~guw?~>A_)1vUwwX;TIQ`UwZMeyKd zAfELi8_tv9!J$sCUOc&z%8)tcMHq+&hbZ{ZX69~BX6f$`@_V1><)8OS==86iA$?(F zJ-NAYXZ2=k;J!Qi`{B}~qW$sb_p6iF=ZI(tC}8(bIc!f?o9$|?<9N-YKj}K{Yi29B z2u!Bvr*5JjfMT3EktC`E&U*o88FcY#?>?dopm?%ct9gF2!xcXP`wU38Ytv4vBdf0K z%}mv~W#_R(fT0^+-FK&CYda;U*@#-<3Re3-$#njO9oCWFR@~e!8vBWE0qWzUnMJRK zpdXv}2Ux2h#+q+neFkyX`~s^RJH<0(&d(amb&z1qr?4uhi9b_w7|J*}z?y@w3~-P& z!|o~8e2jXF;1Fv*hxHDmS@SlmWzfT#;Th>=%>?2}0URbK&kU?l(9fDH*y9+?0oDwx z3n0P)oku>;04Y(Yd=d6*prro}YQzCs!J4l@C!9tulp}Z+CjmcT8>n~+CO=?de}2G5 zP;U(I0~VMS5TX5X9NAG2J?OKr&w;%LeHm++vPtH}3((_V^uI!=i8C|Gz^DUSJupwN37fHz4|ekA4Q$UBE{#VBG_h z=+ks#LKS*Ws-=8+Tr+Hi`mJn9FWR!8S_LUIBX1YFXmCf|bvH&wwPMK>X1=URHJdfd rhAnfZW=X@erFKcT>^L3MR3XfZ0vA#hB~8s$WY#onRW~fTU5w}tbIH7b literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TransactionTimeout.mvsm b/release/v13/source_maps/TransactionTimeout.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..31b8e697cdc3ec4a952a8a044db42680465014ee GIT binary patch literal 1393 zcmajfJ4?e*7{>88O=7LKUaHmLXswGl6bDgf2Ssryh!+SkbO_p0ZBL<-3Mx3dJGggo zu&(_8f)1iv!3!=LlOHO;z2(G5i9xksB>`&+Z?V@$uUe4Jo-;-@M zl5qUHFIPnNkb(X`M!Hb(RMqo!P*#PYR4mtYh#F+R2~%VNiILKEfC6c#A(tfQ{DJt!5?UeoP-^JKag*6UQvgFm>XoqZ23+vsWc=$Rv2ct)b7at?jkX@6vWfW~kxAt&b~%SEDyN}lkWJ+{ltvv?E> literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TransactionTimeoutConfig.mvsm b/release/v13/source_maps/TransactionTimeoutConfig.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..1d2e6e979b79e4da58b9ccc765481b0ba19466d5 GIT binary patch literal 1242 zcmb7?zb`{k6vxkdeSI|=NGwcN3pE%dni`CThN=6WX|lvdq7`;1>YA&B=h5U-#B0!peZ%?y zeb!s7PtccGDTu6qqxP9$9Y9ev*RT%3Rn2dDJjN`krm=dEW2Et-$Q+3E@5PlVTQ;S6 Re(4$FCFqOW!|D%Xe*r@ezcc^< literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TransferScripts.mvsm b/release/v13/source_maps/TransferScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..b94f1ce1bdc54c43d74747e71d9db53868763182 GIT binary patch literal 5656 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 VlbJCwH|NQQk7Q2Hnivdt{|1+9o0k9p literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TreasuryScripts.mvsm b/release/v13/source_maps/TreasuryScripts.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..88327c5cea1c9e952ced3964b69e36694bbb39e6 GIT binary patch literal 3680 zcma*pPe_w-9LMpW+uU?BH#411i%_95!jKC3kI}IR(&!Sbu|3t)w)JdQMp4=76m}^u z(V?Plh6H(vAc6`y6lJLu1qpQ!grFjze!w2=PTJ{QA#Z%f6vfHr zDvSwKax#BUw$IA+C|`lCCa*uAKA5p=<=e3B6v^4yTsCjn@kAtFsA_>;=yGnz*QgT{EItU^V}E9G6z*?{y(>8M6>aig~a#@r*f zFLNAwpUPdn%vacHs<5r3l|HK9{tS4Q{E5TaflNWYzaP-w4$oP3IxAndkJ$}6S;wtp zJZ1GK2Gtd6;7!Ce^n@gUhe%IIFUlr8AqCV4(i3tLHAH$sil|{Km$S4Ib%|Wu=o~7- zig7zjHP|TmT+Y%8YzKu7WL@usF8mI1IZkn?%s%oLoLwtd;7({anV6o{YFr)ZS$)e5*CX|;mVTa|)gtG+NP1R>QI|>2 z>VDJ}^2@0%J=TDfr6*b;<#Vq5hAO3;LVcj1l;fz66q0hY*O)GA{KN!f^6O7&8p-V2E9p4 zgM1`uT#odzT#GtFdRdlkS1-#KoNtQsvb>F&CcP|6zg{oPT0VSYq?ctgs)h8joaY`} zk$PF4MV%+TEW1$`NH5D>sAYUL>Sg%|`Iz*w96>!Hy(}H|l=QL;bC30;mt_O0iS)Ak Q%$1vwdRaP8XgL}42Y@0>W&i*H literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TreasuryWithdrawDaoProposal.mvsm b/release/v13/source_maps/TreasuryWithdrawDaoProposal.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..39c8cba3d6699b6e392e7c9d94f1ccfe3da07438 GIT binary patch literal 4367 zcma)*LPgPHDFscF(X5cH-A;^E>p1QXy1Lm}XR?V4 zL8yXFwW280Mg&WxwA9**r(&TOE3_zTs~`=n-V{VHUZMx_v&w?E?<{;SyPx-aZ)V>2 zH*YVTd8>Qb>U;NMBj4THa_P6Z=aP3fCR1le4t(GAyS0DSqG4mqF^Iv-pV%9A;JINX zsP-2IcjN0^JMk+JPq+hqr8KDgE4cqabFonJ+`!4XWi{l(c4JmU zqU;3)U#{pT)yKii)Q@6Ln=wm4Z=97_YoS4Iu{+G&hZ&dVdCdP{k~Hhr)F{pR{Y^;o z0BigTnxq+G9fqVd%UA(SmZpPs38qN%N34s`D$OHUe?Xfw>$A5@vyF}SE=-l?zs!6e zrb%;zdZX})G!J4Oh3V2fhV>21kY*Zd3|^IHJ$SE4^D_1RhMCg5f%QMklI9t#+wi(H zYt|iz5aVJa8x*4U{}8td4H0|qKHO1=N9b$E@xF#w%V6zY@rX-cnfeK)1JrSnq*uZ}YJhfNpPbtUNT!YhQ=84N}rvft7<6 zY1U`g?QMv9BcR*c4_H5eZf|?Beg@s%N>~-p?d=@aFA(7k_-oRbKOt(!{=&TmjS)k3 z7xw`q125+lhID2oka;JWh-Z`(>eQMZ?Z7b$bv876d%T>J_lj;+9ckvHFM(Lg?us8& z2Am;((39sgixD3KPfKn<8_%!JAkBJJ9sSR#_XX(aAHq5TI{Kqn2SG=_igg|I+2TCb zRnXBtiFFNh^y{X%SE56f^pLVOH5hF7qj zfR5q%8OCe|9m7tn&p^kp6>B!=7#_kp0s0L*hIJbBAB-JX--3xxv$9#IH)A^;eRg*y zo8D-3#mt+}zqG6_Cu?Gf9Du``af!RqX@E%V}MJCkvGI(k2K`qOrISGJ?y>FCMy I_1X>Q8FAV}qyPW_ literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/TypeInfo.mvsm b/release/v13/source_maps/TypeInfo.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..7f887f18b5582b452af3cc31cde6040f3d36dc3a GIT binary patch literal 1387 zcmb7@KP&`M5QpFHp0Gq*p^_-h#os8<98sL;PN9(PFN(d`KQlBwq037)HI32;}dRVGe*7)L!Bzr_2*l16g*GPAuyjPs}6rM|U-O#2}PM{UR zIDVbh$`QS(GUo70HpaO6fCw=LM|Nk;9h+9GO|+vQHGS2`_-8i8c)IFG#23(|JYc{6&&?p!Jl$*mF0exq` zSv{GvCpkYOO}p%4z;soiUksv?)&0-Tcj5Qim^9lngE$ZRCZ@3#L2pkXF`0zwFGQ_E aitSlNs{s#hmG~0p7Ia@vSOxwwW4-~sQrfNn literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/U256.mvsm b/release/v13/source_maps/U256.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..efe15b746ec7ca465a4b0718aff6a9a136ccd96f GIT binary patch literal 9423 zcma)>drZ}37{}jpIN}Ywpp@W^n~0*esnCqII-5sDPoRLfv_vQ;BI!u0^R{#T=&$d~_W1`sdw%cl`8~hqeII@k zr|kar*vi*qGMk!{PQ8#n{f_^@vW6dOqg#e-C`&k2cX4GqV^)F3{Qt+}8$UQBliyAh z0cJ%RGY5=EnR~JJL#z%O+tZkCV7#7U6*dkp9y}$=Ou|aGQH@V8VFY5(hLst}!5Rx* zX=Y)Kg9vF(!g>ZAF2ARnF-_o-s{?okLFeiy)-i~PEG{Z3n>$D4HY?5;KSY)|>9bKQ zz*D9IUu6;3z@+JC_6Oc=(9i59Rx{{l7QViIX6?D3DDcUr+Yzf1w322tRtJcbrVnd& zyfJO0nS$8|+DbDGs~@zJW-3-+XfMqKtVD>C=6I|^h?Zsn)+Fd4&1bPDLq}-_u!^9Q zG>3=G&e9COBr(!_lbCNo7iliXs)DZ4d>3mK#7c8MRy8~%&3Pg7VQGfn_-@kNLdr9d6 z1L8$;M}4GuFJz`lGmCg5p|3QDhRif+hM!SCY0f9+QWz-B%8)ron&FrZn@3eLuN=7S z&DD6TLGR5UV0~z#x}0O05D(d~^1cpZ9Ra;3HewwGy(gZ=Is*>sna;*s2IKKPUp!YH z`>vqgusVB=ytP1#F{42zAros1=p^J~jRT#8AXX0OgTWxIMWDC)a;yc=THbp;)F7cW{m+XBkPgj?cy@u(Y$*Y#~I9}iX6b@++ux=ttFAkeKi4(k!nGg`R#^o%x!cm<$m zv_hOIqt#=50eVKO!rB3PMmvag z2=t7$7wa%Ml(L@!%?6i#HX3h?b$OL#Cz*jb6Lcpj$EpC`NlLI@28S1Ka-uQC;BsOw z!Fvw$iG4a&xs6JTk{MWmSZ%{fa}8Dv=nO2zss-IkKf>As4y~t-gVJVuSaSF;?H0U` zLFcLgYnP3RteaZKKx3W&mo+?z=Lfxp9IRX$6WO+74^jjJE~!8g^ne*r>?5#g}5fXl;iz%)y%rdJV5(RobY?dh<9=<@{u;$6*a; z@qPxqhAUWCZB%5vE%|6Qt!=yE$E)A>6x4p8-}iW|{x-1Q@OJX=@7a9!ft3jk$G#dy!*zB%beQ?p<8836;W?;j>jdIS&>8p<>n!LD{DO53 zbOsJ$od-Q_9SE6v+WH;yBIs%B0@iP!r>#9$ZTZ-&H}Do44^wZmmoVF4>di2Gb-iT` zAl^XG8%sLYV9@PNh0s&J#jj#5hF;QKg0&QSOLHdHGDwi-jF6cq&2r2tNRnnX z)*48b<~vxcAVr$nutIl`=GzPdJR@B zq)T&pD5k?J_gyqYKG+|J)9Gc@8=&`^b67WR;5HFshYW6IBF1J8jWoUqxp~7|n^u8w zTKh+ysnuZbF&7w{JZ^8Wj4go&|#&CV(G2eXG4 M1p_%F3r2a&zbSt{dH?_b literal 0 HcmV?d00001 diff --git a/release/v13/source_maps/UpgradeModuleDaoProposal.mvsm b/release/v13/source_maps/UpgradeModuleDaoProposal.mvsm new file mode 100644 index 0000000000000000000000000000000000000000..a1d50eca970dc7ad863c2b310eac9f6892e6c16e GIT binary patch literal 4305 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 + } + + /// Return an empty ACL. + public fun empty(): ACL { + ACL{ list: Vector::empty

() } + } + + /// Add the address to the ACL. + public fun add(acl: &mut ACL, addr: address) { + assert!(!Vector::contains(&mut acl.list, &addr), Errors::invalid_argument(ECONTAIN)); + Vector::push_back(&mut acl.list, addr); + } + + /// Remove the address from the ACL. + public fun remove(acl: &mut ACL, addr: address) { + let (found, index) = Vector::index_of(&mut acl.list, &addr); + assert!(found, Errors::invalid_argument(ENOT_CONTAIN)); + Vector::remove(&mut acl.list, index); + } + + /// Return true iff the ACL contains the address. + public fun contains(acl: &ACL, addr: address): bool { + Vector::contains(&acl.list, &addr) + } + + /// assert! that the ACL has the address. + public fun assert_contains(acl: &ACL, addr: address) { + assert!(contains(acl, addr), Errors::invalid_argument(ENOT_CONTAIN)); + } +} diff --git a/release/v13/sources/Account.move b/release/v13/sources/Account.move new file mode 100644 index 00000000..0e3be33b --- /dev/null +++ b/release/v13/sources/Account.move @@ -0,0 +1,1228 @@ +address StarcoinFramework { + +/// The module for the account resource that governs every account +module Account { + use StarcoinFramework::Authenticator; + use StarcoinFramework::Event; + use StarcoinFramework::Hash; + use StarcoinFramework::Token::{Self, Token}; + use StarcoinFramework::Vector; + use StarcoinFramework::Signer; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::TransactionFee; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::STC::{Self, STC, is_stc}; + use StarcoinFramework::BCS; + use StarcoinFramework::Math; + friend StarcoinFramework::TransactionManager; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + + /// Every account has a Account::Account resource + struct Account has key { + /// The current authentication key. + /// This can be different than the key used to create the account + authentication_key: vector, + /// A `withdrawal_capability` allows whoever holds this capability + /// to withdraw from the account. At the time of account creation + /// this capability is stored in this option. It can later be + /// "extracted" from this field via `extract_withdraw_capability`, + /// and can also be restored via `restore_withdraw_capability`. + withdrawal_capability: Option, + /// A `key_rotation_capability` allows whoever holds this capability + /// the ability to rotate the authentication key for the account. At + /// the time of account creation this capability is stored in this + /// option. It can later be "extracted" from this field via + /// `extract_key_rotation_capability`, and can also be restored via + /// `restore_key_rotation_capability`. + key_rotation_capability: Option, + + /// event handle for account balance withdraw event + withdraw_events: Event::EventHandle, + /// event handle for account balance deposit event + deposit_events: Event::EventHandle, + + /// Event handle for accept_token event + accept_token_events: Event::EventHandle, + + /// The current sequence number. + /// Incremented by one each time a transaction is submitted + sequence_number: u64, + } + + /// A resource that holds the tokens stored in this account + struct Balance has key { + token: Token, + } + + /// The holder of WithdrawCapability for account_address can withdraw Token from + /// account_address/Account::Account/balance. + /// There is at most one WithdrawCapability in existence for a given address. + struct WithdrawCapability has store { + account_address: address, + } + + /// The holder of KeyRotationCapability for account_address can rotate the authentication key for + /// account_address (i.e., write to account_address/Account::Account/authentication_key). + /// There is at most one KeyRotationCapability in existence for a given address. + struct KeyRotationCapability has store { + account_address: address, + } + + /// Message for balance withdraw event. + struct WithdrawEvent has drop, store { + /// The amount of Token sent + amount: u128, + /// The code symbol for the token that was sent + token_code: Token::TokenCode, + /// Metadata associated with the withdraw + metadata: vector, + } + /// Message for balance deposit event. + struct DepositEvent has drop, store { + /// The amount of Token sent + amount: u128, + /// The code symbol for the token that was sent + token_code: Token::TokenCode, + /// Metadata associated with the deposit + metadata: vector, + } + + /// Message for accept token events + struct AcceptTokenEvent has drop, store { + token_code: Token::TokenCode, + } + + // SignerDelegated can only be stored under address, not in other structs. + struct SignerDelegated has key {} + // SignerCapability can only be stored in other structs, not under address. + // So that the capability is always controlled by contracts, not by some EOA. + struct SignerCapability has store { addr: address } + + // Resource marking whether the account enable auto-accept-token feature. + struct AutoAcceptToken has key { enable: bool } + + /// Message for rotate_authentication_key events + struct RotateAuthKeyEvent has drop, store { + account_address: address, + new_auth_key: vector, + } + + /// Message for extract_withdraw_capability events + struct ExtractWithdrawCapEvent has drop, store { + account_address: address, + } + + /// Message for SignerDelegate events + struct SignerDelegateEvent has drop, store { + account_address: address + } + + struct EventStore has key { + /// Event handle for rotate_authentication_key event + rotate_auth_key_events: Event::EventHandle, + /// Event handle for extract_withdraw_capability event + extract_withdraw_cap_events: Event::EventHandle, + /// Event handle for signer delegated event + signer_delegate_events: Event::EventHandle, + } + + const MAX_U64: u128 = 18446744073709551615; + + const EPROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0; + 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; + + 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; + + /// A one-way action, once SignerCapability is removed from signer, the address cannot send txns anymore. + /// This function can only called once by signer. + public fun remove_signer_capability(signer: &signer): SignerCapability + acquires Account, EventStore { + let signer_addr = Signer::address_of(signer); + assert!(!is_signer_delegated(signer_addr), Errors::invalid_state(ERR_SIGNER_ALREADY_DELEGATED)); + + // set to account auth key to noop. + { + let key_rotation_capability = extract_key_rotation_capability(signer); + rotate_authentication_key_with_capability(&key_rotation_capability, CONTRACT_ACCOUNT_AUTH_KEY_PLACEHOLDER); + destroy_key_rotation_capability(key_rotation_capability); + move_to(signer, SignerDelegated {}); + + make_event_store_if_not_exist(signer); + let event_store = borrow_global_mut(signer_addr); + Event::emit_event( + &mut event_store.signer_delegate_events, + SignerDelegateEvent { + account_address: signer_addr + } + ); + }; + + let signer_cap = SignerCapability {addr: signer_addr }; + signer_cap + } + + public fun create_signer_with_cap(cap: &SignerCapability): signer { + create_signer(cap.addr) + } + public fun destroy_signer_cap(cap: SignerCapability) { + let SignerCapability {addr: _} = cap; + } + + public fun signer_address(cap: &SignerCapability): address { + cap.addr + } + public fun is_signer_delegated(addr: address): bool { + exists(addr) + } + + /// Create an genesis account at `new_account_address` and return signer. + /// Genesis authentication_key is zero bytes. + public fun create_genesis_account( + new_account_address: address, + ) :signer { + Timestamp::assert_genesis(); + let new_account = create_signer(new_account_address); + make_account(&new_account, DUMMY_AUTH_KEY); + new_account + } + + spec create_genesis_account { + aborts_if !Timestamp::is_genesis(); + aborts_if len(DUMMY_AUTH_KEY) != 32; + aborts_if exists(new_account_address); + } + + /// Release genesis account signer + public fun release_genesis_signer(_genesis_account: signer){ + } + + spec release_genesis_signer { + aborts_if false; + } + + /// Deprecated since @v5 + public fun create_account(_authentication_key: vector): address { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + spec create_account { + aborts_if true; + } + + /// Creates a new account at `fresh_address` with a balance of zero and empty auth key, the address as init auth key for check transaction. + /// Creating an account at address StarcoinFramework will cause runtime failure as it is a + /// reserved address for the MoveVM. + public fun create_account_with_address(fresh_address: address) acquires Account { + let new_account = create_signer(fresh_address); + make_account(&new_account, DUMMY_AUTH_KEY); + // Make sure all account accept STC. + if (!STC::is_stc()){ + do_accept_token(&new_account); + }; + do_accept_token(&new_account); + } + + spec create_account_with_address { + //abort condition for make_account + aborts_if exists(fresh_address); + //abort condition for do_accept_token + aborts_if Token::spec_token_code() != Token::spec_token_code() && exists>(fresh_address); + //abort condition for do_accept_token + aborts_if exists>(fresh_address); + ensures exists_at(fresh_address); + ensures exists>(fresh_address); + } + + fun make_account( + new_account: &signer, + authentication_key: vector, + ) { + assert!(Vector::length(&authentication_key) == 32, Errors::invalid_argument(EMALFORMED_AUTHENTICATION_KEY)); + let new_account_addr = Signer::address_of(new_account); + Event::publish_generator(new_account); + move_to(new_account, Account { + authentication_key, + withdrawal_capability: Option::some( + WithdrawCapability { + account_address: new_account_addr + }), + key_rotation_capability: Option::some( + KeyRotationCapability { + account_address: new_account_addr + }), + withdraw_events: Event::new_event_handle(new_account), + deposit_events: Event::new_event_handle(new_account), + accept_token_events: Event::new_event_handle(new_account), + sequence_number: 0, + }); + move_to(new_account, AutoAcceptToken{enable: true}); + move_to(new_account, EventStore { + rotate_auth_key_events: Event::new_event_handle(new_account), + extract_withdraw_cap_events: Event::new_event_handle(new_account), + signer_delegate_events: Event::new_event_handle(new_account), + }); + } + + spec make_account { + aborts_if len(authentication_key) != 32; + aborts_if exists(Signer::address_of(new_account)); + aborts_if exists(Signer::address_of(new_account)); + ensures exists_at(Signer::address_of(new_account)); + } + + native fun create_signer(addr: address): signer; + + public entry fun create_account_with_initial_amount(account: signer, fresh_address: address, _auth_key: vector, initial_amount: u128) + acquires Account, Balance, AutoAcceptToken { + create_account_with_initial_amount_entry(account, fresh_address, initial_amount); + } + + public entry fun create_account_with_initial_amount_v2(account: signer, fresh_address: address, initial_amount: u128) + 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); + if (initial_amount > 0) { + pay_from(&account, fresh_address, initial_amount); + }; + } + + spec create_account_with_initial_amount { + pragma verify = false; + } + + spec create_account_with_initial_amount_v2 { + pragma verify = false; + } + + /// Generate an new address and create a new account, then delegate the account and return the new account address and `SignerCapability` + public fun create_delegate_account(sender: &signer) : (address, SignerCapability) acquires Balance, Account, EventStore { + let sender_address = Signer::address_of(sender); + let sequence_number = Self::sequence_number(sender_address); + // use stc balance as part of seed, just for new address more random. + let stc_balance = Self::balance(sender_address); + + let seed_bytes = BCS::to_bytes(&sender_address); + Vector::append(&mut seed_bytes, BCS::to_bytes(&sequence_number)); + Vector::append(&mut seed_bytes, BCS::to_bytes(&stc_balance)); + + let seed_hash = Hash::sha3_256(seed_bytes); + let i = 0; + let address_bytes = Vector::empty(); + while (i < ADDRESS_LENGTH) { + Vector::push_back(&mut address_bytes, *Vector::borrow(&seed_hash,i)); + i = i + 1; + }; + let new_address = BCS::to_address(address_bytes); + Self::create_account_with_address(new_address); + let new_signer = Self::create_signer(new_address); + (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) + acquires Account, Balance, AutoAcceptToken { + let account_address = Signer::address_of(account); + if (!is_accepts_token(account_address)){ + do_accept_token(account); + }; + deposit(account_address, to_deposit); + } + + spec deposit_to_self { + aborts_if to_deposit.value == 0; + let is_accepts_token = exists>(Signer::address_of(account)); + aborts_if is_accepts_token && global>(Signer::address_of(account)).token.value + to_deposit.value > max_u128(); + aborts_if !exists(Signer::address_of(account)); + ensures exists>(Signer::address_of(account)); + } + + /// Deposits the `to_deposit` token into the `receiver`'s account balance with the no metadata + /// It's a reverse operation of `withdraw`. + public fun deposit( + receiver: address, + to_deposit: Token, + ) acquires Account, Balance, AutoAcceptToken { + deposit_with_metadata(receiver, to_deposit, x"") + } + + spec deposit { + include DepositWithMetadataAbortsIf; + } + + /// Deposits the `to_deposit` token into the `receiver`'s account balance with the attached `metadata` + /// It's a reverse operation of `withdraw_with_metadata`. + public fun deposit_with_metadata( + receiver: address, + 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); + if (deposit_value > 0u128) { + // Deposit the `to_deposit` token + deposit_to_balance(borrow_global_mut>(receiver), to_deposit); + + // emit deposit event + emit_account_deposit_event(receiver, deposit_value, metadata); + } else { + Token::destroy_zero(to_deposit); + }; + } + + spec deposit_with_metadata { + include DepositWithMetadataAbortsIf; + ensures exists>(receiver); + ensures old(global>(receiver)).token.value + to_deposit.value == global>(receiver).token.value; + } + + spec schema DepositWithMetadataAbortsIf { + receiver: address; + to_deposit: Token; + + aborts_if to_deposit.value == 0; + aborts_if !exists(receiver); + aborts_if !exists>(receiver); + + aborts_if global>(receiver).token.value + to_deposit.value > max_u128(); + + } + + /// Helper to deposit `amount` to the given account balance + fun deposit_to_balance(balance: &mut Balance, token: Token::Token) { + Token::deposit(&mut balance.token, token) + } + + spec deposit_to_balance { + 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 + public fun withdraw_from_balance(balance: &mut Balance, amount: u128): Token{ + Token::withdraw(&mut balance.token, amount) + } + + spec withdraw_from_balance { + aborts_if balance.token.value < amount; + } + + + /// Withdraw `amount` Token from the account balance + public fun withdraw(account: &signer, amount: u128): Token + acquires Account, Balance { + withdraw_with_metadata(account, amount, x"") + } + spec withdraw { + aborts_if !exists>(Signer::address_of(account)); + aborts_if !exists(Signer::address_of(account)); + aborts_if global>(Signer::address_of(account)).token.value < amount; + aborts_if Option::is_none(global(Signer::address_of(account)).withdrawal_capability); + } + + + /// Withdraw `amount` tokens from `signer` with given `metadata`. + public fun withdraw_with_metadata(account: &signer, amount: u128, metadata: vector): Token + acquires Account, Balance { + let sender_addr = Signer::address_of(account); + let sender_balance = borrow_global_mut>(sender_addr); + // The sender_addr has delegated the privilege to withdraw from her account elsewhere--abort. + assert!(!delegated_withdraw_capability(sender_addr), Errors::invalid_state(EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED)); + if (amount == 0){ + return Token::zero() + }; + emit_account_withdraw_event(sender_addr, amount, metadata); + // The sender_addr has retained her withdrawal privileges--proceed. + withdraw_from_balance(sender_balance, amount) + } + + spec withdraw_with_metadata { + aborts_if !exists>(Signer::address_of(account)); + aborts_if !exists(Signer::address_of(account)); + aborts_if global>(Signer::address_of(account)).token.value < amount; + aborts_if Option::is_none(global(Signer::address_of(account)).withdrawal_capability); + } + + spec fun spec_withdraw(account: signer, amount: u128): Token { + Token { value: amount } + } + + /// Withdraw `amount` Token from the account under cap.account_address with no metadata + public fun withdraw_with_capability( + cap: &WithdrawCapability, amount: u128 + ): Token acquires Balance, Account { + withdraw_with_capability_and_metadata(cap, amount, x"") + } + + spec withdraw_with_capability { + aborts_if !exists>(cap.account_address); + aborts_if !exists(cap.account_address); + aborts_if global>(cap.account_address).token.value < amount; + } + + /// Withdraw `amount` Token from the account under cap.account_address with metadata + public fun withdraw_with_capability_and_metadata( + cap: &WithdrawCapability, amount: u128, metadata: vector + ): Token acquires Balance, Account { + let balance = borrow_global_mut>(cap.account_address); + emit_account_withdraw_event(cap.account_address, amount, metadata); + withdraw_from_balance(balance , amount) + } + + spec withdraw_with_capability_and_metadata { + aborts_if !exists>(cap.account_address); + aborts_if !exists(cap.account_address); + aborts_if global>(cap.account_address).token.value < amount; + } + + + /// Return a unique capability granting permission to withdraw from the sender's account balance. + public fun extract_withdraw_capability( + sender: &signer + ): WithdrawCapability acquires Account, EventStore { + let sender_addr = Signer::address_of(sender); + // Abort if we already extracted the unique withdraw capability for this account. + assert!(!delegated_withdraw_capability(sender_addr), Errors::invalid_state(EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED)); + + make_event_store_if_not_exist(sender); + let event_store = borrow_global_mut(sender_addr); + Event::emit_event( + &mut event_store.extract_withdraw_cap_events, + ExtractWithdrawCapEvent { + account_address: sender_addr, + } + ); + let account = borrow_global_mut(sender_addr); + Option::extract(&mut account.withdrawal_capability) + } + + spec extract_withdraw_capability { + aborts_if !exists(Signer::address_of(sender)); + aborts_if Option::is_none(global( Signer::address_of(sender)).withdrawal_capability); + } + + /// Return the withdraw capability to the account it originally came from + public fun restore_withdraw_capability(cap: WithdrawCapability) + acquires Account { + let account = borrow_global_mut(cap.account_address); + Option::fill(&mut account.withdrawal_capability, cap) + } + + spec restore_withdraw_capability { + aborts_if Option::is_some(global(cap.account_address).withdrawal_capability); + aborts_if !exists(cap.account_address); + } + + fun emit_account_withdraw_event(account: address, amount: u128, metadata: vector) + acquires Account { + // emit withdraw event + let account = borrow_global_mut(account); + + Event::emit_event(&mut account.withdraw_events, WithdrawEvent { + amount, + token_code: Token::token_code(), + metadata, + }); + } + spec emit_account_withdraw_event { + aborts_if !exists(account); + } + + fun emit_account_deposit_event(account: address, amount: u128, metadata: vector) + acquires Account { + // emit withdraw event + let account = borrow_global_mut(account); + + Event::emit_event(&mut account.deposit_events, DepositEvent { + amount, + token_code: Token::token_code(), + metadata, + }); + } + spec emit_account_deposit_event { + aborts_if !exists(account); + } + + + /// Withdraws `amount` Token using the passed in WithdrawCapability, and deposits it + /// into the `payee`'s account balance. Creates the `payee` account if it doesn't exist. + public fun pay_from_capability( + cap: &WithdrawCapability, + payee: address, + amount: u128, + metadata: vector, + ) acquires Account, Balance, AutoAcceptToken { + let tokens = withdraw_with_capability_and_metadata(cap, amount, *&metadata); + deposit_with_metadata( + payee, + tokens, + metadata, + ); + } + + spec pay_from_capability { + // condition for withdraw_with_capability_and_metadata() + aborts_if !exists>(cap.account_address); + aborts_if !exists(cap.account_address); + aborts_if global>(cap.account_address).token.value < amount; + // condition for deposit_with_metadata() + aborts_if amount == 0; + aborts_if !exists(payee); + aborts_if !exists>(payee); + aborts_if cap.account_address != payee && global>(payee).token.value + amount > MAX_U128; + } + + /// Withdraw `amount` Token from the transaction sender's + /// account balance and send the token to the `payee` address with the + /// attached `metadata` Creates the `payee` account if it does not exist + public fun pay_from_with_metadata( + account: &signer, + payee: address, + amount: u128, + metadata: vector, + ) acquires Account, Balance, AutoAcceptToken { + let tokens = withdraw_with_metadata(account, amount, *&metadata); + deposit_with_metadata( + payee, + tokens, + metadata, + ); + } + + spec pay_from_with_metadata { + // condition for withdraw_with_metadata() + aborts_if !exists>(Signer::address_of(account)); + aborts_if !exists(Signer::address_of(account)); + aborts_if global>(Signer::address_of(account)).token.value < amount; + aborts_if Option::is_none(global(Signer::address_of(account)).withdrawal_capability); + // condition for deposit_with_metadata() + aborts_if amount == 0; + aborts_if !exists(payee); + aborts_if !exists>(payee); + aborts_if Signer::address_of(account) != payee && global>(payee).token.value + amount > max_u128(); +} + spec schema DepositWithPayerAndMetadataAbortsIf { + payer: address; + payee: address; + to_deposit: Token; + + aborts_if to_deposit.value == 0; + aborts_if !exists(payer); + aborts_if !exists(payee); + aborts_if !exists>(payee); + aborts_if global>(payee).token.value + to_deposit.value > max_u128(); + } + + + /// Withdraw `amount` Token from the transaction sender's + /// account balance and send the token to the `payee` address + /// Creates the `payee` account if it does not exist + public fun pay_from( + account: &signer, + payee: address, + amount: u128 + ) acquires Account, Balance, AutoAcceptToken { + pay_from_with_metadata(account, payee, amount, x""); + } + + spec pay_from { + // condition for withdraw_with_metadata() + aborts_if !exists>(Signer::address_of(account)); + aborts_if !exists(Signer::address_of(account)); + aborts_if global>(Signer::address_of(account)).token.value < amount; + aborts_if Option::is_none(global(Signer::address_of(account)).withdrawal_capability); + // condition for deposit_with_metadata() + aborts_if amount == 0; + aborts_if !exists(payee); + aborts_if !exists>(payee); + aborts_if Signer::address_of(account) != payee && global>(payee).token.value + amount > max_u128(); + } + + /// Rotate the authentication key for the account under cap.account_address + public fun rotate_authentication_key_with_capability( + cap: &KeyRotationCapability, + new_authentication_key: vector, + ) acquires Account { + let sender_account_resource = borrow_global_mut(cap.account_address); + // Don't allow rotating to clearly invalid key + assert!(Vector::length(&new_authentication_key) == 32, Errors::invalid_argument(EMALFORMED_AUTHENTICATION_KEY)); + sender_account_resource.authentication_key = new_authentication_key; + } + + spec rotate_authentication_key_with_capability { + aborts_if !exists(cap.account_address); + aborts_if len(new_authentication_key) != 32; + ensures global(cap.account_address).authentication_key == new_authentication_key; + } + + spec fun spec_rotate_authentication_key_with_capability(addr: address, new_authentication_key: vector): bool { + global(addr).authentication_key == new_authentication_key + } + + + /// Return a unique capability granting permission to rotate the sender's authentication key + public fun extract_key_rotation_capability(account: &signer): KeyRotationCapability + acquires Account { + let account_address = Signer::address_of(account); + // Abort if we already extracted the unique key rotation capability for this account. + assert!(!delegated_key_rotation_capability(account_address), Errors::invalid_state(EKEY_ROTATION_CAPABILITY_ALREADY_EXTRACTED)); + let account = borrow_global_mut(account_address); + Option::extract(&mut account.key_rotation_capability) + } + + spec extract_key_rotation_capability { + aborts_if !exists(Signer::address_of(account)); + aborts_if Option::is_none(global(Signer::address_of(account)).key_rotation_capability); + } + + /// Return the key rotation capability to the account it originally came from + public fun restore_key_rotation_capability(cap: KeyRotationCapability) + acquires Account { + let account = borrow_global_mut(cap.account_address); + Option::fill(&mut account.key_rotation_capability, cap) + } + public fun destroy_key_rotation_capability(cap: KeyRotationCapability) { + let KeyRotationCapability {account_address: _} = cap; + } + + spec restore_key_rotation_capability { + aborts_if Option::is_some(global(cap.account_address).key_rotation_capability); + aborts_if !exists(cap.account_address); + } + + public entry fun rotate_authentication_key(account: signer, new_key: vector) acquires Account, EventStore { + rotate_authentication_key_entry(account, new_key); + } + + public entry fun rotate_authentication_key_entry(account: signer, new_key: vector) acquires Account, EventStore { + do_rotate_authentication_key(&account, new_key); + } + + public fun do_rotate_authentication_key(account: &signer, new_key: vector) acquires Account, EventStore { + let key_rotation_capability = extract_key_rotation_capability(account); + rotate_authentication_key_with_capability(&key_rotation_capability, copy new_key); + restore_key_rotation_capability(key_rotation_capability); + + make_event_store_if_not_exist(account); + let signer_addr = Signer::address_of(account); + let event_store = borrow_global_mut(signer_addr); + Event::emit_event( + &mut event_store.rotate_auth_key_events, + RotateAuthKeyEvent { + account_address: signer_addr, + new_auth_key: new_key, + } + ); + } + + spec rotate_authentication_key { + pragma verify = false; + } + + /// Helper to return the u128 value of the `balance` for `account` + fun balance_for(balance: &Balance): u128 { + Token::value(&balance.token) + } + + spec balance_for { + aborts_if false; + } + + /// Return the current TokenType balance of the account at `addr`. + public fun balance(addr: address): u128 acquires Balance { + if (exists>(addr)) { + balance_for(borrow_global>(addr)) + } else { + 0u128 + } + } + + + /// Add a balance of `Token` type to the sending account. + public fun do_accept_token(account: &signer) acquires Account { + move_to(account, Balance{ token: Token::zero() }); + let token_code = Token::token_code(); + // Load the sender's account + let sender_account_ref = borrow_global_mut(Signer::address_of(account)); + // Log a sent event + Event::emit_event( + &mut sender_account_ref.accept_token_events, + AcceptTokenEvent { + token_code: token_code, + }, + ); + } + + spec do_accept_token { + aborts_if exists>(Signer::address_of(account)); + aborts_if !exists(Signer::address_of(account)); + } + + public entry fun accept_token(account: signer) acquires Account { + accept_token_entry(account); + } + + public entry fun accept_token_entry(account: signer) acquires Account { + do_accept_token(&account); + } + + spec accept_token { + pragma verify = false; + } + + /// This is a alias of is_accept_token + public fun is_accepts_token(addr: address): bool acquires AutoAcceptToken { + Self::is_accept_token(addr) + } + + spec is_accepts_token { + aborts_if false; + } + + /// Return whether the account at `addr` accept `Token` type tokens + public fun is_accept_token(addr: address): bool acquires AutoAcceptToken { + if (can_auto_accept_token(addr)) { + true + } else { + exists>(addr) + } + } + + spec is_accept_token { + aborts_if false; + } + + /// Check whether the address can auto accept token. + public fun can_auto_accept_token(addr: address): bool acquires AutoAcceptToken { + if (exists(addr)) { + borrow_global(addr).enable + } else { + false + } + } + + public entry fun set_auto_accept_token_entry(account: signer, enable: bool) acquires AutoAcceptToken { + set_auto_accept_token(&account, enable); + } + + /// Configure whether auto-accept tokens. + public fun set_auto_accept_token(account: &signer, enable: bool) acquires AutoAcceptToken { + let addr = Signer::address_of(account); + if (exists(addr)) { + let config = borrow_global_mut(addr); + config.enable = enable; + } else { + move_to(account, AutoAcceptToken{enable}); + }; + } + spec set_auto_accept_token { + aborts_if false; + } + + /// try to accept token for `addr`. + fun try_accept_token(addr: address) acquires AutoAcceptToken, Account { + if (!exists>(addr)) { + if (can_auto_accept_token(addr)) { + let signer = create_signer(addr); + do_accept_token(&signer); + }else{ + abort Errors::not_published(ERR_TOKEN_NOT_ACCEPT) + } + }; + } + spec try_accept_token { + aborts_if false; + } + + /// Helper to return the sequence number field for given `account` + fun sequence_number_for_account(account: &Account): u64 { + account.sequence_number + } + + spec is_accepts_token { + aborts_if false; + } + + /// Return the current sequence number at `addr` + public fun sequence_number(addr: address): u64 acquires Account { + sequence_number_for_account(borrow_global(addr)) + } + + spec sequence_number { + aborts_if !exists(addr); + } + + /// Return the authentication key for this account + public fun authentication_key(addr: address): vector acquires Account { + *&borrow_global(addr).authentication_key + } + + spec authentication_key { + aborts_if !exists(addr); + } + + /// Return true if the account at `addr` has delegated its key rotation capability + public fun delegated_key_rotation_capability(addr: address): bool + acquires Account { + Option::is_none(&borrow_global(addr).key_rotation_capability) + } + + spec delegated_key_rotation_capability { + aborts_if !exists(addr); + } + + /// Return true if the account at `addr` has delegated its withdraw capability + public fun delegated_withdraw_capability(addr: address): bool + acquires Account { + Option::is_none(&borrow_global(addr).withdrawal_capability) + } + + spec delegated_withdraw_capability { + aborts_if !exists(addr); + } + + /// Return a reference to the address associated with the given withdraw capability + public fun withdraw_capability_address(cap: &WithdrawCapability): &address { + &cap.account_address + } + + spec withdraw_capability_address { + aborts_if false; + } + + /// Return a reference to the address associated with the given key rotation capability + public fun key_rotation_capability_address(cap: &KeyRotationCapability): &address { + &cap.account_address + } + + spec key_rotation_capability_address { + aborts_if false; + } + + /// Checks if an account exists at `check_addr` + public fun exists_at(check_addr: address): bool { + exists(check_addr) + } + + spec exists_at { + aborts_if false; + } + + fun is_dummy_auth_key(account: &Account): bool { + *&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 + /// - That the account has enough balance to pay for all of the gas + /// - That the sequence number matches the transaction's sequence key + public fun txn_prologue( + account: &signer, + txn_sender: address, + txn_sequence_number: u64, + 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); + + // 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 (is_dummy_auth_key(sender_account)){ + // 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) == *&sender_account.authentication_key, + 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 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)); + + } + + + /// The epilogue is invoked at the end of transactions. + /// It collects gas and bumps the sequence number + public fun txn_epilogue( + account: &signer, + txn_sender: address, + txn_sequence_number: u64, + txn_gas_price: u64, + txn_max_gas_units: u64, + gas_units_remaining: u64, + ) acquires Account, Balance { + 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( + 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, + ) acquires Account, Balance { + 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) + } + + 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_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 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_stc > 0) { + let transaction_fee_token = withdraw_from_balance( + borrow_global_mut>(txn_sender), + transaction_fee_amount_token + ); + 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); + }; + } + + 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_sequence_number + 1 > max_u64(); + 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); + } + + /// Remove zero Balance + public fun remove_zero_balance(account: &signer) acquires Balance { + let addr: address = Signer::address_of(account); + let Balance { token } = move_from>(addr); + Token::destroy_zero(token); + } + + spec remove_zero_balance { + let addr = Signer::address_of(account); + aborts_if !exists>(addr); + ensures !exists>(addr); + } + + /// Make a event store if it's not exist. + fun make_event_store_if_not_exist(account: &signer) { + if (!exists(Signer::address_of(account))) { + move_to(account, EventStore { + rotate_auth_key_events: Event::new_event_handle(account), + extract_withdraw_cap_events: Event::new_event_handle(account), + signer_delegate_events: Event::new_event_handle(account), + }) + }; + } +} + +} diff --git a/release/v13/sources/AccountScripts.move b/release/v13/sources/AccountScripts.move new file mode 100644 index 00000000..ce11e3b6 --- /dev/null +++ b/release/v13/sources/AccountScripts.move @@ -0,0 +1,21 @@ +address StarcoinFramework { +module AccountScripts { + use StarcoinFramework::Account; + /// Enable account's auto-accept-token feature. + /// The script function is reenterable. + public entry fun enable_auto_accept_token(account: signer) { + Account::set_auto_accept_token_entry(account, true); + } + + /// Disable account's auto-accept-token feature. + /// The script function is reenterable. + public entry fun disable_auto_accept_token(account: signer) { + Account::set_auto_accept_token_entry(account, false); + } + + /// Remove zero Balance + public entry fun remove_zero_balance(account: signer) { + Account::remove_zero_balance_entry(account); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Arith.move b/release/v13/sources/Arith.move new file mode 100644 index 00000000..83cbdc27 --- /dev/null +++ b/release/v13/sources/Arith.move @@ -0,0 +1,442 @@ +address StarcoinFramework { +/// Helper module to do u64 arith. +module Arith { + use StarcoinFramework::Errors; + const ERR_INVALID_CARRY: u64 = 301; + const ERR_INVALID_BORROW: u64 = 302; + + const P32: u64 = 0x100000000; + const P64: u128 = 0x10000000000000000; + + spec module { + pragma verify = true; + pragma aborts_if_is_strict; + } + + /// split u64 to (high, low) + public fun split_u64(i: u64): (u64, u64) { + (i >> 32, i & 0xFFFFFFFF) + } + + spec split_u64 { + pragma verify = false; + pragma opaque; // MVP cannot reason about bitwise operation + ensures [abstract] result_1 == i / P32; + ensures [abstract] result_2 == i % P32; + } + + /// combine (high, low) to u64, + /// any lower bits of `high` will be erased, any higher bits of `low` will be erased. + public fun combine_u64(hi: u64, lo: u64): u64 { + (hi << 32) | (lo & 0xFFFFFFFF) + } + + spec combine_u64 { + pragma verify = false; + pragma opaque = true; // MVP cannot reason about bitwise operation + let hi_32 = hi % P32; + let lo_32 = lo % P32; + ensures [abstract] result == hi_32 * P32 + lo_32; + } + + /// a + b, with carry + public fun adc(a: u64, b: u64, carry: &mut u64) : u64 { + assert!(*carry <= 1, Errors::invalid_argument(ERR_INVALID_CARRY)); + let (a1, a0) = split_u64(a); + let (b1, b0) = split_u64(b); + let (c, r0) = split_u64(a0 + b0 + *carry); + let (c, r1) = split_u64(a1 + b1 + c); + *carry = c; + combine_u64(r1, r0) + } + + spec adc { + // Carry has either to be 0 or 1 + aborts_if !(carry == 0 || carry == 1); + ensures carry == 0 || carry == 1; + // Result with or without carry + ensures carry == 0 ==> result == a + b + old(carry); + ensures carry == 1 ==> P64 + result == a + b + old(carry); + } + + /// a - b, with borrow + public fun sbb(a: u64, b: u64, borrow: &mut u64): u64 { + assert!(*borrow <= 1, Errors::invalid_argument(ERR_INVALID_BORROW)); + let (a1, a0) = split_u64(a); + let (b1, b0) = split_u64(b); + let (b, r0) = split_u64(P32 + a0 - b0 - *borrow); + let borrowed = 1 - b; + let (b, r1) = split_u64(P32 + a1 - b1 - borrowed); + *borrow = 1 - b; + + combine_u64(r1, r0) + } + + spec sbb { + // Borrow has either to be 0 or 1 + aborts_if !(borrow == 0 || borrow == 1); + ensures borrow == 0 || borrow == 1; + // Result with or without borrow + ensures borrow == 0 ==> result == a - b - old(borrow); + ensures borrow == 1 ==> result == P64 + a - b - old(borrow); + } +} + +/// Implementation u256. +module U256 { + + spec module { + pragma verify = true; + } + + use StarcoinFramework::Vector; + use StarcoinFramework::Errors; + + const WORD: u8 = 4; + const P32: u64 = 0x100000000; + const P64: u128 = 0x10000000000000000; + + const ERR_INVALID_LENGTH: u64 = 100; + const ERR_OVERFLOW: u64 = 200; + /// use vector to represent data. + /// so that we can use buildin vector ops later to construct U256. + /// vector should always has two elements. + struct U256 has copy, drop, store { + /// little endian representation + bits: vector, + } + + spec U256 { + invariant len(bits) == 4; + } + + spec fun value_of_U256(a: U256): num { + a.bits[0] + + a.bits[1] * P64 + + a.bits[2] * P64 * P64 + + a.bits[3] * P64 * P64 * P64 + } + + public fun zero(): U256 { + from_u128(0u128) + } + + public fun one(): U256 { + from_u128(1u128) + } + + public fun from_u64(v: u64): U256 { + from_u128((v as u128)) + } + + public fun from_u128(v: u128): U256 { + let low = ((v & 0xffffffffffffffff) as u64); + let high = ((v >> 64) as u64); + let bits = Vector::singleton(low); + Vector::push_back(&mut bits, high); + Vector::push_back(&mut bits, 0u64); + Vector::push_back(&mut bits, 0u64); + U256 { bits } + } + + spec from_u128 { + pragma verify = false; + pragma opaque; // Original function has bitwise operator + ensures value_of_U256(result) == v; + } + + #[test] + fun test_from_u128() { + // 2^64 + 1 + let v = from_u128(18446744073709551617u128); + assert!(*Vector::borrow(&v.bits, 0) == 1, 0); + assert!(*Vector::borrow(&v.bits, 1) == 1, 1); + assert!(*Vector::borrow(&v.bits, 2) == 0, 2); + assert!(*Vector::borrow(&v.bits, 3) == 0, 3); + } + + public fun from_big_endian(data: vector): U256 { + // TODO: define error code. + assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH)); + from_bytes(&data, true) + } + + spec from_big_endian { + pragma verify = false; // TODO: How to interpret the value of vector data of bytes + } + + public fun from_little_endian(data: vector): U256 { + // TODO: define error code. + assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH)); + from_bytes(&data, false) + } + + spec from_little_endian { + pragma verify = false; // TODO: How to interpret the value of vector data of bytes + } + + public fun to_u128(v: &U256): u128 { + assert!(*Vector::borrow(&v.bits, 3) == 0, Errors::invalid_state(ERR_OVERFLOW)); + assert!(*Vector::borrow(&v.bits, 2) == 0, Errors::invalid_state(ERR_OVERFLOW)); + ((*Vector::borrow(&v.bits, 1) as u128) << 64) | (*Vector::borrow(&v.bits, 0) as u128) + } + + spec to_u128 { + pragma verify = false; + pragma opaque; // Original function has bitwise operator + aborts_if value_of_U256(v) >= P64 * P64; + ensures value_of_U256(v) == result; + } + + #[test] + fun test_to_u128() { + // 2^^128 - 1 + let i = 340282366920938463463374607431768211455u128; + let v = from_u128(i); + assert!(to_u128(&v) == i, 128); + } + #[test] + #[expected_failure] + fun test_to_u128_overflow() { + // 2^^128 - 1 + let i = 340282366920938463463374607431768211455u128; + let v = from_u128(i); + let v = add(v, one()); + to_u128(&v); + } + + const EQUAL: u8 = 0; + const LESS_THAN: u8 = 1; + const GREATER_THAN: u8 = 2; + + public fun compare(a: &U256, b: &U256): u8 { + let i = (WORD as u64); + while (i > 0) { + i = i - 1; + let a_bits = *Vector::borrow(&a.bits, i); + let b_bits = *Vector::borrow(&b.bits, i); + if (a_bits != b_bits) { + if (a_bits < b_bits) { + return LESS_THAN + } else { + return GREATER_THAN + } + } + }; + return EQUAL + } + + // TODO: MVP interprets it wrong + // spec compare { + // let va = value_of_U256(a); + // let vb = value_of_U256(b); + // ensures (va > vb) ==> (result == GREATER_THAN); + // ensures (va < vb) ==> (result == LESS_THAN); + // ensures (va == vb) ==> (result == EQUAL); + // } + + #[test] + fun test_compare() { + let a = from_u64(111); + let b = from_u64(111); + let c = from_u64(112); + let d = from_u64(110); + assert!(compare(&a, &b) == EQUAL, 0); + assert!(compare(&a, &c) == LESS_THAN, 1); + assert!(compare(&a, &d) == GREATER_THAN, 2); + } + + + public fun add(a: U256, b: U256): U256 { + native_add(&mut a, &b); + a + } + + spec add { + aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(result) == value_of_U256(a) + value_of_U256(b); + } + + #[test] + fun test_add() { + let a = Self::one(); + let b = Self::from_u128(10); + let ret = Self::add(a, b); + assert!(compare(&ret, &from_u64(11)) == EQUAL, 0); + } + + public fun sub(a: U256, b: U256): U256 { + native_sub(&mut a, &b); + a + } + + spec sub { + aborts_if value_of_U256(a) < value_of_U256(b); + ensures value_of_U256(result) == value_of_U256(a) - value_of_U256(b); + } + + #[test] + #[expected_failure] + fun test_sub_overflow() { + let a = Self::one(); + let b = Self::from_u128(10); + let _ = Self::sub(a, b); + } + + #[test] + fun test_sub_ok() { + let a = Self::from_u128(10); + let b = Self::one(); + let ret = Self::sub(a, b); + assert!(compare(&ret, &from_u64(9)) == EQUAL, 0); + } + + public fun mul(a: U256, b: U256): U256 { + native_mul(&mut a, &b); + a + } + + spec mul { + pragma verify = false; + pragma timeout = 200; // Take longer time + aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(result) == value_of_U256(a) * value_of_U256(b); + } + + #[test] + fun test_mul() { + let a = Self::from_u128(10); + let b = Self::from_u64(10); + let ret = Self::mul(a, b); + assert!(compare(&ret, &from_u64(100)) == EQUAL, 0); + } + + public fun div(a: U256, b: U256): U256 { + native_div(&mut a, &b); + a + } + + spec div { + pragma verify = false; + pragma timeout = 160; // Might take longer time + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(result) == value_of_U256(a) / value_of_U256(b); + } + + #[test] + fun test_div() { + let a = Self::from_u128(10); + let b = Self::from_u64(2); + let c = Self::from_u64(3); + // as U256 cannot be implicitly copied, we need to add copy keyword. + assert!(compare(&Self::div(copy a, b), &from_u64(5)) == EQUAL, 0); + assert!(compare(&Self::div(copy a, c), &from_u64(3)) == EQUAL, 0); + } + + public fun rem(a: U256, b: U256): U256 { + native_rem(&mut a, &b); + a + } + + spec rem { + pragma verify = false; + pragma timeout = 160; // Might take longer time + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(result) == value_of_U256(a) % value_of_U256(b); + } + + #[test] + fun test_rem() { + let a = Self::from_u128(10); + let b = Self::from_u64(2); + let c = Self::from_u64(3); + assert!(compare(&Self::rem(copy a, b), &from_u64(0)) == EQUAL, 0); + assert!(compare(&Self::rem(copy a, c), &from_u64(1)) == EQUAL, 0); + } + + public fun pow(a: U256, b: U256): U256 { + native_pow(&mut a, &b); + a + } + + spec pow { + // Verfication of Pow takes enormous amount of time + // Don't verify it, and make it opaque so that the caller + // can make use of the properties listed here. + pragma verify = false; + pragma opaque; + pragma timeout = 600; + let p = pow_spec(value_of_U256(a), value_of_U256(b)); + aborts_if p >= P64 * P64 * P64 * P64; + ensures value_of_U256(result) == p; + } + + #[test] + fun test_pow() { + let a = Self::from_u128(10); + let b = Self::from_u64(1); + let c = Self::from_u64(2); + let d = Self::zero(); + assert!(compare(&Self::pow(copy a, b), &from_u64(10)) == EQUAL, 0); + assert!(compare(&Self::pow(copy a, c), &from_u64(100)) == EQUAL, 0); + assert!(compare(&Self::pow(copy a, d), &from_u64(1)) == EQUAL, 0); + } + + native fun from_bytes(data: &vector, be: bool): U256; + native fun native_add(a: &mut U256, b: &U256); + native fun native_sub(a: &mut U256, b: &U256); + native fun native_mul(a: &mut U256, b: &U256); + native fun native_div(a: &mut U256, b: &U256); + native fun native_rem(a: &mut U256, b: &U256); + native fun native_pow(a: &mut U256, b: &U256); + + spec native_add { + pragma opaque; + aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(a) == value_of_U256(old(a)) + value_of_U256(b); + } + + spec native_sub { + pragma opaque; + aborts_if value_of_U256(a) - value_of_U256(b) < 0; + ensures value_of_U256(a) == value_of_U256(old(a)) - value_of_U256(b); + } + + spec native_mul { + pragma opaque; + aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(a) == value_of_U256(old(a)) * value_of_U256(b); + } + + spec native_div { + pragma opaque; + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(a) == value_of_U256(old(a)) / value_of_U256(b); + } + + spec native_rem { + pragma opaque; + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(a) == value_of_U256(old(a)) % value_of_U256(b); + } + + spec native_pow { + pragma opaque; + aborts_if pow_spec(value_of_U256(a), value_of_U256(b)) >= P64 * P64 * P64 * P64; + ensures value_of_U256(a) == pow_spec(value_of_U256(old(a)), value_of_U256(b)); + } + + spec fun pow_spec(base: num, expon: num): num { + // This actually doesn't follow a strict definition as 0^0 is undefined + // mathematically. But the U256::pow of Rust is defined to be like this: + // Link: https://docs.rs/uint/0.9.3/src/uint/uint.rs.html#1000-1003 + if (expon > 0) { + let x = pow_spec(base, expon / 2); + if (expon % 2 == 0) { x * x } else { x * x * base } + } else { + 1 + } + } + +} +} diff --git a/release/v13/sources/Authenticator.move b/release/v13/sources/Authenticator.move new file mode 100644 index 00000000..1acda180 --- /dev/null +++ b/release/v13/sources/Authenticator.move @@ -0,0 +1,155 @@ + +address StarcoinFramework { +/// Move representation of the authenticator types +/// - Ed25519 (single-sig) +/// - MultiEd25519 (K-of-N multisig) +module Authenticator { + use StarcoinFramework::Hash; + use StarcoinFramework::BCS; + use StarcoinFramework::Vector; + use StarcoinFramework::Errors; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + const AUTHENTICATION_KEY_LENGTH: u64 = 32; + + const ED25519_SCHEME_ID: u8 = 0; + const MULTI_ED25519_SCHEME_ID: u8 = 1; + + /// A multi-ed25519 public key + struct MultiEd25519PublicKey has copy, drop, store { + /// vector of ed25519 public keys + public_keys: vector>, + /// approval threshold + threshold: u8, + } + + /// Maximum number of keys allowed in a MultiEd25519 public/private key + const MAX_MULTI_ED25519_KEYS: u64 = 32; + + const EWRONG_AUTHENTICATION_KEY_LENGTH: u64 = 101; + /// Threshold provided was 0 which can't be used to create a `MultiEd25519` key + const EZERO_THRESHOLD: u64 = 102; + /// Not enough keys were provided for the specified threshold when creating an `MultiEd25519` key + const ENOT_ENOUGH_KEYS_FOR_THRESHOLD: u64 = 103; + /// Too many keys were provided for the specified threshold when creating an `MultiEd25519` key + const ENUM_KEYS_ABOVE_MAX_THRESHOLD: u64 = 104; + + /// Create a a multisig policy from a vector of ed25519 public keys and a threshold. + /// Note: this does *not* check uniqueness of keys. Repeated keys are convenient to + /// encode weighted multisig policies. For example Alice AND 1 of Bob or Carol is + /// public_key: {alice_key, alice_key, bob_key, carol_key}, threshold: 3 + /// Aborts if threshold is zero or bigger than the length of `public_keys`. + public fun create_multi_ed25519( + public_keys: vector>, + threshold: u8 + ): MultiEd25519PublicKey { + // check threshold requirements + let len = Vector::length(&public_keys); + assert!(threshold != 0, Errors::invalid_argument(EZERO_THRESHOLD)); + assert!( + (threshold as u64) <= len, + Errors::invalid_argument(ENOT_ENOUGH_KEYS_FOR_THRESHOLD) + ); + // the multied25519 signature scheme allows at most 32 keys + assert!( + len <= MAX_MULTI_ED25519_KEYS, + Errors::invalid_argument(ENUM_KEYS_ABOVE_MAX_THRESHOLD) + ); + + MultiEd25519PublicKey { public_keys, threshold } + } + + spec create_multi_ed25519 { + aborts_if threshold == 0; + aborts_if threshold > Vector::length(public_keys); + aborts_if Vector::length(public_keys) > 32; + } + + /// Compute an authentication key for the ed25519 public key `public_key` + public fun ed25519_authentication_key(public_key: vector): vector { + Vector::push_back(&mut public_key, ED25519_SCHEME_ID); + Hash::sha3_256(public_key) + } + + spec ed25519_authentication_key { + pragma opaque = true; + aborts_if false; + ensures [abstract] result == spec_ed25519_authentication_key(public_key); + } + + /// We use an uninterpreted function to represent the result of key construction. The actual value + /// does not matter for the verification of callers. + spec fun spec_ed25519_authentication_key(public_key: vector): vector; + + /// convert authentication key to address + public fun derived_address(authentication_key: vector): address { + assert!(Vector::length(&authentication_key) == AUTHENTICATION_KEY_LENGTH, Errors::invalid_argument(EWRONG_AUTHENTICATION_KEY_LENGTH)); + let address_bytes = Vector::empty(); + + let i = 16; + while (i < 32) { + let b = *Vector::borrow(&authentication_key, i); + Vector::push_back(&mut address_bytes, b); + i = i + 1; + }; + + BCS::to_address(address_bytes) + } + + spec derived_address { + pragma opaque = true; + aborts_if len(authentication_key) != 32; + ensures [abstract] result == spec_derived_address(authentication_key); + } + + /// We use an uninterpreted function to represent the result of derived address. The actual value + /// does not matter for the verification of callers. + spec fun spec_derived_address(authentication_key: vector): address; + + /// Compute a multied25519 account authentication key for the policy `k` + public fun multi_ed25519_authentication_key(k: &MultiEd25519PublicKey): vector { + let public_keys = &k.public_keys; + let len = Vector::length(public_keys); + let authentication_key_preimage = Vector::empty(); + let i = 0; + while (i < len) { + let public_key = *Vector::borrow(public_keys, i); + Vector::append( + &mut authentication_key_preimage, + public_key + ); + i = i + 1; + }; + Vector::append(&mut authentication_key_preimage, BCS::to_bytes(&k.threshold)); + Vector::push_back(&mut authentication_key_preimage, MULTI_ED25519_SCHEME_ID); + Hash::sha3_256(authentication_key_preimage) + } + + spec multi_ed25519_authentication_key { + aborts_if false; + } + + /// Return the public keys involved in the multisig policy `k` + public fun public_keys(k: &MultiEd25519PublicKey): &vector> { + &k.public_keys + } + + spec public_keys { + aborts_if false; + } + + /// Return the threshold for the multisig policy `k` + public fun threshold(k: &MultiEd25519PublicKey): u8 { + *&k.threshold + } + + spec threshold { + aborts_if false; + } + +} +} diff --git a/release/v13/sources/BCS.move b/release/v13/sources/BCS.move new file mode 100644 index 00000000..2c524dd5 --- /dev/null +++ b/release/v13/sources/BCS.move @@ -0,0 +1,696 @@ +address StarcoinFramework { +/// Utility for converting a Move value to its binary representation in BCS (Diem Canonical +/// Serialization). BCS is the binary encoding for Move resources and other non-module values +/// published on-chain. +module BCS { + + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + use StarcoinFramework::Option; + use StarcoinFramework::BCS; + + const ERR_INPUT_NOT_LARGE_ENOUGH: u64 = 201; + const ERR_UNEXPECTED_BOOL_VALUE: u64 = 205; + const ERR_OVERFLOW_PARSING_ULEB128_ENCODED_UINT32: u64 = 206; + const ERR_INVALID_ULEB128_NUMBER_UNEXPECTED_ZERO_DIGIT: u64 = 207; + const INTEGER32_MAX_VALUE: u64 = 2147483647; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + /// Return the binary representation of `v` in BCS (Starcoin Canonical Serialization) format + native public fun to_bytes(v: &MoveValue): vector; + + /// Return the address of key bytes + native public fun to_address(key_bytes: vector): address; + // ------------------------------------------------------------------------ + // Specification + // ------------------------------------------------------------------------ + + + spec native fun serialize(v: &MoveValue): vector; + + + public fun deserialize_option_bytes_vector(input: &vector, offset: u64): (vector>>, u64) { + let (len, new_offset) = deserialize_len(input, offset); + let i = 0; + let vec = Vector::empty>>(); + while (i < len) { + let (opt_bs, o) = deserialize_option_bytes(input, new_offset); + Vector::push_back(&mut vec, opt_bs); + new_offset = o; + i = i + 1; + }; + (vec, new_offset) + } + spec deserialize_option_bytes_vector { + pragma verify = false; + } + + public fun deserialize_bytes_vector(input: &vector, offset: u64): (vector>, u64) { + let (len, new_offset) = deserialize_len(input, offset); + let i = 0; + let vec = Vector::empty>(); + while (i < len) { + let (opt_bs, o) = deserialize_bytes(input, new_offset); + Vector::push_back(&mut vec, opt_bs); + new_offset = o; + i = i + 1; + }; + (vec, new_offset) + } + + spec deserialize_bytes_vector { + pragma verify = false; + } + + #[test] + public fun test_deserialize_bytes_array() { + let hello = b"hello"; + let world = b"world"; + let hello_world = Vector::empty>(); + Vector::push_back(&mut hello_world, hello); + Vector::push_back(&mut hello_world, world); + let bs = BCS::to_bytes>>(&hello_world); + let (r, _) = deserialize_bytes_vector(&bs, 0); + assert!(hello_world == r, 1001); + } + + public fun deserialize_u64_vector(input: &vector, offset: u64): (vector, u64) { + let (len, new_offset) = deserialize_len(input, offset); + let i = 0; + let vec = Vector::empty(); + while (i < len) { + let (opt_bs, o) = deserialize_u64(input, new_offset); + Vector::push_back(&mut vec, opt_bs); + new_offset = o; + i = i + 1; + }; + (vec, new_offset) + } + + spec deserialize_u64_vector { + pragma verify = false; + } + + public fun deserialize_u128_vector(input: &vector, offset: u64): (vector, u64) { + let (len, new_offset) = deserialize_len(input, offset); + let i = 0; + let vec = Vector::empty(); + while (i < len) { + let (opt_bs, o) = deserialize_u128(input, new_offset); + Vector::push_back(&mut vec, opt_bs); + new_offset = o; + i = i + 1; + }; + (vec, new_offset) + } + + spec deserialize_u128_vector { + pragma verify = false; + } + + #[test] + public fun test_deserialize_u128_array() { + let hello:u128 = 1111111; + let world:u128 = 2222222; + let hello_world = Vector::empty(); + Vector::push_back(&mut hello_world, hello); + Vector::push_back(&mut hello_world, world); + let bs = BCS::to_bytes>(&hello_world); + let (r, _) = deserialize_u128_vector(&bs, 0); + assert!(hello_world == r, 1002); + } + + public fun deserialize_option_bytes(input: &vector, offset: u64): (Option::Option>, u64) { + let (tag, new_offset) = deserialize_option_tag(input, offset); + if (!tag) { + return (Option::none>(), new_offset) + } else { + let (bs, new_offset) = deserialize_bytes(input, new_offset); + return (Option::some>(bs), new_offset) + } + } + + spec deserialize_option_bytes { + pragma verify = false; + } + + public fun deserialize_address(input: &vector, offset: u64): (address, u64) { + let (content, new_offset) = deserialize_16_bytes(input, offset); + (BCS::to_address(content), new_offset) + } + + spec deserialize_address { + pragma verify = false; + } + + #[test] + fun test_deserialize_address() { + let addr = @0x18351d311d32201149a4df2a9fc2db8a; + let bs = BCS::to_bytes
(&addr); + let (r, offset) = deserialize_address(&bs, 0); + assert!(addr == r, 1003); + assert!(offset == 16, 1004); + } + + public fun deserialize_16_bytes(input: &vector, offset: u64): (vector, u64) { + let content = get_n_bytes(input, offset, 16); + (content, offset + 16) + } + + spec deserialize_16_bytes { + pragma verify = false; + } + + public fun deserialize_bytes(input: &vector, offset: u64): (vector, u64) { + let (len, new_offset) = deserialize_len(input, offset); + let content = get_n_bytes(input, new_offset, len); + (content, new_offset + len) + } + + spec deserialize_bytes { + pragma verify = false; + } + + #[test] + public fun test_deserialize_bytes() { + let hello = b"hello world"; + let bs = BCS::to_bytes>(&hello); + let (r, _) = deserialize_bytes(&bs, 0); + assert!(hello == r, 1005); + } + + public fun deserialize_u128(input: &vector, offset: u64): (u128, u64) { + let u = get_n_bytes_as_u128(input, offset, 16); + (u, offset + 16) + } + + spec deserialize_u128 { + pragma verify = false; + } + + #[test] + fun test_deserialize_u128() { + let max_int128 = 170141183460469231731687303715884105727; + let u: u128 = max_int128; + let bs = BCS::to_bytes(&u); + let (r, offset) = deserialize_u128(&bs, 0); + assert!(u == r, 1006); + assert!(offset == 16, 1007); + } + + + public fun deserialize_u64(input: &vector, offset: u64): (u64, u64) { + let u = get_n_bytes_as_u128(input, offset, 8); + ((u as u64), offset + 8) + } + + spec deserialize_u64 { + pragma verify = false; + } + + #[test] + fun test_deserialize_u64() { + let u: u64 = 12811111111111; + let bs = BCS::to_bytes(&u); + let (r, offset) = deserialize_u64(&bs, 0); + assert!(u == r, 1008); + assert!(offset == 8, 1009); + } + + public fun deserialize_u32(input: &vector, offset: u64): (u64, u64) { + let u = get_n_bytes_as_u128(input, offset, 4); + ((u as u64), offset + 4) + } + + spec deserialize_u32 { + pragma verify = false; + } + + #[test] + fun test_deserialize_u32() { + let u: u64 = 1281111; + let bs = BCS::to_bytes(&u); + let (r, offset) = deserialize_u32(&bs, 0); + _ = r; + assert!(u == r, 1010); + assert!(offset == 4, 1011); + } + + public fun deserialize_u16(input: &vector, offset: u64): (u64, u64) { + let u = get_n_bytes_as_u128(input, offset, 2); + ((u as u64), offset + 2) + } + + spec deserialize_u16 { + pragma verify = false; + } + + public fun deserialize_u8(input: &vector, offset: u64): (u8, u64) { + let u = get_byte(input, offset); + (u, offset + 1) + } + + spec deserialize_u8 { + pragma verify = false; + } + + #[test] + fun test_deserialize_u8() { + let u: u8 = 128; + let bs = BCS::to_bytes(&u); + let (r, offset) = deserialize_u8(&bs, 0); + assert!(u == r, 1012); + assert!(offset == 1, 1013); + } + + public fun deserialize_option_tag(input: &vector, offset: u64): (bool, u64) { + deserialize_bool(input, offset) + } + + spec deserialize_option_tag { + pragma verify = false; + } + + public fun deserialize_len(input: &vector, offset: u64): (u64, u64) { + deserialize_uleb128_as_u32(input, offset) + } + + spec deserialize_len { + pragma verify = false; + } + + public fun deserialize_bool(input: &vector, offset: u64): (bool, u64) { + let b = get_byte(input, offset); + if (b == 1) { + return (true, offset + 1) + } else if (b == 0) { + return (false, offset + 1) + } else { + abort ERR_UNEXPECTED_BOOL_VALUE + } + } + + spec deserialize_bool { + pragma verify = false; + } + + #[test] + public fun test_deserialize_bool() { + let t = true; + let bs = BCS::to_bytes(&t); + let (d, _) = deserialize_bool(&bs, 0); + assert!(d, 1014); + + let f = false; + bs = BCS::to_bytes(&f); + (d, _) = deserialize_bool(&bs, 0); + assert!(!d, 1015); + } + + fun get_byte(input: &vector, offset: u64): u8 { + assert!(((offset + 1) <= Vector::length(input)) && (offset < offset + 1), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH)); + *Vector::borrow(input, offset) + } + + spec get_byte { + pragma verify = false; + } + + fun get_n_bytes(input: &vector, offset: u64, n: u64): vector { + assert!(((offset + n) <= Vector::length(input)) && (offset < offset + n), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH)); + let i = 0; + let content = Vector::empty(); + while (i < n) { + let b = *Vector::borrow(input, offset + i); + Vector::push_back(&mut content, b); + i = i + 1; + }; + content + } + + spec get_n_bytes { + pragma verify = false; + } + + fun get_n_bytes_as_u128(input: &vector, offset: u64, n: u64): u128 { + assert!(((offset + n) <= Vector::length(input)) && (offset < offset + n), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH)); + let number: u128 = 0; + let i = 0; + while (i < n) { + let byte = *Vector::borrow(input, offset + i); + let s = (i as u8) * 8; + number = number + ((byte as u128) << s); + i = i + 1; + }; + number + } + + spec get_n_bytes_as_u128 { + pragma verify = false; + } + + public fun deserialize_uleb128_as_u32(input: &vector, offset: u64): (u64, u64) { + let value: u64 = 0; + let shift = 0; + let new_offset = offset; + while (shift < 32) { + let x = get_byte(input, new_offset); + new_offset = new_offset + 1; + let digit: u8 = x & 0x7F; + value = value | (digit as u64) << shift; + if ((value < 0) || (value > INTEGER32_MAX_VALUE)) { + abort ERR_OVERFLOW_PARSING_ULEB128_ENCODED_UINT32 + }; + if (digit == x) { + if (shift > 0 && digit == 0) { + abort ERR_INVALID_ULEB128_NUMBER_UNEXPECTED_ZERO_DIGIT + }; + return (value, new_offset) + }; + shift = shift + 7 + }; + abort ERR_OVERFLOW_PARSING_ULEB128_ENCODED_UINT32 + } + + spec deserialize_uleb128_as_u32 { + pragma opaque; + pragma verify = false; + } + + #[test] + public fun test_deserialize_uleb128_as_u32() { + let i: u64 = 0x7F; + let bs = serialize_u32_as_uleb128(i); + let (len, _) = deserialize_uleb128_as_u32(&bs, 0); + assert!(len == i, 1016); + + let i2: u64 = 0x8F; + let bs2 = serialize_u32_as_uleb128(i2); + (len, _) = deserialize_uleb128_as_u32(&bs2, 0); + assert!(len == i2, 1017); + } + + + #[test] + public fun test_deserialize_uleb128_as_u32_max_int() { + let max_int: u64 = 2147483647; + + let bs = serialize_u32_as_uleb128(max_int); + let (len, _) = deserialize_uleb128_as_u32(&bs, 0); + assert!(len == max_int, 1018); + } + + #[test] + #[expected_failure(abort_code = 206, location=StarcoinFramework::BCS)] + public fun test_deserialize_uleb128_as_u32_exceeded_max_int() { + let max_int: u64 = 2147483647; + let exceeded_max_int: u64 = max_int + 1; + + let bs = serialize_u32_as_uleb128(exceeded_max_int); + let (_, _) = deserialize_uleb128_as_u32(&bs, 0); + } + + + fun serialize_u32_as_uleb128(value: u64): vector { + let output = Vector::empty(); + while ((value >> 7) != 0) { + Vector::push_back(&mut output, (((value & 0x7f) | 0x80) as u8)); + value = value >> 7; + }; + Vector::push_back(&mut output, (value as u8)); + output + } + + spec serialize_u32_as_uleb128 { + pragma verify = false; + } + + // skip Vector>> + public fun skip_option_bytes_vector(input: &vector, offset: u64): u64 { + let (len, new_offset) = deserialize_len(input, offset); + let i = 0; + while (i < len) { + new_offset = skip_option_bytes(input, new_offset); + i = i + 1; + }; + new_offset + } + + spec skip_option_bytes_vector { + pragma verify = false; + } + + #[test] + fun test_skip_option_bytes_vector(){ + let vec = Vector::empty>>(); + Vector::push_back(&mut vec, Option::some(x"01020304")); + Vector::push_back(&mut vec, Option::some(x"04030201")); + let vec = to_bytes(&vec); + //vec : [2, 1, 4, 1, 2, 3, 4, 1, 4, 4, 3, 2, 1] + assert!(skip_option_bytes_vector(&vec, 0) == 13,2000); + } + + // skip Option::Option> + public fun skip_option_bytes(input: &vector, offset: u64): u64 { + let (tag, new_offset) = deserialize_option_tag(input, offset); + if (!tag) { + new_offset + } else { + skip_bytes(input, new_offset) + } + } + + spec skip_option_bytes { + pragma verify = false; + } + + #[test] + fun test_skip_none_option_bytes(){ + let op = Option::none>(); + let op = to_bytes(&op); + let vec = to_bytes(&x"01020304"); + Vector::append(&mut op, vec); + // op : [0, 4, 1, 2, 3, 4] + assert!(skip_option_bytes(&op, 0) == 1,2007); + } + + #[test] + fun test_skip_some_option_bytes(){ + let op = Option::some(x"01020304"); + let op = to_bytes(&op); + let vec = to_bytes(&x"01020304"); + Vector::append(&mut op, vec); + // op : [1, 4, 1, 2, 3, 4, 4, 1, 2, 3, 4] + assert!(skip_option_bytes(&op, 0) == 6,2008); + } + + // skip vector> + public fun skip_bytes_vector(input: &vector, offset: u64): u64 { + let (len, new_offset) = deserialize_len(input, offset); + let i = 0; + while (i < len) { + new_offset = skip_bytes(input, new_offset); + i = i + 1; + }; + new_offset + } + + spec skip_bytes_vector { + pragma verify = false; + } + + // skip vector + public fun skip_bytes(input: &vector, offset: u64): u64 { + let (len, new_offset) = deserialize_len(input, offset); + new_offset + len + } + + spec skip_bytes { + pragma verify = false; + } + + #[test] + fun test_skip_bytes(){ + let vec = to_bytes(&x"01020304"); + let u_64 = to_bytes(&10); + Vector::append(&mut vec, u_64); + // vec : [4, 1, 2, 3, 4, 10, 0, 0, 0, 0, 0, 0, 0] + assert!(skip_bytes(&vec, 0) == 5,2001); + } + + // skip some bytes + public fun skip_n_bytes(input: &vector, offset: u64, n:u64): u64 { + can_skip(input, offset, n ); + offset + n + } + + spec skip_n_bytes { + pragma verify = false; + } + + #[test] + fun test_skip_n_bytes(){ + let vec = to_bytes(&x"01020304"); + let u_64 = to_bytes(&10); + Vector::append(&mut vec, u_64); + // vec : [4, 1, 2, 3, 4, 10, 0, 0, 0, 0, 0, 0, 0] + assert!(skip_n_bytes(&vec, 0, 1) == 1,2002); + } + + // skip vector + public fun skip_u64_vector(input: &vector, offset: u64): u64 { + let (len, new_offset) = deserialize_len(input, offset); + can_skip(input, new_offset, len * 8); + new_offset + len * 8 + } + + spec skip_u64_vector { + pragma verify = false; + } + + #[test] + fun test_skip_u64_vector(){ + let vec = Vector::empty(); + Vector::push_back(&mut vec, 11111); + Vector::push_back(&mut vec, 22222); + let u_64 = to_bytes(&10); + let vec = to_bytes(&vec); + Vector::append(&mut vec, u_64); + // vec : [2, 103, 43, 0, 0, 0, 0, 0, 0, 206, 86, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0] + assert!(skip_u64_vector(&vec, 0) == 17,2004); + } + + // skip vector + public fun skip_u128_vector(input: &vector, offset: u64): u64 { + let (len, new_offset) = deserialize_len(input, offset); + can_skip(input, new_offset, len * 16); + new_offset + len * 16 + } + + spec skip_u128_vector { + pragma verify = false; + } + + #[test] + fun test_skip_u128_vector(){ + let vec = Vector::empty(); + Vector::push_back(&mut vec, 11111); + Vector::push_back(&mut vec, 22222); + let u_64 = to_bytes(&10); + let vec = to_bytes(&vec); + Vector::append(&mut vec, u_64); + // vec : [2, 103, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0] + assert!(skip_u128_vector(&vec, 0) == 33,2003); + } + + // skip u256 + public fun skip_u256(input: &vector, offset: u64): u64 { + can_skip(input, offset, 32 ); + offset + 32 + } + + spec skip_u256 { + pragma verify = false; + } + + // skip u128 + public fun skip_u128(input: &vector, offset: u64): u64 { + can_skip(input, offset, 16 ); + offset + 16 + } + + spec skip_u128 { + pragma verify = false; + } + + #[test] + fun test_skip_u128(){ + let u_128:u128 = 100; + let u_128 = to_bytes(&u_128); + let vec = to_bytes(&x"01020304"); + Vector::append(&mut u_128, vec); + // u_128 : [100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3, 4] + assert!(skip_u128(&u_128, 0) == 16,2005); + } + + // skip u64 + public fun skip_u64(input: &vector, offset: u64): u64 { + can_skip(input, offset, 8 ); + offset + 8 + } + + spec skip_u64 { + pragma verify = false; + } + + #[test] + fun test_skip_u64(){ + let u_64:u64 = 100; + let u_64 = to_bytes(&u_64); + let vec = to_bytes(&x"01020304"); + Vector::append(&mut u_64, vec); + // u_64 : [100, 0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3, 4] + assert!(skip_u64(&u_64, 0) == 8,2006); + } + + // skip u32 + public fun skip_u32(input: &vector, offset: u64): u64 { + can_skip(input, offset, 4 ); + offset + 4 + } + + spec skip_u32 { + pragma verify = false; + } + + // skip u16 + public fun skip_u16(input: &vector, offset: u64): u64 { + can_skip(input, offset, 2 ); + offset + 2 + } + + spec skip_u16 { + pragma verify = false; + } + + // skip address + public fun skip_address(input: &vector, offset: u64): u64 { + skip_n_bytes(input, offset, 16) + } + + spec skip_address { + pragma verify = false; + } + + #[test] + fun test_address(){ + let addr:address = @0x1; + let addr = to_bytes(&addr); + let vec = to_bytes(&x"01020304"); + Vector::append(&mut addr, vec); + // addr : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 1, 2, 3, 4] + assert!(skip_address(&addr, 0) == 16,2006); + } + + // skip bool + public fun skip_bool(input: &vector, offset: u64): u64{ + can_skip(input, offset, 1); + offset + 1 + } + + spec skip_bool { + pragma verify = false; + } + + fun can_skip(input: &vector, offset: u64, n: u64){ + assert!(((offset + n) <= Vector::length(input)) && (offset < offset + n), Errors::invalid_state(ERR_INPUT_NOT_LARGE_ENOUGH)); + } + + spec can_skip { + pragma verify = false; + } +} +} diff --git a/release/v13/sources/BitOperators.move b/release/v13/sources/BitOperators.move new file mode 100644 index 00000000..9f8f0138 --- /dev/null +++ b/release/v13/sources/BitOperators.move @@ -0,0 +1,39 @@ +address StarcoinFramework { +/// Functions for bit operations. +module BitOperators { + + spec module { + pragma verify = false; + } + + /// bit and: x & y + public fun and(x: u64, y: u64): u64 { + (x & y as u64) + } + + /// bit or: x | y + public fun or(x: u64, y: u64): u64 { + (x | y as u64) + } + + /// bit xor: x ^ y + public fun xor(x: u64, y: u64): u64 { + (x ^ y as u64) + } + + /// bit not: !x + public fun not(x: u64): u64 { + (x ^ 18446744073709551615u64 as u64) + } + + /// left shift n bits. + public fun lshift(x: u64, n: u8): u64 { + (x << n as u64) + } + + /// right shift n bits. + public fun rshift(x: u64, n: u8): u64 { + (x >> n as u64) + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Block.move b/release/v13/sources/Block.move new file mode 100644 index 00000000..b90033d9 --- /dev/null +++ b/release/v13/sources/Block.move @@ -0,0 +1,465 @@ +address StarcoinFramework { +/// Block module provide metadata for generated blocks. +module Block { + use StarcoinFramework::FlexiDagConfig; + use StarcoinFramework::Event; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + use StarcoinFramework::Option; + use StarcoinFramework::Ring; + use StarcoinFramework::BCS; + use StarcoinFramework::Hash; + + spec module { + pragma verify; + pragma aborts_if_is_strict = true; + } + + /// Block metadata struct. + struct BlockMetadata has key { + /// number of the current block + number: u64, + /// Hash of the parent block. + parent_hash: vector, + /// Author of the current block. + author: address, + /// number of uncles. + uncles: u64, + /// Hash of the parents hash for a Dag block. + parents_hash: Option::Option>, + /// Handle of events when new blocks are emitted + new_block_events: Event::EventHandle, + } + + /// Events emitted when new block generated. + struct NewBlockEvent has drop, store { + number: u64, + author: address, + timestamp: u64, + uncles: u64, + parents_hash: Option::Option>, + } + + // + struct Checkpoint has copy,drop,store{ + //number of the block + block_number: u64, + //Hash of the block + block_hash: vector, + //State root of the block + state_root: Option::Option>, + } + + // + struct Checkpoints has key,store{ + //all checkpoints + checkpoints : Ring::Ring, + index : u64, + last_number : u64, + } + + const EBLOCK_NUMBER_MISMATCH : u64 = 17; + const ERROR_NO_HAVE_CHECKPOINT: u64 = 18; + const ERROR_NOT_BLOCK_HEADER : u64 = 19; + const ERROR_INTERVAL_TOO_LITTLE: u64 = 20; + + const CHECKPOINT_LENGTH : u64 = 60; + const BLOCK_HEADER_LENGTH : u64 = 247; + const BLOCK_INTERVAL_NUMBER : u64 = 5; + + /// This can only be invoked by the GENESIS_ACCOUNT at genesis + public fun initialize(account: &signer, parent_hash: vector) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + + move_to( + account, + BlockMetadata { + number: 0, + parent_hash, + author: CoreAddresses::GENESIS_ADDRESS(), + uncles: 0, + parents_hash: Option::none>(), + new_block_events: Event::new_event_handle(account), + }); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists(Signer::address_of(account)); + } + + /// Get the current block number + public fun get_current_block_number(): u64 acquires BlockMetadata { + borrow_global(CoreAddresses::GENESIS_ADDRESS()).number + } + + spec get_current_block_number { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get the hash of the parent block. + public fun get_parent_hash(): vector acquires BlockMetadata { + *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parent_hash + } + + spec get_parent_hash { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + public fun get_parents_hash(): Option::Option> acquires BlockMetadata { + *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parents_hash + } + + spec get_parents_hash { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Gets the address of the author of the current block + public fun get_current_author(): address acquires BlockMetadata { + borrow_global(CoreAddresses::GENESIS_ADDRESS()).author + } + + spec get_current_author { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Call at block prologue + public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option>) acquires BlockMetadata{ + CoreAddresses::assert_genesis_address(account); + + let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH)); + assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH)); + block_metadata_ref.number = number; + block_metadata_ref.author= author; + block_metadata_ref.parent_hash = parent_hash; + block_metadata_ref.uncles = uncles; + block_metadata_ref.parents_hash = parents_hash; + + Event::emit_event( + &mut block_metadata_ref.new_block_events, + NewBlockEvent { + number, + author, + timestamp, + uncles, + parents_hash, + } + ); + } + + spec process_block_metadata { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1; + } + + spec schema AbortsIfBlockMetadataNotExist { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + public fun checkpoints_init(account: &signer){ + CoreAddresses::assert_genesis_address(account); + + let checkpoints = Ring::create_with_capacity(CHECKPOINT_LENGTH); + move_to( + account, + Checkpoints { + checkpoints, + index : 0, + last_number : 0, + }); + } + + spec checkpoints_init { + pragma verify = false; + } + + public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints { + checkpoint(); + } + + spec checkpoint_entry { + pragma verify = false; + } + + public fun checkpoint() acquires BlockMetadata, Checkpoints{ + let parent_block_number = get_current_block_number() - 1; + let parent_block_hash = get_parent_hash(); + + let checkpoints = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + base_checkpoint(checkpoints, parent_block_number, parent_block_hash); + + } + + spec checkpoint { + pragma verify = false; + } + + fun base_checkpoint(checkpoints: &mut Checkpoints, parent_block_number: u64, parent_block_hash:vector){ + assert!(checkpoints.last_number + BLOCK_INTERVAL_NUMBER <= parent_block_number || checkpoints.last_number == 0, Errors::invalid_argument(ERROR_INTERVAL_TOO_LITTLE)); + + checkpoints.index = checkpoints.index + 1; + checkpoints.last_number = parent_block_number; + let op_checkpoint = Ring::push(&mut checkpoints.checkpoints, Checkpoint { + block_number: parent_block_number, + block_hash: parent_block_hash, + state_root: Option::none>(), + } ); + if(Option::is_some(&op_checkpoint)){ + Option::destroy_some(op_checkpoint); + }else{ + Option::destroy_none(op_checkpoint); + } + } + + spec base_checkpoint { + pragma verify = false; + } + + public fun latest_state_root():(u64,vector) acquires Checkpoints{ + let checkpoints = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + base_latest_state_root(checkpoints) + } + + spec latest_state_root { + pragma verify = false; + } + + fun base_latest_state_root(checkpoints: &Checkpoints):(u64,vector){ + let len = Ring::capacity(&checkpoints.checkpoints); + let j = if(checkpoints.index < len - 1){ + checkpoints.index + }else{ + len + }; + let i = checkpoints.index; + while( j > 0){ + let op_checkpoint = Ring::borrow(&checkpoints.checkpoints, i - 1 ); + if( Option::is_some(op_checkpoint) && Option::is_some(&Option::borrow(op_checkpoint).state_root) ) { + let state_root = Option::borrow(&Option::borrow(op_checkpoint).state_root); + return (Option::borrow(op_checkpoint).block_number, *state_root) + }; + j = j - 1; + i = i - 1; + }; + + abort Errors::invalid_state(ERROR_NO_HAVE_CHECKPOINT) + } + + spec base_latest_state_root { + pragma verify = false; + } + + public entry fun update_state_root_entry(_account: signer , header: vector) + acquires Checkpoints { + update_state_root(header); + } + + spec update_state_root_entry { + pragma verify = false; + } + + public fun update_state_root(header: vector) acquires Checkpoints { + let checkpoints = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + base_update_state_root(checkpoints, header); + } + + spec update_state_root { + pragma verify = false; + } + + fun base_update_state_root(checkpoints: &mut Checkpoints, header: vector){ + let prefix = Hash::sha3_256(b"STARCOIN::BlockHeader"); + + //parent_hash + let new_offset = BCS::skip_bytes(&header,0); + //timestamp + let new_offset = BCS::skip_u64(&header,new_offset); + //number + let (number,new_offset) = BCS::deserialize_u64(&header,new_offset); + //author + new_offset = BCS::skip_address(&header,new_offset); + //author_auth_key + new_offset = BCS::skip_option_bytes(&header,new_offset); + //txn_accumulator_root + new_offset = BCS::skip_bytes(&header,new_offset); + //block_accumulator_root + new_offset = BCS::skip_bytes(&header,new_offset); + //state_root + let (state_root,_new_offset) = BCS::deserialize_bytes(&header,new_offset); + + Vector::append(&mut prefix,header); + let block_hash = Hash::sha3_256(prefix); + + let len = Ring::capacity(&checkpoints.checkpoints); + let j = if(checkpoints.index < len - 1){ + checkpoints.index + }else{ + len + }; + let i = checkpoints.index; + while( j > 0){ + let op_checkpoint = Ring::borrow_mut(&mut checkpoints.checkpoints, i - 1); + + if( Option::is_some(op_checkpoint) && &Option::borrow(op_checkpoint).block_hash == &block_hash && Option::borrow(op_checkpoint).block_number == number) { + + let op_state_root = &mut Option::borrow_mut(op_checkpoint).state_root; + if(Option::is_some(op_state_root)){ + Option::swap(op_state_root, state_root); + }else{ + Option::fill(op_state_root, state_root); + }; + return + }; + j = j - 1; + i = i - 1; + }; + + abort Errors::invalid_state(ERROR_NO_HAVE_CHECKPOINT) + } + + spec base_update_state_root { + pragma verify = false; + } + + #[test] + fun test_header(){ + // Block header Unit test + // Use Main Genesis BlockHeader in Rust + // BlockHeader { + // id: Some(HashValue(0x80848150abee7e9a3bfe9542a019eb0b8b01f124b63b011f9c338fdb935c417d)), + // parent_hash: HashValue(0xb82a2c11f2df62bf87c2933d0281e5fe47ea94d5f0049eec1485b682df29529a), + // timestamp: 1621311100863, + // number: 0, + // author: 0x00000000000000000000000000000001, + // author_auth_key: None, + // txn_accumulator_root: HashValue(0x43609d52fdf8e4a253c62dfe127d33c77e1fb4afdefb306d46ec42e21b9103ae), + // block_accumulator_root: HashValue(0x414343554d554c41544f525f504c414345484f4c4445525f4841534800000000), + // state_root: HashValue(0x61125a3ab755b993d72accfea741f8537104db8e022098154f3a66d5c23e828d), + // gas_used: 0, + // difficulty: 11660343, + // body_hash: HashValue(0x7564db97ee270a6c1f2f73fbf517dc0777a6119b7460b7eae2890d1ce504537b), + // chain_id: ChainId { id: 1 }, + // nonce: 0, + // extra: BlockHeaderExtra([0, 0, 0, 0]) + // } + // Blockheader BCS : 20b82a2c11f2df62bf87c2933d0281e5fe47ea94d5f0049eec1485b682df29529abf17ac7d79010000000000000000000000000000000000000000000000000001002043609d52fdf8e4a253c62dfe127d33c77e1fb4afdefb306d46ec42e21b9103ae20414343554d554c41544f525f504c414345484f4c4445525f48415348000000002061125a3ab755b993d72accfea741f8537104db8e022098154f3a66d5c23e828d00000000000000000000000000000000000000000000000000000000000000000000000000b1ec37207564db97ee270a6c1f2f73fbf517dc0777a6119b7460b7eae2890d1ce504537b010000000000000000 + + let prefix = Hash::sha3_256(b"STARCOIN::BlockHeader"); + let header = x"20b82a2c11f2df62bf87c2933d0281e5fe47ea94d5f0049eec1485b682df29529abf17ac7d79010000000000000000000000000000000000000000000000000001002043609d52fdf8e4a253c62dfe127d33c77e1fb4afdefb306d46ec42e21b9103ae20414343554d554c41544f525f504c414345484f4c4445525f48415348000000002061125a3ab755b993d72accfea741f8537104db8e022098154f3a66d5c23e828d00000000000000000000000000000000000000000000000000000000000000000000000000b1ec37207564db97ee270a6c1f2f73fbf517dc0777a6119b7460b7eae2890d1ce504537b010000000000000000"; + let (_parent_hash,new_offset) = BCS::deserialize_bytes(&header,0); + let (_timestamp,new_offset) = BCS::deserialize_u64(&header,new_offset); + let (number,new_offset) = BCS::deserialize_u64(&header,new_offset); + let (_author,new_offset) = BCS::deserialize_address(&header,new_offset); + let (_author_auth_key,new_offset) = BCS::deserialize_option_bytes(&header,new_offset); + let (_txn_accumulator_root,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (_block_accumulator_root,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (state_root,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (_gas_used,new_offset) = BCS::deserialize_u64(&header,new_offset); + let (_difficultyfirst,new_offset) = BCS::deserialize_u128(&header,new_offset); + let (_difficultylast,new_offset) = BCS::deserialize_u128(&header,new_offset); + let (_body_hash,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (_chain_id,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_nonce,new_offset) = BCS::deserialize_u32(&header,new_offset); + let (_extra1,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_extra2,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_extra3,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_extra4,_new_offset) = BCS::deserialize_u8(&header,new_offset); + + Vector::append(&mut prefix,header); + let block_hash = Hash::sha3_256(prefix); + assert!(block_hash == x"80848150abee7e9a3bfe9542a019eb0b8b01f124b63b011f9c338fdb935c417d" ,1001); + assert!(number == 0,1002); + assert!(state_root == x"61125a3ab755b993d72accfea741f8537104db8e022098154f3a66d5c23e828d",1003); + } + + #[test] + fun test_header2(){ + // Block header Unit test + // Use BlockHeader in integration test + //"number":"2", + //"block_hash":"0x9433bb7b56333dfc33e012f3b22b67277a3026448eb5043747d59284f648343d" + //"parent_hash":"0x9be97e678afa8a0a4cf9ca612be6f64810a6f7d5f8b4b4ddf5e4971ef4b5eb48" + //"state_root":"0xd2df4c8c579f9e05b0adf14b53785379fb245465d703834eb19fba74d9114a9a" + //"header":"0x209be97e678afa8a0a4cf9ca612be6f64810a6f7d5f8b4b4ddf5e4971ef4b5eb4820aa26050000000002000000000000000000000000000000000000000000000200205c79e9493845327132ab3011c7c6c9d8bddcfde5553abb90cf5ef7fdfb39a4aa20c4d8e6cdb52520794dad5241f51a4eed46a5e5264dd148032cc3bdb8e3bdbe7a20d2df4c8c579f9e05b0adf14b53785379fb245465d703834eb19fba74d9114a9a0000000000000000000000000000000000000000000000000000000000000000000000000000000020c01e0329de6d899348a8ef4bd51db56175b3fa0988e57c3dcec8eaf13a164d97fe0000000000000000" + + let prefix = Hash::sha3_256(b"STARCOIN::BlockHeader"); + let header = x"209be97e678afa8a0a4cf9ca612be6f64810a6f7d5f8b4b4ddf5e4971ef4b5eb4820aa26050000000002000000000000000000000000000000000000000000000200205c79e9493845327132ab3011c7c6c9d8bddcfde5553abb90cf5ef7fdfb39a4aa20c4d8e6cdb52520794dad5241f51a4eed46a5e5264dd148032cc3bdb8e3bdbe7a20d2df4c8c579f9e05b0adf14b53785379fb245465d703834eb19fba74d9114a9a0000000000000000000000000000000000000000000000000000000000000000000000000000000020c01e0329de6d899348a8ef4bd51db56175b3fa0988e57c3dcec8eaf13a164d97fe0000000000000000"; + let (_parent_hash,new_offset) = BCS::deserialize_bytes(&header,0); + let (_timestamp,new_offset) = BCS::deserialize_u64(&header,new_offset); + let (number,new_offset) = BCS::deserialize_u64(&header,new_offset); + let (_author,new_offset) = BCS::deserialize_address(&header,new_offset); + let (_author_auth_key,new_offset) = BCS::deserialize_option_bytes(&header,new_offset); + let (_txn_accumulator_root,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (_block_accumulator_root,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (state_root,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (_gas_used,new_offset) = BCS::deserialize_u64(&header,new_offset); + let (_difficultyfirst,new_offset) = BCS::deserialize_u128(&header,new_offset); + let (_difficultylast,new_offset) = BCS::deserialize_u128(&header,new_offset); + let (_body_hash,new_offset) = BCS::deserialize_bytes(&header,new_offset); + let (_chain_id,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_nonce,new_offset) = BCS::deserialize_u32(&header,new_offset); + let (_extra1,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_extra2,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_extra3,new_offset) = BCS::deserialize_u8(&header,new_offset); + let (_extra4,_new_offset) = BCS::deserialize_u8(&header,new_offset); + + Vector::append(&mut prefix,header); + let block_hash = Hash::sha3_256(prefix); + assert!(block_hash == x"9433bb7b56333dfc33e012f3b22b67277a3026448eb5043747d59284f648343d" ,1001); + assert!(number == 2,1002); + assert!(state_root == x"d2df4c8c579f9e05b0adf14b53785379fb245465d703834eb19fba74d9114a9a",1003); + } + + #[test] + fun test_checkpoint(){ + let checkpoints = Checkpoints { + checkpoints : Ring::create_with_capacity(3), + index : 0, + last_number : 0 + }; + + base_checkpoint(&mut checkpoints, 0, x"80848150abee7e9a3bfe9542a019eb0b8b01f124b63b011f9c338fdb935c417d"); + + let Checkpoints{ + checkpoints: ring, + index : index, + last_number: last_number + } = checkpoints; + assert!( index == 1 && last_number == 0 , 10020); + Ring::destroy(ring); + } + + #[test] + fun test_latest_state_root(){ + let header = x"20b82a2c11f2df62bf87c2933d0281e5fe47ea94d5f0049eec1485b682df29529abf17ac7d79010000000000000000000000000000000000000000000000000001002043609d52fdf8e4a253c62dfe127d33c77e1fb4afdefb306d46ec42e21b9103ae20414343554d554c41544f525f504c414345484f4c4445525f48415348000000002061125a3ab755b993d72accfea741f8537104db8e022098154f3a66d5c23e828d00000000000000000000000000000000000000000000000000000000000000000000000000b1ec37207564db97ee270a6c1f2f73fbf517dc0777a6119b7460b7eae2890d1ce504537b010000000000000000"; + + let checkpoints = Checkpoints { + checkpoints : Ring::create_with_capacity(3), + index : 0, + last_number : 0 + }; + + base_checkpoint(&mut checkpoints, 0, x"80848150abee7e9a3bfe9542a019eb0b8b01f124b63b011f9c338fdb935c417d"); + + base_update_state_root(&mut checkpoints, copy header); + + let (number , state_root ) = base_latest_state_root(&checkpoints); + let Checkpoints{ + checkpoints: ring, + index : index, + last_number: last_number + } = checkpoints; + assert!( index == 1 && last_number == 0 , 10020); + assert!( number == 0 && state_root == x"61125a3ab755b993d72accfea741f8537104db8e022098154f3a66d5c23e828d" , 10020); + Ring::destroy(ring); + } + +} +} \ No newline at end of file diff --git a/release/v13/sources/BlockReward.move b/release/v13/sources/BlockReward.move new file mode 100644 index 00000000..c5bd5078 --- /dev/null +++ b/release/v13/sources/BlockReward.move @@ -0,0 +1,192 @@ +address StarcoinFramework { +/// The module provide block rewarding calculation logic. +module BlockReward { + use StarcoinFramework::Timestamp; + use StarcoinFramework::Token; + use StarcoinFramework::STC::{STC}; + use StarcoinFramework::Vector; + use StarcoinFramework::Account; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::RewardConfig; + use StarcoinFramework::Config; + use StarcoinFramework::Event; + use StarcoinFramework::Treasury; + use StarcoinFramework::TreasuryWithdrawDaoProposal; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + + /// Queue of rewards distributed to miners. + struct RewardQueue has key { + /// How many block rewards has been handled. + reward_number: u64, + /// informations about the reward distribution. + infos: vector, + /// event handle used to emit block reward event. + reward_events: Event::EventHandle, + } + + /// Reward info of miners. + struct RewardInfo has store { + /// number of the block miner minted. + number: u64, + /// how many stc rewards. + reward: u128, + /// miner who mint the block. + miner: address, + /// store the gas fee that users consumed. + gas_fees: Token::Token, + } + + /// block reward event + struct BlockRewardEvent has drop, store { + /// block number + block_number: u64, + /// STC reward. + block_reward: u128, + /// gas fees in STC. + gas_fees: u128, + /// block miner + miner: address, + } + + const EAUTHOR_AUTH_KEY_IS_EMPTY: u64 = 101; + const ECURRENT_NUMBER_IS_WRONG: u64 = 102; + const EREWARD_NUMBER_IS_WRONG: u64 = 103; + const EMINER_EXIST: u64 = 104; + const EAUTHOR_ADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 105; + + /// Initialize the module, should be called in genesis. + public fun initialize(account: &signer, reward_delay: u64) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + + RewardConfig::initialize(account, reward_delay); + move_to(account, RewardQueue { + reward_number: 0, + infos: Vector::empty(), + reward_events: Event::new_event_handle(account), + }); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + include Config::PublishNewConfigAbortsIf; + include Config::PublishNewConfigEnsures; + aborts_if exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Process the given block rewards. + public fun process_block_reward(account: &signer, current_number: u64, current_reward: u128, + current_author: address, _auth_key_vec: vector, + previous_block_gas_fees: Token::Token) acquires RewardQueue { + CoreAddresses::assert_genesis_address(account); + if (current_number == 0) { + Token::destroy_zero(previous_block_gas_fees); + return + }; + + let rewards = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + let len = Vector::length(&rewards.infos); + assert!((current_number == (rewards.reward_number + len + 1)), Errors::invalid_argument(ECURRENT_NUMBER_IS_WRONG)); + + // distribute gas fee to last block reward info. + // if not last block reward info, the passed in gas fee must be zero. + if (len == 0) { + Token::destroy_zero(previous_block_gas_fees); + } else { + let reward_info = Vector::borrow_mut(&mut rewards.infos, len - 1); + assert!(current_number == reward_info.number + 1, Errors::invalid_argument(ECURRENT_NUMBER_IS_WRONG)); + Token::deposit(&mut reward_info.gas_fees, previous_block_gas_fees); + }; + + let reward_delay = RewardConfig::reward_delay(); + if (len >= reward_delay) {//pay and remove + let i = len; + while (i > 0 && i >= reward_delay) { + let RewardInfo { number: reward_block_number, reward: block_reward, gas_fees, miner } = Vector::remove(&mut rewards.infos, 0); + + let gas_fee_value = Token::value(&gas_fees); + let total_reward = gas_fees; + // add block reward to total. + if (block_reward > 0) { + // if no STC in Treasury, BlockReward will been 0. + let treasury_balance = Treasury::balance(); + if (treasury_balance < block_reward) { + block_reward = treasury_balance; + }; + if (block_reward > 0) { + let reward = TreasuryWithdrawDaoProposal::withdraw_for_block_reward(account, block_reward); + Token::deposit(&mut total_reward, reward); + }; + }; + // distribute total. + if (Token::value(&total_reward) > 0) { + Account::deposit(miner, total_reward); + } else { + Token::destroy_zero(total_reward); + }; + // emit reward event. + Event::emit_event( + &mut rewards.reward_events, + BlockRewardEvent { + block_number: reward_block_number, + block_reward: block_reward, + gas_fees: gas_fee_value, + miner, + } + ); + + rewards.reward_number = rewards.reward_number + 1; + i = i - 1; + } + }; + + if (!Account::exists_at(current_author)) { + Account::create_account_with_address(current_author); + }; + let current_info = RewardInfo { + number: current_number, + reward: current_reward, + miner: current_author, + gas_fees: Token::zero(), + }; + Vector::push_back(&mut rewards.infos, current_info); + + } + + spec process_block_reward { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + // abort if current block is genesis, and previous block gas fees != 0 + aborts_if current_number == 0 && Token::value(previous_block_gas_fees) != 0; + + aborts_if current_number > 0 && !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if current_number > 0 && (global(CoreAddresses::GENESIS_ADDRESS()).reward_number + Vector::length(global(CoreAddresses::GENESIS_ADDRESS()).infos) + 1) != current_number; + aborts_if current_number > 0 && !exists>(CoreAddresses::GENESIS_ADDRESS()); + + + let reward_info_length = Vector::length(global(CoreAddresses::GENESIS_ADDRESS()).infos); + + // abort if no previous block but has gas fees != 0. + aborts_if current_number > 0 && reward_info_length == 0 && Token::value(previous_block_gas_fees) != 0; + // abort if previous block number != current_block_number - 1. + aborts_if current_number > 0 && reward_info_length != 0 && Vector::borrow(global(CoreAddresses::GENESIS_ADDRESS()).infos, reward_info_length - 1).number != current_number - 1; + + aborts_if current_number > 0 && Vector::length(global(CoreAddresses::GENESIS_ADDRESS()).infos) >= global>(CoreAddresses::GENESIS_ADDRESS()).payload.reward_delay + && (global(CoreAddresses::GENESIS_ADDRESS()).reward_number + 1) != Vector::borrow(global(CoreAddresses::GENESIS_ADDRESS()).infos, 0).number; + + aborts_if current_number > 0 && Vector::length(global(CoreAddresses::GENESIS_ADDRESS()).infos) >= global>(CoreAddresses::GENESIS_ADDRESS()).payload.reward_delay + && (global(CoreAddresses::GENESIS_ADDRESS()).reward_number + 1) > max_u64(); + + aborts_if current_number > 0 && !Account::exists_at(current_author) ; + + pragma verify = false; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/ChainId.move b/release/v13/sources/ChainId.move new file mode 100644 index 00000000..927777a8 --- /dev/null +++ b/release/v13/sources/ChainId.move @@ -0,0 +1,94 @@ +address StarcoinFramework { +/// The module provides chain id information. +module ChainId { + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// chain id data structure. + struct ChainId has key { + /// real id. + id: u8 + } + + const MAIN_CHAIN_ID: u8 = 1; + const BARNARD_CHAIN_ID: u8 = 251; + const PROXIMA_CHAIN_ID: u8 = 252; + const HALLEY_CHAIN_ID: u8 = 253; + const DEV_CHAIN_ID: u8 = 254; + const TEST_CHAIN_ID: u8 = 255; + + /// Publish the chain ID under the genesis account + public fun initialize(account: &signer, id: u8) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + move_to(account, ChainId { id }); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists(Signer::address_of(account)); + ensures exists(Signer::address_of(account)); + } + + /// Return the chain ID of this chain + public fun get(): u8 acquires ChainId { + borrow_global(CoreAddresses::GENESIS_ADDRESS()).id + } + + public fun is_dev(): bool acquires ChainId { + get() == DEV_CHAIN_ID + } + public fun is_test(): bool acquires ChainId { + get() == TEST_CHAIN_ID + } + public fun is_halley(): bool acquires ChainId { + get() == HALLEY_CHAIN_ID + } + public fun is_proxima(): bool acquires ChainId { + get() == PROXIMA_CHAIN_ID + } + public fun is_barnard(): bool acquires ChainId { + get() == BARNARD_CHAIN_ID + } + public fun is_main(): bool acquires ChainId { + get() == MAIN_CHAIN_ID + } + + spec is_dev { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } + spec is_test { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } + spec is_halley { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } + spec is_proxima { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } + spec is_barnard { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } + spec is_main { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } + + spec get { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures exists(CoreAddresses::GENESIS_ADDRESS()); + } +} +} diff --git a/release/v13/sources/Collection.move b/release/v13/sources/Collection.move new file mode 100644 index 00000000..d2ffcbd0 --- /dev/null +++ b/release/v13/sources/Collection.move @@ -0,0 +1,118 @@ +address StarcoinFramework { +/// Deprecated since @v3 please use Collection2 +/// Provide a account based vector for save resource. +module Collection { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + use StarcoinFramework::Option::{Self, Option}; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = false; + } + + /// Collection in memory, can not drop & store. + struct Collection{ + items:vector, + /// the owner of Collection. + owner: address, + } + + /// Collection in global store. + struct CollectionStore has key { + /// items in the CollectionStore. + /// use Option at here is for temporary take away from store to construct Collection. + items: Option>, + } + + const EDEPRECATED_FUNCTION: u64 = 19; + + const ECOLLECTION_NOT_EXIST: u64 = 101; + /// The operator require the collection owner. + const ECOLLECTION_NOT_OWNER: u64 = 102; + + /// Acquire an immutable reference to the `i`th element of the collection `c`. + /// Aborts if `i` is out of bounds. + public fun borrow(c: &Collection, i: u64): &T{ + Vector::borrow(&c.items, i) + } + + /// Pop an element from the end of vector `v`. + /// Aborts if `v` is empty. + public fun pop_back(account: &signer, c: &mut Collection): T { + assert!(Signer::address_of(account) == c.owner, Errors::requires_address(ECOLLECTION_NOT_OWNER)); + Vector::pop_back(&mut c.items) + } + + /// check the Collection exists in `addr` + fun exists_at(addr: address): bool{ + exists>(addr) + } + + spec exists_at {aborts_if false;} + + /// Deprecated since @v3 + /// Put items to account's Collection last position. + public fun put(_account: &signer, _item: T) { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + spec put {aborts_if false;} + + /// Take last item from account's Collection of T. + public fun take(account: &signer): T acquires CollectionStore{ + let addr = Signer::address_of(account); + let c = borrow_collection(addr); + let item = pop_back(account, &mut c); + return_collection(c); + item + } + + spec take { + aborts_if false; + } + + /// Borrow collection of T from `addr` + public fun borrow_collection(addr: address): Collection acquires CollectionStore{ + assert!(exists_at(addr), Errors::invalid_state(ECOLLECTION_NOT_EXIST)); + let c = borrow_global_mut>(addr); + let items = Option::extract(&mut c.items); + Collection{ + items, + owner: addr + } + } + + spec borrow_collection { + aborts_if false; + } + + /// Return the Collection of T + public fun return_collection(c: Collection) acquires CollectionStore{ + let Collection{ items, owner } = c; + if (Vector::is_empty(&items)) { + let c = move_from>(owner); + destroy_empty(c); + Vector::destroy_empty(items); + }else{ + let c = borrow_global_mut>(owner); + Option::fill(&mut c.items, items); + } + } + + spec return_collection { + aborts_if false; + } + + fun destroy_empty(c: CollectionStore){ + let CollectionStore{ items } = c; + Option::destroy_none(items); + } + + spec destroy_empty { + aborts_if false; + } + +} +} \ No newline at end of file diff --git a/release/v13/sources/Collection2.move b/release/v13/sources/Collection2.move new file mode 100644 index 00000000..db5f44e3 --- /dev/null +++ b/release/v13/sources/Collection2.move @@ -0,0 +1,235 @@ +address StarcoinFramework { +/// Provide a account based vector for save resource item. +/// The resource in CollectionStore can borrowed by anyone, anyone can get immutable ref of item. +/// and the owner of Collection can allow others to add item to Collection or get mut ref from Collection.git +module Collection2 { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + use StarcoinFramework::Option::{Self, Option}; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = false; + } + + /// Collection in memory, can not drop & store. + struct Collection{ + items: vector, + owner: address, + can_put: bool, + can_mut: bool, + can_take: bool, + } + + /// Collection in global store. + struct CollectionStore has key { + /// items in the CollectionStore. + /// use Option at here is for temporary take away from store to construct Collection. + items: Option>, + anyone_can_put: bool, + anyone_can_mut: bool, + } + + const ERR_COLLECTION_NOT_EXIST: u64 = 101; + /// The operator require the collection owner or collection set anyone_can_put to true. + const ERR_COLLECTION_CAN_NOT_ADD: u64 = 102; + /// The operator require the collection owner or collection set anyone_can_mut to true. + const ERR_COLLECTION_CAN_NOT_MUT: u64 = 103; + /// The operator require the collection owner + const ERR_COLLECTION_CAN_NOT_TAKE: u64 = 104; + const ERR_COLLECTION_INVALID_BORROW_STATE: u64 = 105; + const ERR_COLLECTION_IS_NOT_EMPTY: u64 = 106; + + /// Return the length of the collection. + public fun length(c: &Collection): u64{ + Vector::length(&c.items) + } + + spec length {aborts_if false;} + + /// Acquire an immutable reference to the `i`th element of the collection `c`. + /// Aborts if `i` is out of bounds. + public fun borrow(c: &Collection, i: u64): &T{ + Vector::borrow(&c.items, i) + } + + /// Add item `v` to the end of the collection `c`. + /// require owner of Collection. + public fun push_back(c: &mut Collection, t: T){ + assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD)); + Vector::push_back(&mut c.items, t); + } + + /// Return a mutable reference to the `i`th item in the Collection `c`. + /// Aborts if `i` is out of bounds. + public fun borrow_mut(c: &mut Collection, i: u64): &mut T{ + assert!(c.can_mut, Errors::requires_address(ERR_COLLECTION_CAN_NOT_MUT)); + Vector::borrow_mut(&mut c.items, i) + } + + /// Pop an element from the end of vector `v`. + /// Aborts if `v` is empty. + public fun pop_back(c: &mut Collection): T { + assert!(c.can_take, Errors::requires_address(ERR_COLLECTION_CAN_NOT_TAKE)); + Vector::pop_back(&mut c.items) + } + + public fun remove(c: &mut Collection, i: u64): T{ + assert!(c.can_take, Errors::requires_address(ERR_COLLECTION_CAN_NOT_TAKE)); + Vector::remove(&mut c.items, i) + } + + public fun append(c: &mut Collection, other: T) { + assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD)); + Vector::append(&mut c.items, Vector::singleton(other)) + } + + public fun append_all(c: &mut Collection, other: vector) { + assert!(c.can_put, Errors::requires_address(ERR_COLLECTION_CAN_NOT_ADD)); + Vector::append(&mut c.items, other) + } + + /// check the Collection exists in `addr` + public fun exists_at(addr: address): bool{ + exists>(addr) + } + + spec exists_at {aborts_if false;} + + /// check `addr` is accept T and other can send T to `addr`, + /// it means exists a Collection of T at `addr` and anyone_can_put of the Collection is true + public fun is_accept(addr: address): bool acquires CollectionStore { + if (!exists>(addr)){ + return false + }; + let cs = borrow_global>(addr); + cs.anyone_can_put + } + + /// signer allow other send T to self + /// create a Collection of T and set anyone_can_put to true + /// if the Collection exists, just update anyone_can_put to true + public fun accept(signer: &signer) acquires CollectionStore { + let addr = Signer::address_of(signer); + if (!exists>(addr)){ + Self::create_collection(signer, true, false); + }; + let cs = borrow_global_mut>(addr); + if (!cs.anyone_can_put) { + cs.anyone_can_put = true; + } + } + + /// Put items to `to_addr`'s Collection of T + /// put = borrow_collection + append + return_collection. + public fun put(signer: &signer, owner: address, item: T) acquires CollectionStore{ + let c = Self::borrow_collection(signer, owner); + Self::append(&mut c, item); + Self::return_collection(c); + } + + spec put {aborts_if false;} + + /// Put all items to owner's collection of T. + public fun put_all(signer: &signer, owner: address, items: vector) acquires CollectionStore{ + let c = Self::borrow_collection(signer, owner); + Self::append_all(&mut c, items); + Self::return_collection(c); + } + + spec put_all {aborts_if false;} + + /// Take last item from signer's Collection of T. + public fun take(signer: &signer): T acquires CollectionStore{ + let addr = Signer::address_of(signer); + let c = borrow_collection(signer, addr); + let item = pop_back(&mut c); + return_collection(c); + item + } + + spec take { + aborts_if false; + } + + public fun create_collection(signer: &signer, anyone_can_put: bool, anyone_can_mut: bool) { + move_to(signer, CollectionStore{items: Option::some(Vector::empty()), anyone_can_put, anyone_can_mut}) + } + + /// Return the length of Collection from `owner`, if collection do not exist, return 0. + public fun length_of(owner: address) : u64 acquires CollectionStore{ + if (exists_at(owner)){ + let cs = borrow_global_mut>(owner); + //if items is None, indicate it is borrowed + assert!(!Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE)); + let items = Option::borrow(&cs.items); + Vector::length(items) + }else{ + 0 + } + } + + /// Borrow collection of T from `owner`, auto detected the collection's can_put|can_mut|can_take by the `sender` and Collection config. + public fun borrow_collection(sender: &signer, owner: address): Collection acquires CollectionStore{ + assert!(exists_at(owner), Errors::invalid_state(ERR_COLLECTION_NOT_EXIST)); + let cs = borrow_global_mut>(owner); + //if items is None, indicate it is borrowed + assert!(!Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE)); + let items = Option::extract(&mut cs.items); + let is_owner = owner == Signer::address_of(sender); + let can_put = cs.anyone_can_put || is_owner; + let can_mut = cs.anyone_can_mut || is_owner; + let can_take = is_owner; + Collection{ + items, + owner, + can_put, + can_mut, + can_take, + } + } + + spec borrow_collection { + aborts_if false; + } + + /// Return the Collection of T + public fun return_collection(c: Collection) acquires CollectionStore{ + let Collection{ items, owner, can_put:_, can_mut:_, can_take:_ } = c; + let cs = borrow_global_mut>(owner); + assert!(Option::is_none(&cs.items), Errors::invalid_state(ERR_COLLECTION_INVALID_BORROW_STATE)); + Option::fill(&mut cs.items, items); + } + + spec return_collection { + aborts_if false; + } + + public fun destroy_collection(signer: &signer) acquires CollectionStore{ + let c = move_from>(Signer::address_of(signer)); + destroy_empty(c); + } + + spec destroy_collection { + aborts_if false; + } + + fun destroy_empty(c: CollectionStore){ + let CollectionStore{ items, anyone_can_put:_, anyone_can_mut:_,} = c; + if (Option::is_some(&items)) { + let item_vec = Option::extract(&mut items); + assert!(Vector::is_empty(&item_vec), Errors::invalid_state(ERR_COLLECTION_IS_NOT_EMPTY)); + Vector::destroy_empty(item_vec); + Option::destroy_none(items); + }else{ + Option::destroy_none(items); + } + } + + spec destroy_empty { + aborts_if false; + } + +} +} \ No newline at end of file diff --git a/release/v13/sources/Compare.move b/release/v13/sources/Compare.move new file mode 100644 index 00000000..41110b9b --- /dev/null +++ b/release/v13/sources/Compare.move @@ -0,0 +1,126 @@ +address StarcoinFramework { +module Compare { + use StarcoinFramework::Vector; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + const EQUAL: u8 = 0; + const LESS_THAN: u8 = 1; + const GREATER_THAN: u8 = 2; + + /// Compare `v1` and `v2` using + /// (1) byte-by-byte comparison from right to left until we reach the end of the shorter vector, + /// then + /// (2) vector length to break ties. + /// Returns either `EQUAL` (0u8), `LESS_THAN` (1u8), or `GREATER_THAN` (2u8). + /// This function is designed to compare BCS (Starcoin Canonical Serialization)-encoded values + /// (i.e., vectors produced by `BCS::to_bytes`). A typical client will call + /// `Compare::cmp_bcs_bytes(BCS::to_bytes(&t1), BCS::to_bytes(&t2))`. The comparison provides the + /// following guarantees w.r.t the original values t1 and t2: + /// - `cmp_bcs_bytes(bcs_ext(t1), bcs_ext(t2)) == LESS_THAN` iff `cmp_bcs_bytes(t2, t1) == GREATER_THAN` + /// - `Compare::cmp(t1, t2) == EQUAL` iff `t1 == t2` and (similarly) + /// `Compare::cmp(t1, t2) != EQUAL` iff `t1 != t2`, where `==` and `!=` denote the Move + /// bytecode operations for polymorphic equality. + /// - for all primitive types `T` with `<` and `>` comparison operators exposed in Move bytecode + /// (`u8`, `u64`, `u128`), we have + /// `compare_bcs_bytes(bcs_ext(t1), bcs_ext(t2)) == LESS_THAN` iff `t1 < t2` and (similarly) + /// `compare_bcs_bytes(bcs_ext(t1), bcs_ext(t2)) == LESS_THAN` iff `t1 > t2`. + /// For all other types, the order is whatever the BCS encoding of the type and the comparison + /// strategy above gives you. One case where the order might be surprising is the `address` type. + /// CoreAddresses are 16 byte hex values that BCS encodes with the identity function. The right to + /// left, byte-by-byte comparison means that (for example) + /// `compare_bcs_bytes(bcs_ext(0x01), bcs_ext(0x10)) == LESS_THAN` (as you'd expect), but + /// `compare_bcs_bytes(bcs_ext(0x100), bcs_ext(0x001)) == LESS_THAN` (as you probably wouldn't expect). + /// Keep this in mind when using this function to compare addresses. + public fun cmp_bcs_bytes(v1: &vector, v2: &vector): u8 { + let i1 = Vector::length(v1); + let i2 = Vector::length(v2); + let len_cmp = cmp_u64(i1, i2); + + // BCS uses little endian encoding for all integer types, so we choose to compare from left + // to right. Going right to left would make the behavior of Compare.cmp diverge from the + // bytecode operators < and > on integer values (which would be confusing). + while (i1 > 0 && i2 > 0) { + i1 = i1 - 1; + i2 = i2 - 1; + let v1 = *Vector::borrow(v1, i1); + let v2 = *Vector::borrow(v2, i2); + let elem_cmp = if (v1 == v2) EQUAL + else if (v1 < v2) LESS_THAN + else GREATER_THAN; + if (elem_cmp != 0) return elem_cmp + // else, compare next element + }; + // all compared elements equal; use length comparison to break the tie + len_cmp + } + + public fun cmp_bytes(v1: &vector, v2: &vector): u8 { + let l1 = Vector::length(v1); + let l2 = Vector::length(v2); + let len_cmp = cmp_u64(l1, l2); + let i = 0; + while (i < l1 && i < l2) { + let v1 = *Vector::borrow(v1, i); + let v2 = *Vector::borrow(v2, i); + let elem_cmp = if (v1 == v2) EQUAL + else if (v1 < v2) LESS_THAN + else GREATER_THAN; + if (elem_cmp != 0) { + return elem_cmp + }; + // else, compare next element + i = i + 1; + }; + // all compared elements equal; use length comparison to break the tie + len_cmp + } + + spec cmp_bytes { + pragma verify = false; + } + + spec cmp_bcs_bytes { + pragma verify = false; + } + + // Compare two `u64`'s + fun cmp_u64(i1: u64, i2: u64): u8 { + if (i1 == i2) EQUAL + else if (i1 < i2) LESS_THAN + else GREATER_THAN + } + + spec cmp_u64 { + aborts_if false; + } + + public fun is_equal(result: u8): bool { + result == EQUAL + } + + spec is_equal { + aborts_if false; + } + + public fun is_less_than(result: u8): bool { + result == LESS_THAN + } + + spec is_less_than { + aborts_if false; + } + + public fun is_greater_than(result: u8): bool { + result == GREATER_THAN + } + + spec is_greater_than { + aborts_if false; + } +} + +} diff --git a/release/v13/sources/Config.move b/release/v13/sources/Config.move new file mode 100644 index 00000000..54e28ab0 --- /dev/null +++ b/release/v13/sources/Config.move @@ -0,0 +1,281 @@ +address StarcoinFramework { +/// The module provides a general implmentation of configuration for onchain contracts. +module Config { + use StarcoinFramework::Event; + use StarcoinFramework::Signer; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::Errors; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// A generic singleton resource that holds a value of a specific type. + struct Config has key { payload: ConfigValue } + + /// Accounts with this privilege can modify config of type ConfigValue under account_address + struct ModifyConfigCapability has store { + account_address: address, + events: Event::EventHandle>, + } + + /// A holder for ModifyConfigCapability, for extraction and restoration of ModifyConfigCapability. + struct ModifyConfigCapabilityHolder has key, store { + cap: Option>, + } + + /// Event emitted when config value is changed. + struct ConfigChangeEvent has drop, store { + account_address: address, + value: ConfigValue, + } + + const ECONFIG_VALUE_DOES_NOT_EXIST: u64 = 13; + const ECAPABILITY_HOLDER_NOT_EXISTS: u64 = 101; + + + + spec fun spec_get(addr: address): ConfigValue { + global>(addr).payload + } + + + /// Get a copy of `ConfigValue` value stored under `addr`. + public fun get_by_address(addr: address): ConfigValue acquires Config { + assert!(exists>(addr), Errors::invalid_state(ECONFIG_VALUE_DOES_NOT_EXIST)); + *&borrow_global>(addr).payload + } + + spec get_by_address { + aborts_if !exists>(addr); + ensures exists>(addr); + ensures result == spec_get(addr); + } + + /// Check whether the config of `ConfigValue` type exists under `addr`. + public fun config_exist_by_address(addr: address): bool { + exists>(addr) + } + + spec config_exist_by_address { + aborts_if false; + ensures result == exists>(addr); + } + + /// Set a config item to a new value with capability stored under signer + public fun set( + account: &signer, + payload: ConfigValue, + ) acquires Config, ModifyConfigCapabilityHolder { + let signer_address = Signer::address_of(account); + assert!( + exists>(signer_address), + Errors::requires_capability(ECAPABILITY_HOLDER_NOT_EXISTS), + ); + let cap_holder = borrow_global_mut>(signer_address); + assert!(Option::is_some(&cap_holder.cap), Errors::requires_capability(ECAPABILITY_HOLDER_NOT_EXISTS)); + set_with_capability(Option::borrow_mut(&mut cap_holder.cap), payload); + } + + spec set { + let addr = Signer::address_of(account); + let cap_opt = spec_cap(addr); + let cap = Option::borrow(spec_cap(Signer::address_of(account))); + + aborts_if !exists>(addr); + aborts_if Option::is_none>(cap_opt); + ensures exists>(addr); + + // TODO: For unknown reason we can't specify the strict abort conditions. + // Intuitively, the commented out spec should be able to be verified because + // it is exactly the spec of the callee `set_with_capability()`. + //aborts_if !exists>(Option::borrow(spec_cap(Signer::address_of(account))).account_address); + pragma aborts_if_is_partial; + ensures exists>( + Option::borrow(spec_cap(Signer::address_of(account))).account_address, + ); + ensures global>( + Option::borrow(spec_cap(Signer::address_of(account))).account_address, + ).payload == payload; + } + + + spec fun spec_cap(addr: address): Option> { + global>(addr).cap + } + + + /// Set a config item to a new value with cap. + public fun set_with_capability( + cap: &mut ModifyConfigCapability, + payload: ConfigValue, + ) acquires Config { + let addr = cap.account_address; + assert!(exists>(addr), Errors::invalid_state(ECONFIG_VALUE_DOES_NOT_EXIST)); + let config = borrow_global_mut>(addr); + config.payload = copy payload; + emit_config_change_event(cap, payload); + } + + spec set_with_capability { + aborts_if !exists>(cap.account_address); + ensures exists>(cap.account_address); + ensures global>(cap.account_address).payload == payload; + } + + /// Publish a new config item. The caller will use the returned ModifyConfigCapability to specify the access control + /// policy for who can modify the config. + public fun publish_new_config_with_capability( + account: &signer, + payload: ConfigValue, + ): ModifyConfigCapability acquires ModifyConfigCapabilityHolder{ + publish_new_config(account, payload); + extract_modify_config_capability(account) + } + + spec publish_new_config_with_capability { + include PublishNewConfigAbortsIf; + + ensures exists>(Signer::address_of(account)); + ensures global>(Signer::address_of(account)).payload == payload; + + ensures exists>(Signer::address_of(account)); + ensures Option::is_none(global>(Signer::address_of(account)).cap); + } + + /// Publish a new config item under account address. + public fun publish_new_config(account: &signer, payload: ConfigValue) { + move_to(account, Config{ payload }); + let cap = ModifyConfigCapability { + account_address: Signer::address_of(account), + events: Event::new_event_handle>(account), + }; + move_to(account, ModifyConfigCapabilityHolder{cap: Option::some(cap)}); + } + + spec publish_new_config { + include PublishNewConfigAbortsIf; + + ensures exists>(Signer::address_of(account)); + ensures global>(Signer::address_of(account)).payload == payload; + + ensures exists>(Signer::address_of(account)); + ensures Option::is_some(global>(Signer::address_of(account)).cap); + } + + spec schema PublishNewConfigAbortsIf { + account: signer; + aborts_if exists>(Signer::address_of(account)); + aborts_if exists>(Signer::address_of(account)); + } + + spec schema AbortsIfConfigNotExist { + addr: address; + + aborts_if !exists>(addr); + } + + spec schema AbortsIfConfigOrCapabilityNotExist { + addr: address; + + aborts_if !exists>(addr); + aborts_if !exists>(addr); + } + + spec schema PublishNewConfigEnsures { + account: signer; + ensures exists>(Signer::address_of(account)); + ensures exists>(Signer::address_of(account)); + } + + spec schema AbortsIfCapNotExist { + address: address; + aborts_if !exists>(address); + aborts_if Option::is_none>( + global>(address).cap, + ); + } + + /// Extract account's ModifyConfigCapability for ConfigValue type + public fun extract_modify_config_capability( + account: &signer, + ): ModifyConfigCapability acquires ModifyConfigCapabilityHolder { + let signer_address = Signer::address_of(account); + assert!( + exists>(signer_address), + Errors::requires_capability(ECAPABILITY_HOLDER_NOT_EXISTS) + ); + let cap_holder = borrow_global_mut>(signer_address); + Option::extract(&mut cap_holder.cap) + } + + spec extract_modify_config_capability { + let address = Signer::address_of(account); + include AbortsIfCapNotExist; + + ensures exists>(address); + ensures Option::is_none>( + global>(address).cap + ); + ensures result == old(Option::borrow(global>(address).cap)); + } + + /// Restore account's ModifyConfigCapability + public fun restore_modify_config_capability( + cap: ModifyConfigCapability, + ) acquires ModifyConfigCapabilityHolder { + let cap_holder = borrow_global_mut>(cap.account_address); + Option::fill(&mut cap_holder.cap, cap); + } + + spec restore_modify_config_capability { + aborts_if !exists>(cap.account_address); + aborts_if Option::is_some(global>(cap.account_address).cap); + + ensures exists>(cap.account_address); + ensures Option::is_some(global>(cap.account_address).cap); + ensures Option::borrow(global>(cap.account_address).cap) == cap; + } + + /// Destroy the given ModifyConfigCapability + public fun destroy_modify_config_capability( + cap: ModifyConfigCapability, + ) { + let ModifyConfigCapability{account_address:_, events} = cap; + Event::destroy_handle(events) + } + + spec destroy_modify_config_capability { + aborts_if false; + } + + /// Return the address of the given ModifyConfigCapability + public fun account_address(cap: &ModifyConfigCapability): address { + cap.account_address + } + + spec account_address { + aborts_if false; + ensures result == cap.account_address; + } + + /// Emit a config change event. + fun emit_config_change_event( + cap: &mut ModifyConfigCapability, + value: ConfigValue, + ) { + Event::emit_event>( + &mut cap.events, + ConfigChangeEvent { + account_address: cap.account_address, + value, + }, + ); + } + + spec emit_config_change_event { + aborts_if false; + } +} +} diff --git a/release/v13/sources/ConsensusConfig.move b/release/v13/sources/ConsensusConfig.move new file mode 100644 index 00000000..03644354 --- /dev/null +++ b/release/v13/sources/ConsensusConfig.move @@ -0,0 +1,230 @@ +address StarcoinFramework { +/// The module provide configuration of consensus parameters. +module ConsensusConfig { + use StarcoinFramework::Config; + use StarcoinFramework::Signer; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Math; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_strict; + } + + /// consensus configurations. + struct ConsensusConfig has copy, drop, store { + /// Uncle block rate per epoch + uncle_rate_target: u64, + /// Average target time to calculate a block's difficulty + base_block_time_target: u64, + /// Rewards per block + base_reward_per_block: u128, + /// Percentage of `base_reward_per_block` to reward a uncle block + base_reward_per_uncle_percent: u64, + /// Blocks each epoch + epoch_block_count: u64, + /// How many ancestor blocks which use to calculate next block's difficulty + base_block_difficulty_window: u64, + /// Minimum target time to calculate a block's difficulty + min_block_time_target: u64, + /// Maximum target time to calculate a block's difficulty + max_block_time_target: u64, + /// Maximum number of uncle block per block + base_max_uncles_per_block: u64, + /// Maximum gases per block + base_block_gas_limit: u64, + /// Strategy to calculate difficulty + strategy: u8, + } + + const EINVALID_ARGUMENT: u64 = 18; + + /// Initialization of the module. + public fun initialize( + account: &signer, + uncle_rate_target: u64, + epoch_block_count: u64, + base_block_time_target: u64, + base_block_difficulty_window: u64, + base_reward_per_block: u128, + base_reward_per_uncle_percent: u64, + min_block_time_target: u64, + max_block_time_target: u64, + base_max_uncles_per_block: u64, + base_block_gas_limit: u64, + strategy: u8, + ) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + + Config::publish_new_config( + account, + new_consensus_config( + uncle_rate_target, + base_block_time_target, + base_reward_per_block, + base_reward_per_uncle_percent, + epoch_block_count, + base_block_difficulty_window, + min_block_time_target, + max_block_time_target, + base_max_uncles_per_block, + base_block_gas_limit, + strategy, + ), + ); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if uncle_rate_target == 0; + aborts_if epoch_block_count == 0; + aborts_if base_reward_per_block == 0; + aborts_if base_block_time_target == 0; + aborts_if base_block_difficulty_window == 0; + aborts_if min_block_time_target == 0; + aborts_if max_block_time_target < min_block_time_target; + + include Config::PublishNewConfigAbortsIf; + include Config::PublishNewConfigEnsures; + } + + /// Create a new consensus config mainly used in DAO. + public fun new_consensus_config(uncle_rate_target: u64, + base_block_time_target: u64, + base_reward_per_block: u128, + base_reward_per_uncle_percent: u64, + epoch_block_count: u64, + base_block_difficulty_window: u64, + min_block_time_target: u64, + max_block_time_target: u64, + base_max_uncles_per_block: u64, + base_block_gas_limit: u64, + strategy: u8,): ConsensusConfig { + assert!(uncle_rate_target > 0, Errors::invalid_argument(EINVALID_ARGUMENT)); + assert!(base_block_time_target > 0, Errors::invalid_argument(EINVALID_ARGUMENT)); + assert!(base_reward_per_block > 0, Errors::invalid_argument(EINVALID_ARGUMENT)); + assert!(epoch_block_count > 0, Errors::invalid_argument(EINVALID_ARGUMENT)); + assert!(base_block_difficulty_window > 0, Errors::invalid_argument(EINVALID_ARGUMENT)); + // base_reward_per_uncle_percent can been zero. + assert!(min_block_time_target > 0, Errors::invalid_argument(EINVALID_ARGUMENT)); + assert!(max_block_time_target >= min_block_time_target, Errors::invalid_argument(EINVALID_ARGUMENT)); + + ConsensusConfig { + uncle_rate_target, + base_block_time_target, + base_reward_per_block, + epoch_block_count, + base_block_difficulty_window, + base_reward_per_uncle_percent, + min_block_time_target, + max_block_time_target, + base_max_uncles_per_block, + base_block_gas_limit, + strategy, + } + } + + spec new_consensus_config { + aborts_if uncle_rate_target == 0; + aborts_if epoch_block_count == 0; + aborts_if base_reward_per_block == 0; + aborts_if base_block_time_target == 0; + aborts_if base_block_difficulty_window == 0; + aborts_if min_block_time_target == 0; + aborts_if max_block_time_target < min_block_time_target; + } + + /// Get config data. + public fun get_config(): ConsensusConfig { + Config::get_by_address(CoreAddresses::GENESIS_ADDRESS()) + } + + spec get_config { + aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + } + + spec fun spec_get_config(): ConsensusConfig { + global>(CoreAddresses::GENESIS_ADDRESS()).payload + } + + /// Get uncle_rate_target + public fun uncle_rate_target(config: &ConsensusConfig): u64 { + config.uncle_rate_target + } + /// Get base_block_time_target + public fun base_block_time_target(config: &ConsensusConfig): u64 { + config.base_block_time_target + } + + /// Get base_reward_per_block + public fun base_reward_per_block(config: &ConsensusConfig): u128 { + config.base_reward_per_block + } + + /// Get epoch_block_count + public fun epoch_block_count(config: &ConsensusConfig): u64 { + config.epoch_block_count + } + + /// Get base_block_difficulty_window + public fun base_block_difficulty_window(config: &ConsensusConfig): u64 { + config.base_block_difficulty_window + } + + /// Get base_reward_per_uncle_percent + public fun base_reward_per_uncle_percent(config: &ConsensusConfig): u64 { + config.base_reward_per_uncle_percent + } + + /// Get min_block_time_target + public fun min_block_time_target(config: &ConsensusConfig): u64 { + config.min_block_time_target + } + + /// Get max_block_time_target + public fun max_block_time_target(config: &ConsensusConfig): u64 { + config.max_block_time_target + } + + /// Get base_max_uncles_per_block + public fun base_max_uncles_per_block(config: &ConsensusConfig): u64 { + config.base_max_uncles_per_block + } + + /// Get base_block_gas_limit + public fun base_block_gas_limit(config: &ConsensusConfig): u64 { + config.base_block_gas_limit + } + + /// Get strategy + public fun strategy(config: &ConsensusConfig): u8 { + config.strategy + } + + /// Compute block reward given the `new_epoch_block_time_target`. + public fun compute_reward_per_block(new_epoch_block_time_target: u64): u128 { + let config = get_config(); + do_compute_reward_per_block(&config, new_epoch_block_time_target) + } + + spec compute_reward_per_block { + aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + include Math::MulDivAbortsIf{x: spec_get_config().base_reward_per_block, y: new_epoch_block_time_target, z: spec_get_config().base_block_time_target}; + } + + /// Compute block reward given the `new_epoch_block_time_target`, and the consensus config. + public fun do_compute_reward_per_block(config: &ConsensusConfig, new_epoch_block_time_target: u64): u128 { + Math::mul_div(config.base_reward_per_block, (new_epoch_block_time_target as u128), (config.base_block_time_target as u128)) + } + + spec do_compute_reward_per_block { + include Math::MulDivAbortsIf{x: config.base_reward_per_block, y: new_epoch_block_time_target, z: config.base_block_time_target}; + } + + +} +} \ No newline at end of file diff --git a/release/v13/sources/ConsensusStrategy.move b/release/v13/sources/ConsensusStrategy.move new file mode 100644 index 00000000..99cb8b61 --- /dev/null +++ b/release/v13/sources/ConsensusStrategy.move @@ -0,0 +1,49 @@ +address StarcoinFramework { +/// The module provides the information of current consensus strategy. +module ConsensusStrategy { + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::Config; + + /// ConsensusStrategy data. + struct ConsensusStrategy has copy, drop, store { + /// Value of strategy + value: u8 + } + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + + /// Publish the chain ID under the genesis account + public fun initialize(account: &signer, consensus_strategy: u8) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + let cap = Config::publish_new_config_with_capability( + account, + ConsensusStrategy { value:consensus_strategy } + ); + //destroy the cap, so ConsensusStrategy can not been change. + Config::destroy_modify_config_capability(cap); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists>(Signer::address_of(account)); + aborts_if exists>(Signer::address_of(account)); + ensures exists>(Signer::address_of(account)); + } + + /// Return the consensus strategy type of this chain + public fun get(): u8 { + Config::get_by_address(CoreAddresses::GENESIS_ADDRESS()).value + } + + spec get { + aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + } +} +} diff --git a/release/v13/sources/CoreAddresses.move b/release/v13/sources/CoreAddresses.move new file mode 100644 index 00000000..3f234c86 --- /dev/null +++ b/release/v13/sources/CoreAddresses.move @@ -0,0 +1,51 @@ +address StarcoinFramework { +/// The module provide addresses used in stdlib. +module CoreAddresses { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + const ENOT_GENESIS_ACCOUNT: u64 = 11; + + /// The address of the genesis + public fun GENESIS_ADDRESS(): address { + @0x1 + } + + /// Assert signer is genesis. + public fun assert_genesis_address(account: &signer) { + assert!(Signer::address_of(account) == GENESIS_ADDRESS(), + Errors::requires_address(ENOT_GENESIS_ACCOUNT)) + } + spec assert_genesis_address { + pragma opaque; + include AbortsIfNotGenesisAddress; + } + + /// Specifies that a function aborts if the account does not have the Diem root address. + spec schema AbortsIfNotGenesisAddress { + account: signer; + aborts_if Signer::address_of(account) != GENESIS_ADDRESS(); + } + + /// The address of the root association account. This account is + /// created in genesis, and cannot be changed. This address has + /// ultimate authority over the permissions granted (or removed) from + /// accounts on-chain. + public fun ASSOCIATION_ROOT_ADDRESS(): address { + @0xA550C18 + } + + /// The reserved address for transactions inserted by the VM into blocks (e.g. + /// block metadata transactions). Because the transaction is sent from + /// the VM, an account _cannot_ exist at the `0x0` address since there + /// is no signer for the transaction. + public fun VM_RESERVED_ADDRESS(): address { + @0x0 + } +} +} diff --git a/release/v13/sources/Dao.move b/release/v13/sources/Dao.move new file mode 100644 index 00000000..ba82079f --- /dev/null +++ b/release/v13/sources/Dao.move @@ -0,0 +1,1073 @@ +address StarcoinFramework { +module Dao { + use StarcoinFramework::Token; + use StarcoinFramework::Signer; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Option; + use StarcoinFramework::Config; + use StarcoinFramework::Event; + use StarcoinFramework::Errors; + use StarcoinFramework::Treasury; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// Proposal state + const PENDING: u8 = 1; + const ACTIVE: u8 = 2; + const DEFEATED: u8 = 3; + const AGREED: u8 = 4; + const QUEUED: u8 = 5; + const EXECUTABLE: u8 = 6; + const EXTRACTED: u8 = 7; + + /// global DAO info of the specified token type `Token`. + struct DaoGlobalInfo has key { + /// next proposal id. + next_proposal_id: u64, + /// proposal creating event. + proposal_create_event: Event::EventHandle, + /// voting event. + vote_changed_event: Event::EventHandle, + } + + /// Configuration of the `Token`'s DAO. + struct DaoConfig has copy, drop, store { + /// after proposal created, how long use should wait before he can vote (in milliseconds) + voting_delay: u64, + /// how long the voting window is (in milliseconds). + voting_period: u64, + /// the quorum rate to agree on the proposal. + /// if 50% votes needed, then the voting_quorum_rate should be 50. + /// it should between (0, 100]. + voting_quorum_rate: u8, + /// how long the proposal should wait before it can be executed (in milliseconds). + min_action_delay: u64, + } + + spec DaoConfig { + invariant voting_quorum_rate > 0 && voting_quorum_rate <= 100; + invariant voting_delay > 0; + invariant voting_period > 0; + invariant min_action_delay > 0; + } + + /// emitted when proposal created. + struct ProposalCreatedEvent has drop, store { + /// the proposal id. + proposal_id: u64, + /// proposer is the user who create the proposal. + proposer: address, + } + + /// emitted when user vote/revoke_vote. + struct VoteChangedEvent has drop, store { + /// the proposal id. + proposal_id: u64, + /// the voter. + voter: address, + /// creator of the proposal. + proposer: address, + /// agree with the proposal or not + agree: bool, + /// latest vote count of the voter. + vote: u128, + } + + /// Proposal data struct. + struct Proposal has key { + /// id of the proposal + id: u64, + /// creator of the proposal + proposer: address, + /// when voting begins. + start_time: u64, + /// when voting ends. + end_time: u64, + /// count of voters who agree with the proposal + for_votes: u128, + /// count of voters who're against the proposal + against_votes: u128, + /// executable after this time. + eta: u64, + /// after how long, the agreed proposal can be executed. + action_delay: u64, + /// how many votes to reach to make the proposal pass. + quorum_votes: u128, + /// proposal action. + action: Option::Option, + } + + /// User vote info. + struct Vote has key { + /// vote for the proposal under the `proposer`. + proposer: address, + /// proposal id. + id: u64, + /// how many tokens to stake. + stake: Token::Token, + /// vote for or vote against. + agree: bool, + } + + const ERR_NOT_AUTHORIZED: u64 = 1401; + const ERR_ACTION_DELAY_TOO_SMALL: u64 = 1402; + const ERR_PROPOSAL_STATE_INVALID: u64 = 1403; + const ERR_PROPOSAL_ID_MISMATCH: u64 = 1404; + const ERR_PROPOSER_MISMATCH: u64 = 1405; + const ERR_QUORUM_RATE_INVALID: u64 = 1406; + const ERR_CONFIG_PARAM_INVALID: u64 = 1407; + const ERR_VOTE_STATE_MISMATCH: u64 = 1408; + const ERR_ACTION_MUST_EXIST: u64 = 1409; + const ERR_VOTED_OTHERS_ALREADY: u64 = 1410; + + /// plugin function, can only be called by token issuer. + /// Any token who wants to have gov functionality + /// can optin this module by call this `register function`. + public fun plugin( + signer: &signer, + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + ) { + let token_issuer = Token::token_address(); + assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + // let proposal_id = ProposalId {next: 0}; + let gov_info = DaoGlobalInfo { + next_proposal_id: 0, + proposal_create_event: Event::new_event_handle(signer), + vote_changed_event: Event::new_event_handle(signer), + }; + move_to(signer, gov_info); + let config = new_dao_config( + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + ); + Config::publish_new_config(signer, config); + } + + spec plugin { + let sender = Signer::address_of(signer); + aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS(); + + include NewDaoConfigParamSchema; + + include Config::PublishNewConfigAbortsIf>{account: signer}; + + aborts_if exists>(sender); + } + + spec schema RequirePluginDao { + let token_addr = Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if !exists>(token_addr); + aborts_if !exists>>(token_addr); + } + spec schema AbortIfDaoInfoNotExist { + let token_addr = Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if !exists>(token_addr); + } + spec schema AbortIfDaoConfigNotExist { + let token_addr = Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if !exists>>(token_addr); + } + spec schema AbortIfTimestampNotExist { + use StarcoinFramework::CoreAddresses; + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + spec module { + apply + AbortIfDaoInfoNotExist + to + generate_next_proposal_id; + + apply + AbortIfDaoConfigNotExist + to + get_config, + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + quorum_votes; + } + + /// create a dao config + public fun new_dao_config( + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + ): DaoConfig { + assert!(voting_delay > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID)); + assert!(voting_period > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID)); + assert!( + voting_quorum_rate > 0 && voting_quorum_rate <= 100, + Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID), + ); + assert!(min_action_delay > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID)); + DaoConfig { voting_delay, voting_period, voting_quorum_rate, min_action_delay } + } + + spec new_dao_config { + include NewDaoConfigParamSchema; + } + + spec schema NewDaoConfigParamSchema { + voting_delay: u64; + voting_period: u64; + voting_quorum_rate: u8; + min_action_delay: u64; + + aborts_if voting_delay == 0; + aborts_if voting_period == 0; + aborts_if voting_quorum_rate == 0 || voting_quorum_rate > 100; + aborts_if min_action_delay == 0; + } + + /// propose a proposal. + /// `action`: the actual action to execute. + /// `action_delay`: the delay to execute after the proposal is agreed + public fun propose( + signer: &signer, + action: ActionT, + action_delay: u64, + ) acquires DaoGlobalInfo { + if (action_delay == 0) { + action_delay = min_action_delay(); + } else { + assert!(action_delay >= min_action_delay(), Errors::invalid_argument(ERR_ACTION_DELAY_TOO_SMALL)); + }; + let proposal_id = generate_next_proposal_id(); + let proposer = Signer::address_of(signer); + let start_time = Timestamp::now_milliseconds() + voting_delay(); + let quorum_votes = quorum_votes(); + let proposal = Proposal { + id: proposal_id, + proposer, + start_time, + end_time: start_time + voting_period(), + for_votes: 0, + against_votes: 0, + eta: 0, + action_delay, + quorum_votes, + action: Option::some(action), + }; + move_to(signer, proposal); + // emit event + let gov_info = borrow_global_mut>(Token::token_address()); + Event::emit_event( + &mut gov_info.proposal_create_event, + ProposalCreatedEvent { proposal_id, proposer }, + ); + } + + spec propose { + use StarcoinFramework::CoreAddresses; + pragma verify = false; + let proposer = Signer::address_of(signer); + + include GenerateNextProposalIdSchema; + + pragma addition_overflow_unchecked = true; // start_time calculation + + include AbortIfDaoConfigNotExist; + include AbortIfDaoInfoNotExist; + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + + aborts_if action_delay > 0 && action_delay < spec_dao_config().min_action_delay; + include CheckQuorumVotes; + + let sender = Signer::address_of(signer); + aborts_if exists>(sender); + modifies global>(Token::SPEC_TOKEN_TEST_ADDRESS()); + + ensures exists>(sender); + } + + /// votes for a proposal. + /// User can only vote once, then the stake is locked, + /// which can only be unstaked by user after the proposal is expired, or cancelled, or executed. + /// So think twice before casting vote. + public fun cast_vote( + signer: &signer, + proposer_address: address, + proposal_id: u64, + stake: Token::Token, + agree: bool, + ) acquires Proposal, DaoGlobalInfo, Vote { + { + let state = proposal_state(proposer_address, proposal_id); + // only when proposal is active, use can cast vote. + assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID)); + }; + let proposal = borrow_global_mut>(proposer_address); + assert!(proposal.id == proposal_id, Errors::invalid_argument(ERR_PROPOSAL_ID_MISMATCH)); + let sender = Signer::address_of(signer); + let total_voted = if (exists>(sender)) { + let my_vote = borrow_global_mut>(sender); + assert!(my_vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY)); + assert!(my_vote.agree == agree, Errors::invalid_state(ERR_VOTE_STATE_MISMATCH)); + + do_cast_vote(proposal, my_vote, stake); + Token::value(&my_vote.stake) + } else { + let my_vote = Vote { + proposer: proposer_address, + id: proposal_id, + stake: Token::zero(), + agree, + }; + do_cast_vote(proposal, &mut my_vote, stake); + let total_voted = Token::value(&my_vote.stake); + move_to(signer, my_vote); + total_voted + }; + + // emit event + let gov_info = borrow_global_mut>(Token::token_address()); + Event::emit_event( + &mut gov_info.vote_changed_event, + VoteChangedEvent { + proposal_id, + proposer: proposer_address, + voter: sender, + agree, + vote: total_voted, + }, + ); + } + + spec schema CheckVoteOnCast { + proposal_id: u64; + agree: bool; + voter: address; + stake_value: u128; + let vote = global>(voter); + aborts_if vote.id != proposal_id; + aborts_if vote.agree != agree; + aborts_if vote.stake.value + stake_value > MAX_U128; + } + + spec cast_vote { + pragma addition_overflow_unchecked = true; + + include AbortIfDaoInfoNotExist; + + let expected_states = vec(ACTIVE); + include CheckProposalStates {expected_states}; + let sender = Signer::address_of(signer); + let vote_exists = exists>(sender); + include vote_exists ==> CheckVoteOnCast { + voter: sender, + proposal_id: proposal_id, + agree: agree, + stake_value: stake.value, + }; + + modifies global>(proposer_address); + ensures !vote_exists ==> global>(sender).stake.value == stake.value; + } + + fun do_cast_vote(proposal: &mut Proposal, vote: &mut Vote, stake: Token::Token) { + let stake_value = Token::value(&stake); + Token::deposit(&mut vote.stake, stake); + if (vote.agree) { + proposal.for_votes = proposal.for_votes + stake_value; + } else { + proposal.against_votes = proposal.against_votes + stake_value; + }; + } + + spec do_cast_vote { + pragma addition_overflow_unchecked = true; + aborts_if vote.stake.value + stake.value > MAX_U128; + ensures vote.stake.value == old(vote).stake.value + stake.value; + ensures vote.agree ==> old(proposal).for_votes + stake.value == proposal.for_votes; + ensures vote.agree ==> old(proposal).against_votes == proposal.against_votes; + ensures !vote.agree ==> old(proposal).against_votes + stake.value == proposal.against_votes; + ensures !vote.agree ==> old(proposal).for_votes == proposal.for_votes; + } + + + /// Let user change their vote during the voting time. + public fun change_vote( + signer: &signer, + proposer_address: address, + proposal_id: u64, + agree: bool, + ) acquires Proposal, DaoGlobalInfo, Vote { + { + let state = proposal_state(proposer_address, proposal_id); + // only when proposal is active, user can change vote. + assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID)); + }; + let proposal = borrow_global_mut>(proposer_address); + assert!(proposal.id == proposal_id, Errors::invalid_argument(ERR_PROPOSAL_ID_MISMATCH)); + let my_vote = borrow_global_mut>(Signer::address_of(signer)); + { + assert!(my_vote.proposer == proposer_address, Errors::invalid_argument(ERR_PROPOSER_MISMATCH)); + assert!(my_vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY)); + }; + + // flip the vote + if (my_vote.agree != agree) { + let total_voted = do_flip_vote(my_vote, proposal); + // emit event + let gov_info = borrow_global_mut>(Token::token_address()); + Event::emit_event( + &mut gov_info.vote_changed_event, + VoteChangedEvent { + proposal_id, + proposer: proposer_address, + voter: Signer::address_of(signer), + agree, + vote: total_voted, + }, + ); + }; + } + spec schema CheckVoteOnProposal { + vote: Vote; + proposer_address: address; + proposal_id: u64; + + aborts_if vote.id != proposal_id; + aborts_if vote.proposer != proposer_address; + } + spec schema CheckChangeVote { + vote: Vote; + proposer_address: address; + let proposal = global>(proposer_address); + include AbortIfDaoInfoNotExist; + include CheckFlipVote {my_vote: vote, proposal}; + } + spec change_vote { + pragma verify = false; + let expected_states = vec(ACTIVE); + include CheckProposalStates{expected_states}; + + let sender = Signer::address_of(signer); + aborts_if !exists>(sender); + let vote = global>(sender); + include CheckVoteOnProposal{vote, proposer_address, proposal_id}; + include vote.agree != agree ==> CheckChangeVote{vote, proposer_address}; + + ensures vote.agree != agree ==> vote.agree == agree; + } + + fun do_flip_vote(my_vote: &mut Vote, proposal: &mut Proposal): u128 { + my_vote.agree = !my_vote.agree; + let total_voted = Token::value(&my_vote.stake); + if (my_vote.agree) { + proposal.for_votes = proposal.for_votes + total_voted; + proposal.against_votes = proposal.against_votes - total_voted; + } else { + proposal.for_votes = proposal.for_votes - total_voted; + proposal.against_votes = proposal.against_votes + total_voted; + }; + total_voted + } + spec schema CheckFlipVote { + my_vote: Vote; + proposal: Proposal; + aborts_if my_vote.agree && proposal.for_votes < my_vote.stake.value; + aborts_if my_vote.agree && proposal.against_votes + my_vote.stake.value > MAX_U128; + aborts_if !my_vote.agree && proposal.against_votes < my_vote.stake.value; + aborts_if !my_vote.agree && proposal.for_votes + my_vote.stake.value > MAX_U128; + } + + spec do_flip_vote { + include CheckFlipVote; + ensures my_vote.agree == !old(my_vote).agree; + } + + /// Revoke some voting powers from vote on `proposal_id` of `proposer_address`. + public fun revoke_vote( + signer: &signer, + proposer_address: address, + proposal_id: u64, + voting_power: u128, + ): Token::Token acquires Proposal, Vote, DaoGlobalInfo { + { + let state = proposal_state(proposer_address, proposal_id); + // only when proposal is active, user can revoke vote. + assert!(state == ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID)); + }; + // get proposal + let proposal = borrow_global_mut>(proposer_address); + + // get vote + let my_vote = move_from>(Signer::address_of(signer)); + { + assert!(my_vote.proposer == proposer_address, Errors::invalid_argument(ERR_PROPOSER_MISMATCH)); + assert!(my_vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY)); + }; + // revoke vote on proposal + let reverted_stake =do_revoke_vote(proposal, &mut my_vote, voting_power); + // emit vote changed event + let gov_info = borrow_global_mut>(Token::token_address()); + Event::emit_event( + &mut gov_info.vote_changed_event, + VoteChangedEvent { + proposal_id, + proposer: proposer_address, + voter: Signer::address_of(signer), + agree: my_vote.agree, + vote: Token::value(&my_vote.stake), + }, + ); + + // if user has no stake, destroy his vote. resolve https://github.com/starcoinorg/starcoin/issues/2925. + if (Token::value(&my_vote.stake) == 0u128) { + let Vote {stake, proposer: _, id: _, agree: _} = my_vote; + Token::destroy_zero(stake); + } else { + move_to(signer, my_vote); + }; + + reverted_stake + } + + spec revoke_vote { + pragma verify = false; + include AbortIfDaoInfoNotExist; + let expected_states = vec(ACTIVE); + include CheckProposalStates {expected_states}; + let sender = Signer::address_of(signer); + + aborts_if !exists>(sender); + let vote = global>(sender); + include CheckVoteOnProposal {vote, proposer_address, proposal_id}; + include CheckRevokeVote { + vote, + proposal: global>(proposer_address), + to_revoke: voting_power, + }; + + modifies global>(sender); + modifies global>(proposer_address); + modifies global>(Token::SPEC_TOKEN_TEST_ADDRESS()); + + ensures global>(sender).stake.value + result.value == old(global>(sender)).stake.value; + ensures result.value == voting_power; + } + + fun do_revoke_vote(proposal: &mut Proposal, vote: &mut Vote, to_revoke: u128): Token::Token { + spec { + assume vote.stake.value >= to_revoke; + }; + let reverted_stake = Token::withdraw(&mut vote.stake, to_revoke); + if (vote.agree) { + proposal.for_votes = proposal.for_votes - to_revoke; + } else { + proposal.against_votes = proposal.against_votes - to_revoke; + }; + spec { + assert Token::value(reverted_stake) == to_revoke; + }; + reverted_stake + } + spec schema CheckRevokeVote { + vote: Vote; + proposal: Proposal; + to_revoke: u128; + aborts_if vote.stake.value < to_revoke; + aborts_if vote.agree && proposal.for_votes < to_revoke; + aborts_if !vote.agree && proposal.against_votes < to_revoke; + } + + spec do_revoke_vote { + include CheckRevokeVote; + ensures vote.agree ==> old(proposal).for_votes == proposal.for_votes + to_revoke; + ensures !vote.agree ==> old(proposal).against_votes == proposal.against_votes + to_revoke; + ensures result.value == to_revoke; + } + + /// Retrieve back my staked token voted for a proposal. + public fun unstake_votes( + signer: &signer, + proposer_address: address, + proposal_id: u64, + ): Token::Token acquires Proposal, Vote { + // only check state when proposal exists. + // because proposal can be destroyed after it ends in DEFEATED or EXTRACTED state. + if (proposal_exists(proposer_address, proposal_id)) { + let state = proposal_state(proposer_address, proposal_id); + // Only after vote period end, user can unstake his votes. + assert!(state > ACTIVE, Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID)); + }; + let Vote { proposer, id, stake, agree: _ } = move_from>( + Signer::address_of(signer), + ); + // these checks are still required. + assert!(proposer == proposer_address, Errors::requires_address(ERR_PROPOSER_MISMATCH)); + assert!(id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY)); + stake + } + + spec unstake_votes { + pragma verify = false; + let expected_states = vec(DEFEATED); + let expected_states1 = concat(expected_states,vec(AGREED)); + let expected_states2 = concat(expected_states1,vec(QUEUED)); + let expected_states3 = concat(expected_states2,vec(EXECUTABLE)); + let expected_states4 = concat(expected_states3,vec(EXTRACTED)); + aborts_if expected_states4[0] != DEFEATED; + aborts_if expected_states4[1] != AGREED; + aborts_if expected_states4[2] != QUEUED; + aborts_if expected_states4[3] != EXECUTABLE; + aborts_if expected_states4[4] != EXTRACTED; + include spec_proposal_exists(proposer_address, proposal_id) ==> + CheckProposalStates{expected_states: expected_states4}; + let sender = Signer::address_of(signer); + aborts_if !exists>(sender); + let vote = global>(sender); + include CheckVoteOnProposal{vote, proposer_address, proposal_id}; + ensures !exists>(sender); + ensures result.value == old(vote).stake.value; + } + + + /// queue agreed proposal to execute. + public entry fun queue_proposal_action( + proposer_address: address, + proposal_id: u64, + ) acquires Proposal { + // Only agreed proposal can be submitted. + assert!( + proposal_state(proposer_address, proposal_id) == AGREED, + Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID) + ); + let proposal = borrow_global_mut>(proposer_address); + proposal.eta = Timestamp::now_milliseconds() + proposal.action_delay; + } + spec queue_proposal_action { + pragma verify = false; + let expected_states = vec(AGREED); + include CheckProposalStates{expected_states}; + + let proposal = global>(proposer_address); + aborts_if Timestamp::spec_now_millseconds() + proposal.action_delay > MAX_U64; + ensures proposal.eta >= Timestamp::spec_now_millseconds(); + } + + /// extract proposal action to execute. + public fun extract_proposal_action( + proposer_address: address, + proposal_id: u64, + ): ActionT acquires Proposal { + // Only executable proposal's action can be extracted. + assert!( + proposal_state(proposer_address, proposal_id) == EXECUTABLE, + Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID), + ); + let proposal = borrow_global_mut>(proposer_address); + let action: ActionT = Option::extract(&mut proposal.action); + action + } + spec extract_proposal_action { + pragma aborts_if_is_partial = false; + let expected_states = vec(EXECUTABLE); + include CheckProposalStates{expected_states}; + modifies global>(proposer_address); + ensures Option::is_none(global>(proposer_address).action); + } + + + /// remove terminated proposal from proposer + public entry fun destroy_terminated_proposal( + proposer_address: address, + proposal_id: u64, + ) acquires Proposal { + let proposal_state = proposal_state(proposer_address, proposal_id); + assert!( + proposal_state == DEFEATED || proposal_state == EXTRACTED, + Errors::invalid_state(ERR_PROPOSAL_STATE_INVALID), + ); + let Proposal { + id: _, + proposer: _, + start_time: _, + end_time: _, + for_votes: _, + against_votes: _, + eta: _, + action_delay: _, + quorum_votes: _, + action, + } = move_from>(proposer_address); + if (proposal_state == DEFEATED) { + let _ = Option::extract(&mut action); + }; + Option::destroy_none(action); + } + + spec destroy_terminated_proposal { + let expected_states = concat(vec(DEFEATED), vec(EXTRACTED)); + aborts_if len(expected_states) != 2; + aborts_if expected_states[0] != DEFEATED; + aborts_if expected_states[1] != EXTRACTED; + + aborts_if !exists>(proposer_address); + let proposal = global>(proposer_address); + aborts_if proposal.id != proposal_id; + include AbortIfTimestampNotExist; + let current_time = Timestamp::spec_now_millseconds(); + let state = do_proposal_state(proposal, current_time); + aborts_if (forall s in expected_states : s != state); + aborts_if state == DEFEATED && Option::is_none(global>(proposer_address).action); + aborts_if state == EXTRACTED && Option::is_some(global>(proposer_address).action); + modifies global>(proposer_address); + } + + /// check whether a proposal exists in `proposer_address` with id `proposal_id`. + public fun proposal_exists( + proposer_address: address, + proposal_id: u64, + ): bool acquires Proposal { + if (exists>(proposer_address)) { + let proposal = borrow_global>(proposer_address); + return proposal.id == proposal_id + }; + false + } + spec proposal_exists { + ensures exists>(proposer_address) && + borrow_global>(proposer_address).id == proposal_id ==> + result; + } + + spec fun spec_proposal_exists( + proposer_address: address, + proposal_id: u64, + ): bool { + if (exists>(proposer_address)) { + let proposal = global>(proposer_address); + proposal.id == proposal_id + } else { + false + } + } + + /// Get the proposal state. + public fun proposal_state( + proposer_address: address, + proposal_id: u64, + ): u8 acquires Proposal { + let proposal = borrow_global>(proposer_address); + assert!(proposal.id == proposal_id, Errors::invalid_argument(ERR_PROPOSAL_ID_MISMATCH)); + let current_time = Timestamp::now_milliseconds(); + do_proposal_state(proposal, current_time) + } + + spec schema CheckProposalStates { + proposer_address: address; + proposal_id: u64; + expected_states: vector; + aborts_if !exists>(proposer_address); + + let proposal = global>(proposer_address); + aborts_if proposal.id != proposal_id; + + include AbortIfTimestampNotExist; + let current_time = Timestamp::spec_now_millseconds(); + let state = do_proposal_state(proposal, current_time); + aborts_if (forall s in expected_states : s != state); + } + + spec proposal_state { + use StarcoinFramework::CoreAddresses; + include AbortIfTimestampNotExist; + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if !exists>(proposer_address); + + let proposal = global>(proposer_address); + aborts_if proposal.id != proposal_id; + } + + fun do_proposal_state( + proposal: &Proposal, + current_time: u64, + ): u8 { + if (current_time < proposal.start_time) { + // Pending + PENDING + } else if (current_time <= proposal.end_time) { + // Active + ACTIVE + } else if (proposal.for_votes <= proposal.against_votes || + proposal.for_votes < proposal.quorum_votes) { + // Defeated + DEFEATED + } else if (proposal.eta == 0) { + // Agreed. + AGREED + } else if (current_time < proposal.eta) { + // Queued, waiting to execute + QUEUED + } else if (Option::is_some(&proposal.action)) { + EXECUTABLE + } else { + EXTRACTED + } + } + + + /// get proposal's information. + /// return: (id, start_time, end_time, for_votes, against_votes). + public fun proposal_info( + proposer_address: address, + ): (u64, u64, u64, u128, u128) acquires Proposal { + let proposal = borrow_global>(proposer_address); + (proposal.id, proposal.start_time, proposal.end_time, proposal.for_votes, proposal.against_votes) + } + + spec proposal_info { + aborts_if !exists>(proposer_address); + } + + /// Get voter's vote info on proposal with `proposal_id` of `proposer_address`. + public fun vote_of( + voter: address, + proposer_address: address, + proposal_id: u64, + ): (bool, u128) acquires Vote { + let vote = borrow_global>(voter); + assert!(vote.proposer == proposer_address, Errors::requires_address(ERR_PROPOSER_MISMATCH)); + assert!(vote.id == proposal_id, Errors::invalid_argument(ERR_VOTED_OTHERS_ALREADY)); + (vote.agree, Token::value(&vote.stake)) + } + + spec vote_of { + aborts_if !exists>(voter); + let vote = global>(voter); + include CheckVoteOnProposal{vote, proposer_address, proposal_id}; + } + + /// Check whether voter has voted on proposal with `proposal_id` of `proposer_address`. + public fun has_vote( + voter: address, + proposer_address: address, + proposal_id: u64, + ): bool acquires Vote { + if (!exists>(voter)) { + return false + }; + + let vote = borrow_global>(voter); + vote.proposer == proposer_address && vote.id == proposal_id + } + + fun generate_next_proposal_id(): u64 acquires DaoGlobalInfo { + let gov_info = borrow_global_mut>(Token::token_address()); + let proposal_id = gov_info.next_proposal_id; + gov_info.next_proposal_id = proposal_id + 1; + proposal_id + } + + spec generate_next_proposal_id { + include GenerateNextProposalIdSchema; + ensures result == old(global>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id); + } + + spec schema GenerateNextProposalIdSchema { + aborts_if global>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id >= MAX_U64; + modifies global>(Token::SPEC_TOKEN_TEST_ADDRESS()); + ensures + global>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id == + old(global>(Token::SPEC_TOKEN_TEST_ADDRESS()).next_proposal_id) + 1; + } + + //// Helper functions + + //// Query functions + + /// get default voting delay of the DAO. + public fun voting_delay(): u64 { + get_config().voting_delay + } + + spec voting_delay { + aborts_if false; + } + + /// get the default voting period of the DAO. + public fun voting_period(): u64 { + get_config().voting_period + } + + spec voting_period { + aborts_if false; + } + + /// Quorum votes to make proposal pass. + public fun quorum_votes(): u128 { + let market_cap = Token::market_cap(); + let balance_in_treasury = Treasury::balance(); + let supply = market_cap - balance_in_treasury; + let rate = voting_quorum_rate(); + let rate = (rate as u128); + supply * rate / 100 + } + spec schema CheckQuorumVotes { + aborts_if Token::spec_abstract_total_value() * spec_dao_config().voting_quorum_rate > MAX_U128; + } + spec quorum_votes { + pragma verify = false; + include CheckQuorumVotes; + } + + spec fun spec_quorum_votes(): u128 { + let supply = Token::spec_abstract_total_value() - Treasury::spec_balance(); + supply * spec_dao_config().voting_quorum_rate / 100 + } + + /// Get the quorum rate in percent. + public fun voting_quorum_rate(): u8 { + get_config().voting_quorum_rate + } + + spec voting_quorum_rate { + aborts_if false; + ensures result == global>>((Token::SPEC_TOKEN_TEST_ADDRESS())).payload.voting_quorum_rate; + } + + /// Get the min_action_delay of the DAO. + public fun min_action_delay(): u64 { + get_config().min_action_delay + } + + spec min_action_delay { + aborts_if false; + ensures result == spec_dao_config().min_action_delay; + } + + fun get_config(): DaoConfig { + let token_issuer = Token::token_address(); + Config::get_by_address>(token_issuer) + } + + spec get_config { + aborts_if false; + ensures result == global>>(Token::SPEC_TOKEN_TEST_ADDRESS()).payload; + } + + + spec fun spec_dao_config(): DaoConfig { + global>>((Token::SPEC_TOKEN_TEST_ADDRESS())).payload + } + + + spec schema CheckModifyConfigWithCap { + cap: Config::ModifyConfigCapability>; + aborts_if cap.account_address != Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if !exists>>(cap.account_address); + } + + /// update function, modify dao config. + /// if any param is 0, it means no change to that param. + public fun modify_dao_config( + cap: &mut Config::ModifyConfigCapability>, + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + ) { + assert!(Config::account_address(cap) == Token::token_address(), Errors::invalid_argument(ERR_NOT_AUTHORIZED)); + let config = get_config(); + if (voting_period > 0) { + config.voting_period = voting_period; + }; + if (voting_delay > 0) { + config.voting_delay = voting_delay; + }; + if (voting_quorum_rate > 0) { + assert!(voting_quorum_rate <= 100, Errors::invalid_argument(ERR_QUORUM_RATE_INVALID)); + config.voting_quorum_rate = voting_quorum_rate; + }; + if (min_action_delay > 0) { + config.min_action_delay = min_action_delay; + }; + Config::set_with_capability>(cap, config); + } + + spec modify_dao_config { + include CheckModifyConfigWithCap; + aborts_if voting_quorum_rate > 0 && voting_quorum_rate > 100; + } + + /// set voting delay + public fun set_voting_delay( + cap: &mut Config::ModifyConfigCapability>, + value: u64, + ) { + assert!(Config::account_address(cap) == Token::token_address(), Errors::invalid_argument(ERR_NOT_AUTHORIZED)); + assert!(value > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID)); + let config = get_config(); + config.voting_delay = value; + Config::set_with_capability>(cap, config); + } + + spec set_voting_delay { + include CheckModifyConfigWithCap; + aborts_if value == 0; + } + + /// set voting period + public fun set_voting_period( + cap: &mut Config::ModifyConfigCapability>, + value: u64, + ) { + assert!(Config::account_address(cap) == Token::token_address(), Errors::invalid_argument(ERR_NOT_AUTHORIZED)); + assert!(value > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID)); + let config = get_config(); + config.voting_period = value; + Config::set_with_capability>(cap, config); + } + + spec set_voting_period { + include CheckModifyConfigWithCap; + aborts_if value == 0; + } + + /// set voting quorum rate + public fun set_voting_quorum_rate( + cap: &mut Config::ModifyConfigCapability>, + value: u8, + ) { + assert!(Config::account_address(cap) == Token::token_address(), Errors::invalid_argument(ERR_NOT_AUTHORIZED)); + assert!(value <= 100 && value > 0, Errors::invalid_argument(ERR_QUORUM_RATE_INVALID)); + let config = get_config(); + config.voting_quorum_rate = value; + Config::set_with_capability>(cap, config); + } + + spec set_voting_quorum_rate { + aborts_if !(value > 0 && value <= 100); + include CheckModifyConfigWithCap; + } + + /// set min action delay + public fun set_min_action_delay( + cap: &mut Config::ModifyConfigCapability>, + value: u64, + ) { + assert!(Config::account_address(cap) == Token::token_address(), Errors::invalid_argument(ERR_NOT_AUTHORIZED)); + assert!(value > 0, Errors::invalid_argument(ERR_CONFIG_PARAM_INVALID)); + let config = get_config(); + config.min_action_delay = value; + Config::set_with_capability>(cap, config); + } + spec set_min_action_delay { + aborts_if value == 0; + include CheckModifyConfigWithCap; + } +} +} diff --git a/release/v13/sources/DaoVoteScripts.move b/release/v13/sources/DaoVoteScripts.move new file mode 100644 index 00000000..3f4ca178 --- /dev/null +++ b/release/v13/sources/DaoVoteScripts.move @@ -0,0 +1,77 @@ +address StarcoinFramework { +module DaoVoteScripts { + use StarcoinFramework::Dao; + use StarcoinFramework::Account; + use StarcoinFramework::Signer; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_partial = false; + pragma aborts_if_is_strict = true; + } + + public entry fun cast_vote( + signer: signer, + proposer_address: address, + proposal_id: u64, + agree: bool, + votes: u128, + ) { + let sender = Signer::address_of(&signer); + if (Dao::has_vote(sender, proposer_address, proposal_id)) { + // if already voted, and vote is not same as the current cast, change the existing vote. + // resolve https://github.com/starcoinorg/starcoin/issues/2925. + let (agree_voted, _) = Dao::vote_of(sender, proposer_address, proposal_id); + if (agree_voted != agree) { + Dao::change_vote(&signer, proposer_address, proposal_id, agree); + } + }; + + let votes = Account::withdraw(&signer, votes); + Dao::cast_vote(&signer, proposer_address, proposal_id, votes, agree); + } + + /// revoke all votes on a proposal + public entry fun revoke_vote( + signer: signer, + proposer_address: address, + proposal_id: u64, + ) { + let sender = Signer::address_of(&signer); + let (_, power) = Dao::vote_of(sender, proposer_address, proposal_id); + let my_token = Dao::revoke_vote(&signer, proposer_address, proposal_id, power); + Account::deposit(sender, my_token); + } + + /// Let user change their vote during the voting time. + public entry fun flip_vote( + signer: signer, + proposer_address: address, + proposal_id: u64, + ) { + let (agree, _) = Dao::vote_of(Signer::address_of(&signer), proposer_address, proposal_id); + Dao::change_vote(&signer, proposer_address, proposal_id, !agree); + } + + /// revoke some votes on a proposal + public entry fun revoke_vote_of_power( + signer: signer, + proposer_address: address, + proposal_id: u64, + power: u128, + ) { + let sender = Signer::address_of(&signer); + let my_token = Dao::revoke_vote(&signer, proposer_address, proposal_id, power); + Account::deposit(sender, my_token); + } + + public entry fun unstake_vote( + signer: signer, + proposer_address: address, + proposal_id: u64, + ) { + let my_token = Dao::unstake_votes(&signer, proposer_address, proposal_id); + Account::deposit(Signer::address_of(&signer), my_token); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Debug.move b/release/v13/sources/Debug.move new file mode 100644 index 00000000..7fb0f1c2 --- /dev/null +++ b/release/v13/sources/Debug.move @@ -0,0 +1,16 @@ +address StarcoinFramework { +/// The module provide debug print for Move. +module Debug { + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// Print data of Type `T`. + native public fun print(x: &T); + + /// Print current stack. + native public fun print_stack_trace(); +} + +} diff --git a/release/v13/sources/DummyToken.move b/release/v13/sources/DummyToken.move new file mode 100644 index 00000000..af6f684b --- /dev/null +++ b/release/v13/sources/DummyToken.move @@ -0,0 +1,77 @@ +address StarcoinFramework{ +/// The module provide a dummy token implementation. +module DummyToken { + use StarcoinFramework::Token::{Self, Token}; + use StarcoinFramework::Errors; + + /// The DummyToken type. + struct DummyToken has copy, drop, store { } + + + const EMINT_TOO_MUCH:u64 = 101; + + const PRECISION: u8 = 3; + + /// Burn capability of the token. + struct SharedBurnCapability has key { + cap: Token::BurnCapability, + } + + /// Mint capability of the token. + struct SharedMintCapability has key, store { + cap: Token::MintCapability, + } + + /// Initialization of the module. + public fun initialize(account: &signer) { + Token::register_token( + account, + PRECISION, + ); + + let burn_cap = Token::remove_burn_capability(account); + move_to(account, SharedBurnCapability{cap: burn_cap}); + + let burn_cap = Token::remove_mint_capability(account); + move_to(account, SharedMintCapability{cap: burn_cap}); + } + + /// Returns true if `TokenType` is `DummyToken::DummyToken` + public fun is_dummy_token(): bool { + Token::is_same_token() + } + + /// Burn the given token. + public fun burn(token: Token) acquires SharedBurnCapability{ + let cap = borrow_global(token_address()); + Token::burn_with_capability(&cap.cap, token); + } + + /// Anyone can mint DummyToken, amount should < 10000 + public fun mint(_account: &signer, amount: u128) : Token acquires SharedMintCapability{ + assert!(amount <= 10000, Errors::invalid_argument(EMINT_TOO_MUCH)); + let cap = borrow_global(token_address()); + Token::mint_with_capability(&cap.cap, amount) + } + + /// Return the token address. + public fun token_address(): address { + Token::token_address() + } +} + +module DummyTokenScripts{ + use StarcoinFramework::DummyToken::{Self,DummyToken}; + use StarcoinFramework::Account; + use StarcoinFramework::Signer; + + public entry fun mint(sender: signer, amount: u128){ + let token = DummyToken::mint(&sender, amount); + let sender_addr = Signer::address_of(&sender); + if(Account::is_accept_token(sender_addr)){ + Account::do_accept_token(&sender); + }; + Account::deposit(sender_addr, token); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/DummyTokenScripts.move b/release/v13/sources/DummyTokenScripts.move new file mode 100644 index 00000000..af6f684b --- /dev/null +++ b/release/v13/sources/DummyTokenScripts.move @@ -0,0 +1,77 @@ +address StarcoinFramework{ +/// The module provide a dummy token implementation. +module DummyToken { + use StarcoinFramework::Token::{Self, Token}; + use StarcoinFramework::Errors; + + /// The DummyToken type. + struct DummyToken has copy, drop, store { } + + + const EMINT_TOO_MUCH:u64 = 101; + + const PRECISION: u8 = 3; + + /// Burn capability of the token. + struct SharedBurnCapability has key { + cap: Token::BurnCapability, + } + + /// Mint capability of the token. + struct SharedMintCapability has key, store { + cap: Token::MintCapability, + } + + /// Initialization of the module. + public fun initialize(account: &signer) { + Token::register_token( + account, + PRECISION, + ); + + let burn_cap = Token::remove_burn_capability(account); + move_to(account, SharedBurnCapability{cap: burn_cap}); + + let burn_cap = Token::remove_mint_capability(account); + move_to(account, SharedMintCapability{cap: burn_cap}); + } + + /// Returns true if `TokenType` is `DummyToken::DummyToken` + public fun is_dummy_token(): bool { + Token::is_same_token() + } + + /// Burn the given token. + public fun burn(token: Token) acquires SharedBurnCapability{ + let cap = borrow_global(token_address()); + Token::burn_with_capability(&cap.cap, token); + } + + /// Anyone can mint DummyToken, amount should < 10000 + public fun mint(_account: &signer, amount: u128) : Token acquires SharedMintCapability{ + assert!(amount <= 10000, Errors::invalid_argument(EMINT_TOO_MUCH)); + let cap = borrow_global(token_address()); + Token::mint_with_capability(&cap.cap, amount) + } + + /// Return the token address. + public fun token_address(): address { + Token::token_address() + } +} + +module DummyTokenScripts{ + use StarcoinFramework::DummyToken::{Self,DummyToken}; + use StarcoinFramework::Account; + use StarcoinFramework::Signer; + + public entry fun mint(sender: signer, amount: u128){ + let token = DummyToken::mint(&sender, amount); + let sender_addr = Signer::address_of(&sender); + if(Account::is_accept_token(sender_addr)){ + Account::do_accept_token(&sender); + }; + Account::deposit(sender_addr, token); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/EVMAddress.move b/release/v13/sources/EVMAddress.move new file mode 100644 index 00000000..044636e4 --- /dev/null +++ b/release/v13/sources/EVMAddress.move @@ -0,0 +1,131 @@ +address StarcoinFramework { + +/// Contains functions for [ed25519](https://en.wikipedia.org/wiki/EdDSA) digital signatures. +module Signature { + + use StarcoinFramework::Vector; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::EVMAddress::{Self, EVMAddress}; + + native public fun ed25519_validate_pubkey(public_key: vector): bool; + native public fun ed25519_verify(signature: vector, public_key: vector, message: vector): bool; + + /// recover address from ECDSA signature, if recover fail, return an empty vector + native fun native_ecrecover(hash: vector, signature: vector): vector; + + /// recover address from ECDSA signature, if recover fail, return None + public fun ecrecover(hash: vector, signature: vector):Option{ + let bytes = native_ecrecover(hash, signature); + if (Vector::is_empty(&bytes)){ + Option::none() + }else{ + Option::some(EVMAddress::new(bytes)) + } + } + + // verify eth secp256k1 sign and compare addr, if add equal return true + public fun secp256k1_verify(signature: vector, addr: vector, message: vector) : bool{ + let receover_address_opt:Option = ecrecover(message, signature); + let expect_address = EVMAddress::new(addr); + &Option::destroy_some(receover_address_opt) == &expect_address + } + + spec module { + pragma intrinsic = true; + } + + #[test] + fun test_ecrecover_invalid(){ + let h = b"00"; + let s = b"00"; + let addr = ecrecover(h, s); + assert!(Option::is_none(&addr), 1001); + } +} + +module EVMAddress{ + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + use StarcoinFramework::Vector; + + const EVM_ADDR_LENGTH:u64 = 20; + + struct EVMAddress has copy, store, drop{ + bytes: vector, + } + + /// Create EVMAddress from bytes, If bytes is larger than EVM_ADDR_LENGTH(20), bytes will be cropped from the left. + /// keep same as https://github.com/ethereum/go-ethereum/blob/master/common/types.go#L302 + public fun new(bytes: vector): EVMAddress{ + let len = Vector::length(&bytes); + let bytes = if (len > EVM_ADDR_LENGTH){ + let new_bytes = Vector::empty(); + let i = 0; + while (i < EVM_ADDR_LENGTH) { + Vector::push_back(&mut new_bytes, *Vector::borrow(&bytes, i)); + i = i + 1; + }; + new_bytes + }else if (len == EVM_ADDR_LENGTH){ + bytes + }else{ + let i = 0; + let new_bytes = Vector::empty(); + while (i < EVM_ADDR_LENGTH - len) { + // pad zero to address + Vector::push_back(&mut new_bytes, 0); + i = i + 1; + }; + Vector::append(&mut new_bytes, bytes); + new_bytes + }; + EVMAddress{ + bytes + } + } + + spec new { + pragma verify = false; + //TODO + } + + /// Get the inner bytes of the `addr` as a reference + public fun as_bytes(addr: &EVMAddress): &vector { + &addr.bytes + } + + spec as_bytes { + pragma verify = false; + //TODO + } + + /// Unpack the `addr` to get its backing bytes + public fun into_bytes(addr: EVMAddress): vector { + let EVMAddress { bytes } = addr; + bytes + } + + spec into_bytes { + pragma verify = false; + //TODO + } + + #[test] + fun test_evm_address_padding(){ + let addr1 = new(x"00"); + let addr2 = new(x"0000"); + assert!(&addr1.bytes == &addr2.bytes, 1001); + } + + #[test] + fun test_evm_address_crop(){ + let addr1 = new(x"01234567890123456789012345678901234567891111"); + let addr2 = new(x"01234567890123456789012345678901234567892222"); + assert!(&addr1.bytes == &addr2.bytes, 1001); + } +} +} diff --git a/release/v13/sources/EasyGas.move b/release/v13/sources/EasyGas.move new file mode 100644 index 00000000..e5ba4710 --- /dev/null +++ b/release/v13/sources/EasyGas.move @@ -0,0 +1,147 @@ +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; + use StarcoinFramework::Errors; + + const EBAD_TRANSACTION_FEE_TOKEN: u64 = 18; + 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); + 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, Errors::invalid_argument(EBAD_TRANSACTION_FEE_TOKEN)); + 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::TransferScripts::peer_to_peer_v2; + 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); + } + public entry fun deposit(sender: signer, amount:u128) { + let address = EasyGas::get_gas_fee_address(); + peer_to_peer_v2(sender, address, amount) + } +} +} diff --git a/release/v13/sources/EasyGasScript.move b/release/v13/sources/EasyGasScript.move new file mode 100644 index 00000000..e5ba4710 --- /dev/null +++ b/release/v13/sources/EasyGasScript.move @@ -0,0 +1,147 @@ +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; + use StarcoinFramework::Errors; + + const EBAD_TRANSACTION_FEE_TOKEN: u64 = 18; + 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); + 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, Errors::invalid_argument(EBAD_TRANSACTION_FEE_TOKEN)); + 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::TransferScripts::peer_to_peer_v2; + 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); + } + public entry fun deposit(sender: signer, amount:u128) { + let address = EasyGas::get_gas_fee_address(); + peer_to_peer_v2(sender, address, amount) + } +} +} diff --git a/release/v13/sources/EmptyScripts.move b/release/v13/sources/EmptyScripts.move new file mode 100644 index 00000000..2735276b --- /dev/null +++ b/release/v13/sources/EmptyScripts.move @@ -0,0 +1,14 @@ +address StarcoinFramework { + // A empty scripts module for call a script but do nothing. + module EmptyScripts { + + spec module { + pragma verify = false; + pragma aborts_if_is_partial = false; + pragma aborts_if_is_strict = false; + } + + public entry fun empty_script() { + } + } +} \ No newline at end of file diff --git a/release/v13/sources/Epoch.move b/release/v13/sources/Epoch.move new file mode 100644 index 00000000..de12b7ea --- /dev/null +++ b/release/v13/sources/Epoch.move @@ -0,0 +1,380 @@ +address StarcoinFramework { +/// The module provide epoch functionality for starcoin. +module Epoch { + use StarcoinFramework::Config; + use StarcoinFramework::Signer; + use StarcoinFramework::CoreAddresses; + + use StarcoinFramework::Event; + use StarcoinFramework::Errors; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Math; + use StarcoinFramework::Option; + use StarcoinFramework::ConsensusConfig::{Self, ConsensusConfig}; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// Current epoch info. + struct Epoch has key { + /// Number of current epoch + number: u64, + /// Start time of current epoch + start_time: u64, + /// Start block's number of current epoch + start_block_number: u64, + /// End block's number of current epoch + end_block_number: u64, + /// Average target time to calculate a block's difficulty in current epoch + block_time_target: u64, + /// Rewards per block in current epoch + reward_per_block: u128, + /// Percentage of `reward_per_block` to reward a uncle block in current epoch + reward_per_uncle_percent: u64, + /// How many ancestor blocks which use to calculate next block's difficulty in current epoch + block_difficulty_window: u64, + /// Maximum number of uncle block per block in current epoch + max_uncles_per_block: u64, + /// Maximum gases per block in current epoch + block_gas_limit: u64, + /// Strategy to calculate difficulty in current epoch + strategy: u8, + /// Switch Epoch Event + new_epoch_events: Event::EventHandle, + } + + /// New epoch event. + struct NewEpochEvent has drop, store { + /// Epoch::number + number: u64, + /// Epoch::start_time + start_time: u64, + /// Epoch::start_block_number + start_block_number: u64, + /// Epoch::end_block_number + end_block_number: u64, + /// Epoch::block_time_target + block_time_target: u64, + /// Epoch::reward_per_block + reward_per_block: u128, + /// Total rewards during previous epoch + previous_epoch_total_reward: u128, + } + + /// Epoch data. + struct EpochData has key { + /// Up to now, Number of uncle block during current epoch + uncles: u64, + /// Up to now, Total rewards during current epoch + total_reward: u128, + /// Up to now, Total gases during current epoch + total_gas: u128, + } + + const THOUSAND: u64 = 1000; + const THOUSAND_U128: u128 = 1000; + const HUNDRED: u64 = 100; + + const EUNREACHABLE: u64 = 19; + const EINVALID_UNCLES_COUNT: u64 = 101; + + /// Initialization of the module. + public fun initialize( + account: &signer, + ) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + + let config = ConsensusConfig::get_config(); + move_to( + account, + Epoch { + number: 0, + start_time: Timestamp::now_milliseconds(), + start_block_number: 0, + end_block_number: ConsensusConfig::epoch_block_count(&config), + block_time_target: ConsensusConfig::base_block_time_target(&config), + reward_per_block: ConsensusConfig::base_reward_per_block(&config), + reward_per_uncle_percent: ConsensusConfig::base_reward_per_uncle_percent(&config), + block_difficulty_window: ConsensusConfig::base_block_difficulty_window(&config), + max_uncles_per_block: ConsensusConfig::base_max_uncles_per_block(&config), + block_gas_limit: ConsensusConfig::base_block_gas_limit(&config), + strategy: ConsensusConfig::strategy(&config), + new_epoch_events: Event::new_event_handle(account), + }, + ); + move_to(account, EpochData { uncles: 0, total_reward: 0, total_gas: 0 }); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + + aborts_if exists(Signer::address_of(account)); + aborts_if exists(Signer::address_of(account)); + } + + /// compute next block time_target. + public fun compute_next_block_time_target(config: &ConsensusConfig, last_epoch_time_target: u64, epoch_start_time: u64, now_milli_second: u64, start_block_number: u64, end_block_number: u64, total_uncles: u64): u64 { + let total_time = now_milli_second - epoch_start_time; + let blocks = end_block_number - start_block_number; + let avg_block_time = total_time / blocks; + let uncles_rate = total_uncles * THOUSAND / blocks; + let new_epoch_block_time_target = (THOUSAND + uncles_rate) * avg_block_time / + (ConsensusConfig::uncle_rate_target(config) + THOUSAND); + if (new_epoch_block_time_target > last_epoch_time_target * 2) { + new_epoch_block_time_target = last_epoch_time_target * 2; + }; + if (new_epoch_block_time_target < last_epoch_time_target / 2) { + new_epoch_block_time_target = last_epoch_time_target / 2; + }; + let min_block_time_target = ConsensusConfig::min_block_time_target(config); + let max_block_time_target = ConsensusConfig::max_block_time_target(config); + if (new_epoch_block_time_target < min_block_time_target) { + new_epoch_block_time_target = min_block_time_target; + }; + if (new_epoch_block_time_target > max_block_time_target) { + new_epoch_block_time_target = max_block_time_target; + }; + new_epoch_block_time_target + } + + spec compute_next_block_time_target { + pragma verify = false; + } + + /// adjust_epoch try to advance to next epoch if current epoch ends. + public fun adjust_epoch(account: &signer, block_number: u64, timestamp: u64, uncles: u64, parent_gas_used:u64): u128 + acquires Epoch, EpochData { + CoreAddresses::assert_genesis_address(account); + + let epoch_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT)); + + let epoch_data = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + let (new_epoch, reward_per_block) = if (block_number < epoch_ref.end_block_number) { + (false, epoch_ref.reward_per_block) + } else if (block_number == epoch_ref.end_block_number) { + //start a new epoch + assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT)); + // block time target unit is milli_seconds. + let now_milli_seconds = timestamp; + + let config = ConsensusConfig::get_config(); + let last_epoch_time_target = epoch_ref.block_time_target; + let new_epoch_block_time_target = compute_next_block_time_target(&config, last_epoch_time_target, epoch_ref.start_time, now_milli_seconds, epoch_ref.start_block_number, epoch_ref.end_block_number, epoch_data.uncles); + let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(&config, new_epoch_block_time_target); + + //update epoch by adjust result or config, because ConsensusConfig may be updated. + epoch_ref.number = epoch_ref.number + 1; + epoch_ref.start_time = now_milli_seconds; + epoch_ref.start_block_number = block_number; + epoch_ref.end_block_number = block_number + ConsensusConfig::epoch_block_count(&config); + epoch_ref.block_time_target = new_epoch_block_time_target; + epoch_ref.reward_per_block = new_reward_per_block; + epoch_ref.reward_per_uncle_percent = ConsensusConfig::base_reward_per_uncle_percent(&config); + epoch_ref.block_difficulty_window = ConsensusConfig::base_block_difficulty_window(&config); + epoch_ref.max_uncles_per_block = ConsensusConfig::base_max_uncles_per_block(&config); + epoch_ref.strategy = ConsensusConfig::strategy(&config); + + epoch_data.uncles = 0; + let last_epoch_total_gas = epoch_data.total_gas + (parent_gas_used as u128); + adjust_gas_limit(&config, epoch_ref, last_epoch_time_target, new_epoch_block_time_target, last_epoch_total_gas); + emit_epoch_event(epoch_ref, epoch_data.total_reward); + (true, new_reward_per_block) + } else { + //This should never happened. + abort EUNREACHABLE + }; + let reward = reward_per_block + + reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128); + update_epoch_data(epoch_data, new_epoch, reward, uncles, parent_gas_used); + reward + } + + spec adjust_epoch { + pragma verify = false; //timeout + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if !exists(Signer::address_of(account)); + aborts_if global(Signer::address_of(account)).max_uncles_per_block < uncles; + aborts_if exists(Signer::address_of(account)); + aborts_if block_number == global(Signer::address_of(account)).end_block_number && uncles != 0; + // ... + } + + fun adjust_gas_limit(config: &ConsensusConfig, epoch_ref: &mut Epoch, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_total_gas:u128) { + let new_gas_limit = compute_gas_limit(config, last_epoch_time_target, new_epoch_time_target, epoch_ref.block_gas_limit, last_epoch_total_gas); + if (Option::is_some(&new_gas_limit)) { + epoch_ref.block_gas_limit = Option::destroy_some(new_gas_limit); + } + } + + spec adjust_gas_limit { + pragma verify = false; //mul_div() timeout + } + + /// Compute block's gas limit of next epoch. + public fun compute_gas_limit(config: &ConsensusConfig, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_block_gas_limit: u64, last_epoch_total_gas: u128) : Option::Option { + let epoch_block_count = (ConsensusConfig::epoch_block_count(config) as u128); + let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div((last_epoch_block_gas_limit as u128) * epoch_block_count, (80 as u128), (HUNDRED as u128))); + let new_gas_limit = Option::none(); + + let min_block_time_target = ConsensusConfig::min_block_time_target(config); + let max_block_time_target = ConsensusConfig::max_block_time_target(config); + let base_block_gas_limit = ConsensusConfig::base_block_gas_limit(config); + if (last_epoch_time_target == new_epoch_time_target) { + if (new_epoch_time_target == min_block_time_target && gas_limit_threshold) { + let increase_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 110, base_block_gas_limit); + new_gas_limit = Option::some(increase_gas_limit); + } else if (new_epoch_time_target == max_block_time_target && !gas_limit_threshold) { + let decrease_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 90, base_block_gas_limit); + new_gas_limit = Option::some(decrease_gas_limit); + } + }; + + new_gas_limit + } + + spec compute_gas_limit { + pragma verify = false; //mul_div() timeout + } + + fun in_or_decrease_gas_limit(last_epoch_block_gas_limit: u64, percent: u64, min_block_gas_limit: u64): u64 { + let tmp_gas_limit = Math::mul_div((last_epoch_block_gas_limit as u128), (percent as u128), (HUNDRED as u128)); + let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit as u128)) { + (tmp_gas_limit as u64) + } else { + min_block_gas_limit + }; + + new_gas_limit + } + + spec in_or_decrease_gas_limit { + include Math::MulDivAbortsIf{x: last_epoch_block_gas_limit, y: percent, z: HUNDRED}; + aborts_if Math::spec_mul_div() > MAX_U64; + } + + fun update_epoch_data(epoch_data: &mut EpochData, new_epoch: bool, reward: u128, uncles: u64, parent_gas_used:u64) { + if (new_epoch) { + epoch_data.total_reward = reward; + epoch_data.uncles = uncles; + epoch_data.total_gas = 0; + } else { + epoch_data.total_reward = epoch_data.total_reward + reward; + epoch_data.uncles = epoch_data.uncles + uncles; + epoch_data.total_gas = epoch_data.total_gas + (parent_gas_used as u128); + } + } + + spec update_epoch_data { + aborts_if !new_epoch && epoch_data.total_reward + reward > MAX_U128; + aborts_if !new_epoch && epoch_data.uncles + uncles > MAX_U64; + aborts_if !new_epoch && epoch_data.total_gas + parent_gas_used > MAX_U128; + } + + fun emit_epoch_event(epoch_ref: &mut Epoch, previous_epoch_total_reward: u128) { + Event::emit_event( + &mut epoch_ref.new_epoch_events, + NewEpochEvent { + number: epoch_ref.number, + start_time: epoch_ref.start_time, + start_block_number: epoch_ref.start_block_number, + end_block_number: epoch_ref.end_block_number, + block_time_target: epoch_ref.block_time_target, + reward_per_block: epoch_ref.reward_per_block, + previous_epoch_total_reward, + }, + ); + } + + spec emit_epoch_event { + aborts_if false; + } + + /// Get start time of current epoch + public fun start_time(): u64 acquires Epoch { + let epoch_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_ref.start_time + } + + spec start_time { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get uncles number of current epoch + public fun uncles(): u64 acquires EpochData { + let epoch_data = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_data.uncles + } + + spec uncles { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get total gas of current epoch + public fun total_gas(): u128 acquires EpochData { + let epoch_data = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_data.total_gas + } + + spec total_gas { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get block's gas_limit of current epoch + public fun block_gas_limit(): u64 acquires Epoch { + let epoch_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_ref.block_gas_limit + } + + spec block_gas_limit { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get start block's number of current epoch + public fun start_block_number(): u64 acquires Epoch { + let epoch_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_ref.start_block_number + } + + spec start_block_number { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get end block's number of current epoch + public fun end_block_number(): u64 acquires Epoch { + let epoch_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_ref.end_block_number + } + + spec end_block_number { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get current epoch number + public fun number(): u64 acquires Epoch { + let epoch_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_ref.number + } + + spec number { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get current block time target + public fun block_time_target(): u64 acquires Epoch { + let epoch_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS()); + epoch_ref.block_time_target + } + + spec block_time_target { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + +} +} \ No newline at end of file diff --git a/release/v13/sources/Errors.move b/release/v13/sources/Errors.move new file mode 100644 index 00000000..4a181039 --- /dev/null +++ b/release/v13/sources/Errors.move @@ -0,0 +1,169 @@ +address StarcoinFramework { + +/// Module defining error codes used in Move aborts throughout the framework. +/// +/// A `u64` error code is constructed from two values: +/// +/// 1. The *error category* which is encoded in the lower 8 bits of the code. Error categories are +/// declared in this module and are globally unique across the Diem framework. There is a limited +/// fixed set of predefined categories, and the framework is guaranteed to use those consistently. +/// +/// 2. The *error reason* which is encoded in the remaining 56 bits of the code. The reason is a unique +/// number relative to the module which raised the error and can be used to obtain more information about +/// the error at hand. It is mostly used for diagnosis purposes. Error reasons may change over time as the +/// framework evolves. +/// +/// Rules to declare or use *error reason*: +/// 1. error reason is declared as const in the user module +/// 2. error reason name must start with "E", for example, const EACCOUNT_DOES_NOT_EXIST = ... +/// 3. value less than 100 is reserved for general purpose and shared by all modules +/// 4. don't change general purpose error reason value, it's co-related with error code in starcoin vm +/// 5. self-defined error reason value must be large than 100 +/// 6. error reason must be used together with error category +/// +module Errors { + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// A function to create an error from from a category and a reason. + fun make(category: u8, reason: u64): u64 { + (category as u64) + (reason << 8) + } + spec make { + pragma opaque = true; + pragma verify = false; + //ensures [concrete] result == category + (reason << 8); + aborts_if [abstract] false; + ensures [abstract] result == category; + } + + /// The system is in a state where the performed operation is not allowed. Example: call to a function only allowed + /// in genesis + const INVALID_STATE: u8 = 1; + + /// The signer of a transaction does not have the expected address for this operation. Example: a call to a function + /// which publishes a resource under a particular address. + const REQUIRES_ADDRESS: u8 = 2; + + /// The signer of a transaction does not have the expected role for this operation. Example: a call to a function + /// which requires the signer to have the role of treasury compliance. + const REQUIRES_ROLE: u8 = 3; + + /// The signer of a transaction does not have a required capability. + const REQUIRES_CAPABILITY: u8 = 4; + + /// A resource is required but not published. Example: access to non-existing resource. + const NOT_PUBLISHED: u8 = 5; + + /// Attempting to publish a resource that is already published. Example: calling an initialization function + /// twice. + const ALREADY_PUBLISHED: u8 = 6; + + /// An argument provided to an operation is invalid. Example: a signing key has the wrong format. + const INVALID_ARGUMENT: u8 = 7; + + /// A limit on an amount, e.g. a currency, is exceeded. Example: withdrawal of money after account limits window + /// is exhausted. + const LIMIT_EXCEEDED: u8 = 8; + + /// An internal error (bug) has occurred. + const INTERNAL: u8 = 10; + + /// deprecated code + const DEPRECATED: u8 = 11; + + /// A custom error category for extension points. + const CUSTOM: u8 = 255; + + /// Create an error of `invalid_state` + public fun invalid_state(reason: u64): u64 { make(INVALID_STATE, reason) } + spec invalid_state { + pragma opaque = true; + aborts_if false; + ensures result == INVALID_STATE; + } + + /// Create an error of `requires_address`. + public fun requires_address(reason: u64): u64 { make(REQUIRES_ADDRESS, reason) } + spec requires_address { + pragma opaque = true; + aborts_if false; + ensures result == REQUIRES_ADDRESS; + } + + /// Create an error of `requires_role`. + public fun requires_role(reason: u64): u64 { make(REQUIRES_ROLE, reason) } + spec requires_role { + pragma opaque = true; + aborts_if false; + ensures result == REQUIRES_ROLE; + } + + /// Create an error of `requires_capability`. + public fun requires_capability(reason: u64): u64 { make(REQUIRES_CAPABILITY, reason) } + spec requires_capability { + pragma opaque = true; + aborts_if false; + ensures result == REQUIRES_CAPABILITY; + } + + /// Create an error of `not_published`. + public fun not_published(reason: u64): u64 { make(NOT_PUBLISHED, reason) } + spec not_published { + pragma opaque = true; + aborts_if false; + ensures result == NOT_PUBLISHED; + } + + /// Create an error of `already_published`. + public fun already_published(reason: u64): u64 { make(ALREADY_PUBLISHED, reason) } + spec already_published { + pragma opaque = true; + aborts_if false; + ensures result == ALREADY_PUBLISHED; + } + + /// Create an error of `invalid_argument`. + public fun invalid_argument(reason: u64): u64 { make(INVALID_ARGUMENT, reason) } + spec invalid_argument { + pragma opaque = true; + aborts_if false; + ensures result == INVALID_ARGUMENT; + } + + /// Create an error of `limit_exceeded`. + public fun limit_exceeded(reason: u64): u64 { make(LIMIT_EXCEEDED, reason) } + spec limit_exceeded { + pragma opaque = true; + aborts_if false; + ensures result == LIMIT_EXCEEDED; + } + + /// Create an error of `internal`. + public fun internal(reason: u64): u64 { make(INTERNAL, reason) } + spec internal { + pragma opaque = true; + aborts_if false; + ensures result == INTERNAL; + } + + /// Create an error of `deprecated`. + public fun deprecated(reason: u64): u64 { make(DEPRECATED, reason) } + spec deprecated { + pragma opaque = true; + aborts_if false; + ensures result == DEPRECATED; + } + + /// Create an error of `custom`. + public fun custom(reason: u64): u64 { make(CUSTOM, reason) } + spec custom { + pragma opaque = true; + aborts_if false; + ensures result == CUSTOM; + } +} + +} diff --git a/release/v13/sources/Event.move b/release/v13/sources/Event.move new file mode 100644 index 00000000..69fedeac --- /dev/null +++ b/release/v13/sources/Event.move @@ -0,0 +1,95 @@ +address StarcoinFramework { + +/// The Event module defines an `EventHandleGenerator` that is used to create +/// `EventHandle`s with unique GUIDs. It contains a counter for the number +/// of `EventHandle`s it generates. An `EventHandle` is used to count the number of +/// events emitted to a handle and emit events to the event store. +module Event { + use StarcoinFramework::Errors; + use StarcoinFramework::BCS; + use StarcoinFramework::Signer; + use StarcoinFramework::Vector; + + /// A resource representing the counter used to generate uniqueness under each account. There won't be destructor for + /// this resource to guarantee the uniqueness of the generated handle. + struct EventHandleGenerator has key { + // A monotonically increasing counter + counter: u64, + addr: address, + } + + /// A handle for an event such that: + /// 1. Other modules can emit events to this handle. + /// 2. Storage can use this handle to prove the total number of events that happened in the past. + struct EventHandle has store { + /// Total number of events emitted to this event stream. + counter: u64, + /// A globally unique ID for this event stream. + guid: vector, + } + + /// The event generator resource was in an invalid state + const EEVENT_GENERATOR: u64 = 0; + + /// Publishs a new event handle generator. + public fun publish_generator(account: &signer) { + let addr = Signer::address_of(account); + assert!(!exists(addr), Errors::already_published(EEVENT_GENERATOR)); + move_to(account, EventHandleGenerator{ counter: 0, addr }) + } + + /// Derive a fresh unique id by using sender's EventHandleGenerator. The generated vector is indeed unique because it + /// was derived from the hash(sender's EventHandleGenerator || sender_address). This module guarantees that the + /// EventHandleGenerator is only going to be monotonically increased and there's no way to revert it or destroy it. Thus + /// such counter is going to give distinct value for each of the new event stream under each sender. And since we + /// hash it with the sender's address, the result is guaranteed to be globally unique. + fun fresh_guid(counter: &mut EventHandleGenerator): vector { + let sender_bytes = BCS::to_bytes(&counter.addr); + let count_bytes = BCS::to_bytes(&counter.counter); + counter.counter = counter.counter + 1; + + // EventHandleGenerator goes first just in case we want to extend address in the future. + Vector::append(&mut count_bytes, sender_bytes); + + count_bytes + } + + /// Use EventHandleGenerator to generate a unique event handle for `sig` + public fun new_event_handle(account: &signer): EventHandle + acquires EventHandleGenerator { + let addr = Signer::address_of(account); + assert!(exists(addr), Errors::not_published(EEVENT_GENERATOR)); + EventHandle { + counter: 0, + guid: fresh_guid(borrow_global_mut(addr)) + } + } + + /// Emit an event with payload `msg` by using `handle_ref`'s key and counter. + public fun emit_event(handle_ref: &mut EventHandle, msg: T) { + let guid = *&handle_ref.guid; + + write_to_event_store(guid, handle_ref.counter, msg); + handle_ref.counter = handle_ref.counter + 1; + } + + /// Native procedure that writes to the actual event stream in Event store + /// This will replace the "native" portion of EmitEvent bytecode + native fun write_to_event_store(guid: vector, count: u64, msg: T); + + /// Destroy a unique handle. + public fun destroy_handle(handle: EventHandle) { + EventHandle { counter: _, guid: _ } = handle; + } + + // ****************** SPECIFICATIONS ******************* + spec module {} // switch documentation context to module + + spec module { + /// Functions of the event module are mocked out using the intrinsic + /// pragma. They are implemented in the prover's prelude. + pragma intrinsic = true; + } +} + +} diff --git a/release/v13/sources/EventUtil.move b/release/v13/sources/EventUtil.move new file mode 100644 index 00000000..1ecfceb5 --- /dev/null +++ b/release/v13/sources/EventUtil.move @@ -0,0 +1,36 @@ +module StarcoinFramework::EventUtil { + use StarcoinFramework::Event; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + const ERR_INIT_REPEATE: u64 = 101; + const ERR_RESOURCE_NOT_EXISTS: u64 = 102; + + struct EventHandleWrapper has key { + handle: Event::EventHandle, + } + + public fun init_event(sender: &signer) { + let broker = Signer::address_of(sender); + assert!(!exists>(broker), Errors::invalid_state(ERR_INIT_REPEATE)); + move_to(sender, EventHandleWrapper { + handle: Event::new_event_handle(sender) + }); + } + + public fun uninit_event(sender: &signer) acquires EventHandleWrapper { + let broker = Signer::address_of(sender); + assert!(exists>(broker), Errors::invalid_state(ERR_RESOURCE_NOT_EXISTS)); + let EventHandleWrapper { handle } = move_from>(broker); + Event::destroy_handle(handle); + } + + public fun emit_event(broker: address, event: EventT) acquires EventHandleWrapper { + let event_handle = borrow_global_mut>(broker); + Event::emit_event(&mut event_handle.handle, event); + } + + public fun exist_event(broker: address): bool { + exists>(broker) + } +} diff --git a/release/v13/sources/FixedPoint32.move b/release/v13/sources/FixedPoint32.move new file mode 100644 index 00000000..0cf4450c --- /dev/null +++ b/release/v13/sources/FixedPoint32.move @@ -0,0 +1,157 @@ +address StarcoinFramework { +/// The module provide operations for FixedPoint32. +module FixedPoint32 { + + use StarcoinFramework::Errors; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// Define a fixed-point numeric type with 32 fractional bits. + /// This is just a u64 integer but it is wrapped in a struct to + /// make a unique type. + struct FixedPoint32 has copy, drop, store { value: u64 } + + const MAX_U64: u128 = 18446744073709551615; + + /// The denominator provided was zero + const EDENOMINATOR: u64 = 101; + /// The quotient value would be too large to be held in a `u64` + const EDIVISION: u64 = 102; + /// The multiplied value would be too large to be held in a `u64` + const EMULTIPLICATION: u64 = 103; + /// A division by zero was encountered + const EDIVISION_BY_ZERO: u64 = 104; + /// The computed ratio when converting to a `FixedPoint32` would be unrepresentable + const ERATIO_OUT_OF_RANGE: u64 = 105; + + /// Multiply a u64 integer by a fixed-point number, truncating any + /// fractional part of the product. This will abort if the product + /// overflows. + public fun multiply_u64(val: u64, multiplier: FixedPoint32): u64 { + // The product of two 64 bit values has 128 bits, so perform the + // multiplication with u128 types and keep the full 128 bit product + // to avoid losing accuracy. + let unscaled_product = (val as u128) * (multiplier.value as u128); + // The unscaled product has 32 fractional bits (from the multiplier) + // so rescale it by shifting away the low bits. + let product = unscaled_product >> 32; + // Check whether the value is too large. + assert!(product <= MAX_U64, Errors::limit_exceeded(EMULTIPLICATION)); + (product as u64) + } + spec multiply_u64 { + /// Currently, we ignore the actual implementation of this function in verification + /// and treat it as uninterpreted, which simplifies the verification problem significantly. + /// This way we avoid the non-linear arithmetic problem presented by this function. + /// + /// Abstracting this and related functions is possible because the correctness of currency + /// conversion (where `FixedPoint32` is used for) is not relevant for the rest of the contract + /// control flow, so we can assume some arbitrary (but fixed) behavior here. + pragma opaque = true; + include MultiplyAbortsIf; + ensures result == spec_multiply_u64(val, multiplier); + } + spec schema MultiplyAbortsIf { + val: num; + multiplier: FixedPoint32; + aborts_if spec_multiply_u64(val, multiplier) > MAX_U64 with Errors::LIMIT_EXCEEDED; + } + spec fun spec_multiply_u64(val: num, multiplier: FixedPoint32): num { + (val * multiplier.value) >> 32 + } + + /// Divide a u64 integer by a fixed-point number, truncating any + /// fractional part of the quotient. This will abort if the divisor + /// is zero or if the quotient overflows. + public fun divide_u64(val: u64, divisor: FixedPoint32): u64 { + // Check for division by zero. + assert!(divisor.value != 0, Errors::invalid_argument(EDIVISION_BY_ZERO)); + // First convert to 128 bits and then shift left to + // add 32 fractional zero bits to the dividend. + let scaled_value = (val as u128) << 32; + let quotient = scaled_value / (divisor.value as u128); + // Check whether the value is too large. + assert!(quotient <= MAX_U64, Errors::limit_exceeded(EDIVISION)); + // the value may be too large, which will cause the cast to fail + // with an arithmetic error. + (quotient as u64) + } + spec divide_u64 { + /// See comment at `Self::multiply_64`. + pragma opaque = true; + include DivideAbortsIf; + ensures result == spec_divide_u64(val, divisor); + } + spec schema DivideAbortsIf { + val: num; + divisor: FixedPoint32; + aborts_if divisor.value == 0 with Errors::INVALID_ARGUMENT; + aborts_if spec_divide_u64(val, divisor) > MAX_U64 with Errors::LIMIT_EXCEEDED; + } + spec fun spec_divide_u64(val: num, divisor: FixedPoint32): num { + (val << 32) / divisor.value + } + + /// Create a fixed-point value from a rational number specified by its + /// numerator and denominator. This function is for convenience; it is also + /// perfectly fine to create a fixed-point value by directly specifying the + /// raw value. This will abort if the denominator is zero or if the ratio is + /// not in the range 2^-32 .. 2^32-1. + public fun create_from_rational(numerator: u64, denominator: u64): FixedPoint32 { + // If the denominator is zero, this will abort. + // Scale the numerator to have 64 fractional bits and the denominator + // to have 32 fractional bits, so that the quotient will have 32 + // fractional bits. + let scaled_numerator = (numerator as u128) << 64; + let scaled_denominator = (denominator as u128) << 32; + assert!(scaled_denominator != 0, Errors::invalid_argument(EDENOMINATOR)); + let quotient = scaled_numerator / scaled_denominator; + assert!(quotient != 0 || numerator == 0, Errors::invalid_argument(ERATIO_OUT_OF_RANGE)); + // Return the quotient as a fixed-point number. We first need to check whether the cast + // can succeed. + assert!(quotient <= MAX_U64, Errors::limit_exceeded(ERATIO_OUT_OF_RANGE)); + FixedPoint32 { value: (quotient as u64) } + } + spec create_from_rational { + /// See comment at `Self::multiply_64`. + pragma verify = false; + pragma opaque = true; + include CreateFromRationalAbortsIf; + ensures result == spec_create_from_rational(numerator, denominator); + } + spec schema CreateFromRationalAbortsIf { + numerator: u64; + denominator: u64; + let scaled_numerator = numerator << 64; + let scaled_denominator = denominator << 32; + let quotient = scaled_numerator / scaled_denominator; + aborts_if scaled_denominator == 0 with Errors::INVALID_ARGUMENT; + aborts_if quotient == 0 && scaled_numerator != 0 with Errors::INVALID_ARGUMENT; + aborts_if quotient > MAX_U64 with Errors::LIMIT_EXCEEDED; + } + spec fun spec_create_from_rational(numerator: num, denominator: num): FixedPoint32 { + FixedPoint32{value: (numerator << 64) / (denominator << 32)} + } + + /// create a fixedpoint 32 from u64. + public fun create_from_raw_value(value: u64): FixedPoint32 { + FixedPoint32 { value } + } + spec create_from_raw_value { + pragma opaque; + aborts_if false; + ensures result.value == value; + } + + /// Accessor for the raw u64 value. Other less common operations, such as + /// adding or subtracting FixedPoint32 values, can be done using the raw + /// values directly. + public fun get_raw_value(num: FixedPoint32): u64 { + num.value + } +} + +} diff --git a/release/v13/sources/FlexiDagConfig.move b/release/v13/sources/FlexiDagConfig.move new file mode 100644 index 00000000..b7c6cf8c --- /dev/null +++ b/release/v13/sources/FlexiDagConfig.move @@ -0,0 +1,55 @@ +address StarcoinFramework { + module FlexiDagConfig { + + use StarcoinFramework::Config; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Signer; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict; + } + + /// The struct to hold all config data needed for Flexidag. + struct FlexiDagConfig has copy, drop, store { + // todo: double check, epoch might be better? + // the height of dag genesis block + effective_height: u64, + } + + /// Create a new configuration for flexidag, mainly used in DAO. + public fun new_flexidag_config(effective_height: u64): FlexiDagConfig { + FlexiDagConfig { + effective_height, + } + } + + public fun initialize(account: &signer, effective_height: u64) { + CoreAddresses::assert_genesis_address(account); + Config::publish_new_config(account, new_flexidag_config(effective_height)) + } + + spec initialize { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists>(Signer::address_of(account)); + aborts_if + exists>( + Signer::address_of(account), + ); + ensures exists>(Signer::address_of(account)); + ensures + exists>( + Signer::address_of(account), + ); + } + + public fun effective_height(account: address): u64 { + let flexi_dag_config = Config::get_by_address(account); + flexi_dag_config.effective_height + } + + spec effective_height { + include Config::AbortsIfConfigNotExist { addr: account }; + } + } +} diff --git a/release/v13/sources/FromBCS.move b/release/v13/sources/FromBCS.move new file mode 100644 index 00000000..8f6376a0 --- /dev/null +++ b/release/v13/sources/FromBCS.move @@ -0,0 +1,85 @@ +/// This module provides a number of functions to convert _primitive_ types from their representation in `std::bcs` +/// to values. This is the opposite of `bcs::to_bytes`. Note that it is not safe to define a generic public `from_bytes` +/// function because this can violate implicit struct invariants, therefore only primitive types are offerred. If +/// a general conversion back-and-force is needed, consider the `StarcoinFramework::Any` type which preserves invariants. +/// +/// Example: +/// ``` +/// use std::bcs; +/// use StarcoinFramework::from_bcs; +/// +/// assert!(from_bcs::to_address(bcs::to_bytes(&@0xabcdef)) == @0xabcdef, 0); +/// ``` +module StarcoinFramework::FromBCS { + //use std::string::{Self, String}; + + /// UTF8 check failed in conversion from bytes to string + const EINVALID_UTF8: u64 = 0x1; + + public fun to_bool(v: vector): bool { + from_bytes(v) + } + + public fun to_u8(v: vector): u8 { + from_bytes(v) + } + + public fun to_u64(v: vector): u64 { + from_bytes(v) + } + + public fun to_u128(v: vector): u128 { + from_bytes(v) + } + + public fun to_address(v: vector): address { + from_bytes
(v) + } + + // public fun to_string(v: vector): vector { + // // To make this safe, we need to evaluate the utf8 invariant. + // let s = from_bytes(v); + // assert!(string::internal_check_utf8(string::bytes(&s)), EINVALID_UTF8); + // s + // } + + /// Package private native function to deserialize a type T. + /// + /// Note that this function does not put any constraint on `T`. If code uses this function to + /// deserialize a linear value, its their responsibility that the data they deserialize is + /// owned. + public(friend) native fun from_bytes(bytes: vector): T; + + spec from_bytes { + pragma opaque; // internal + } + + // friend StarcoinFramework::any; + // friend StarcoinFramework::copyable_any; + + + #[test_only] + use StarcoinFramework::BCS; + #[test_only] + use StarcoinFramework::Debug; + + #[test] + fun test_address() { + let addr = @0x1; + //let addr_vec = x"0000000000000000000000000000000000000000000000000000000000000001"; + let addr_vec = x"00000000000000000000000000000001"; + let addr_out = to_address(addr_vec); + let addr_vec_out = BCS::to_bytes(&addr_out); + Debug::print(&addr); + Debug::print(&addr_vec_out); + assert!(addr == addr_out, 0); + assert!(addr_vec == addr_vec_out, 1); + } + + #[test] + #[expected_failure(abort_code = 0x10001, location = Self)] + fun test_address_fail() { + let bad_vec = b"01"; + to_address(bad_vec); + } +} diff --git a/release/v13/sources/GasSchedule.move b/release/v13/sources/GasSchedule.move new file mode 100644 index 00000000..dc57048d --- /dev/null +++ b/release/v13/sources/GasSchedule.move @@ -0,0 +1,355 @@ +address StarcoinFramework { +/// Gas schedule configuration. +module GasSchedule { + use StarcoinFramework::Vector; + use StarcoinFramework::ChainId; + use StarcoinFramework::Config; + use StarcoinFramework::CoreAddresses; + spec module { + pragma verify = false; + pragma aborts_if_is_strict; + } + + struct GasEntry has store, copy, drop { + key: vector, + val: u64, + } + + struct GasSchedule has copy, drop, store, key { + entries: vector, + } + + /// The `GasCost` tracks: + /// - instruction cost: how much time/computational power is needed to perform the instruction + /// - memory cost: how much memory is required for the instruction, and storage overhead + public fun gas_schedule(): vector { + let table = Vector::empty(); + + // instruction_schedule + // POP + Vector::push_back(&mut table, new_gas_entry(b"instr.pop", 1, 1)); + // RET + Vector::push_back(&mut table, new_gas_entry(b"instr.ret", 638, 1)); + // BR_TRUE + Vector::push_back(&mut table, new_gas_entry(b"instr.br_true", 1, 1)); + // BR_FALSE + Vector::push_back(&mut table, new_gas_entry(b"instr.br_false", 1, 1)); + // BRANCH + Vector::push_back(&mut table, new_gas_entry(b"instr.branch", 1, 1)); + // LD_U64 + Vector::push_back(&mut table, new_gas_entry(b"instr.ld_u64", 1, 1)); + // LD_CONST + Vector::push_back(&mut table, new_gas_entry(b"instr.ld_const.per_byte", 1, 1)); + // LD_TRUE + Vector::push_back(&mut table, new_gas_entry(b"instr.ld_true", 1, 1)); + // LD_FALSE + Vector::push_back(&mut table, new_gas_entry(b"instr.ld_false", 1, 1)); + // COPY_LOC + Vector::push_back(&mut table, new_gas_entry(b"instr.copy_loc.per_abs_mem_unit", 1, 1)); + // MOVE_LOC + Vector::push_back(&mut table, new_gas_entry(b"instr.move_loc.per_abs_mem_unit", 1, 1)); + // ST_LOC + Vector::push_back(&mut table, new_gas_entry(b"instr.st_loc.per_abs_mem_unit", 1, 1)); + // MUT_BORROW_LOC + Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_loc", 2, 1)); + // IMM_BORROW_LOC + Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_loc", 1, 1)); + // MUT_BORROW_FIELD + Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_field", 1, 1)); + // IMM_BORROW_FIELD + Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_field", 1, 1)); + // CALL + Vector::push_back(&mut table, new_gas_entry(b"instr.call.per_arg", 1132, 1)); + // PACK + Vector::push_back(&mut table, new_gas_entry(b"instr.pack.per_abs_mem_unit", 2, 1)); + // UNPACK + Vector::push_back(&mut table, new_gas_entry(b"instr.unpack.per_abs_mem_unit", 2, 1)); + // READ_REF + Vector::push_back(&mut table, new_gas_entry(b"instr.read_ref.per_abs_mem_unit", 1, 1)); + // WRITE_REF + Vector::push_back(&mut table, new_gas_entry(b"instr.write_ref.per_abs_mem_unit", 1, 1)); + // ADD + Vector::push_back(&mut table, new_gas_entry(b"instr.add", 1, 1)); + // SUB + Vector::push_back(&mut table, new_gas_entry(b"instr.sub", 1, 1)); + // MUL + Vector::push_back(&mut table, new_gas_entry(b"instr.mul", 1, 1)); + // MOD + Vector::push_back(&mut table, new_gas_entry(b"instr.mod", 1, 1)); + // DIV + Vector::push_back(&mut table, new_gas_entry(b"instr.div", 3, 1)); + // BIT_OR + Vector::push_back(&mut table, new_gas_entry(b"instr.bit_or", 2, 1)); + // BIT_AND + Vector::push_back(&mut table, new_gas_entry(b"instr.bit_and", 2, 1)); + // XOR + Vector::push_back(&mut table, new_gas_entry(b"instr.xor", 1, 1)); + // OR + Vector::push_back(&mut table, new_gas_entry(b"instr.or", 2, 1)); + // AND + Vector::push_back(&mut table, new_gas_entry(b"instr.and", 1, 1)); + // NOT + Vector::push_back(&mut table, new_gas_entry(b"instr.not", 1, 1)); + // EQ + Vector::push_back(&mut table, new_gas_entry(b"instr.eq.per_abs_mem_unit", 1, 1)); + // NEQ + Vector::push_back(&mut table, new_gas_entry(b"instr.neq.per_abs_mem_unit", 1, 1)); + // LT + Vector::push_back(&mut table, new_gas_entry(b"instr.lt", 1, 1)); + // GT + Vector::push_back(&mut table, new_gas_entry(b"instr.gt", 1, 1)); + // LE + Vector::push_back(&mut table, new_gas_entry(b"instr.le", 2, 1)); + // GE + Vector::push_back(&mut table, new_gas_entry(b"instr.ge", 1, 1)); + // ABORT + Vector::push_back(&mut table, new_gas_entry(b"instr.abort", 1, 1)); + // NOP + Vector::push_back(&mut table, new_gas_entry(b"instr.nop", 1, 1)); + // EXISTS + Vector::push_back(&mut table, new_gas_entry(b"instr.exists.per_abs_mem_unit", 41, 1)); + // MUT_BORROW_GLOBAL + Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_global.per_abs_mem_unit", 21, 1)); + // IML_BORROW_GLOBAL + Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_global.per_abs_mem_unit", 23, 1)); + // MOVE_FROM + Vector::push_back(&mut table, new_gas_entry(b"instr.move_from.per_abs_mem_unit", 459, 1)); + // MOVE_TO + Vector::push_back(&mut table, new_gas_entry(b"instr.move_to.per_abs_mem_unit", 13, 1)); + // FREEZE_REF + Vector::push_back(&mut table, new_gas_entry(b"instr.freeze_ref", 1, 1)); + // SHL + Vector::push_back(&mut table, new_gas_entry(b"instr.shl", 2, 1)); + // SHR + Vector::push_back(&mut table, new_gas_entry(b"instr.shr", 1, 1)); + // LD_U8 + Vector::push_back(&mut table, new_gas_entry(b"instr.ld_u8", 1, 1)); + // LD_U128 + Vector::push_back(&mut table, new_gas_entry(b"instr.ld_u128", 1, 1)); + + // CAST_U8 + Vector::push_back(&mut table, new_gas_entry(b"instr.cast_u8", 2, 1)); + // CAST_U64 + Vector::push_back(&mut table, new_gas_entry(b"instr.cast_u64", 1, 1)); + // CAST_U128 + Vector::push_back(&mut table, new_gas_entry(b"instr.cast_u128", 1, 1)); + // MUT_BORORW_FIELD_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_field_generic.base", 1, 1)); + // IMM_BORORW_FIELD_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_field_generic.base", 1, 1)); + // CALL_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.call_generic.per_arg", 582, 1)); + // PACK_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.pack_generic.per_abs_mem_unit", 2, 1)); + // UNPACK_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.unpack_generic.per_abs_mem_unit", 2, 1)); + // EXISTS_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.exists_generic.per_abs_mem_unit", 34, 1)); + // MUT_BORROW_GLOBAL_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.mut_borrow_global_generic.per_abs_mem_unit", 15, 1)); + // IMM_BORROW_GLOBAL_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.imm_borrow_global_generic.per_abs_mem_unit", 14, 1)); + // MOVE_FROM_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.move_from_generic.per_abs_mem_unit", 13, 1)); + // MOVE_TO_GENERIC + Vector::push_back(&mut table, new_gas_entry(b"instr.move_to_generic.per_abs_mem_unit", 27, 1)); + + // VEC_PACK + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_pack.per_elem", 84, 1)); + // VEC_LEN + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_len.base", 98, 1)); + // VEC_IMM_BORROW + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_imm_borrow.base", 1334, 1)); + // VEC_MUT_BORROW + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_mut_borrow.base", 1902, 1)); + // VEC_PUSH_BACK + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_push_back.per_abs_mem_unit", 53, 1)); + // VEC_POP_BACK + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_pop_back.base", 227, 1)); + // VEC_UNPACK + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_unpack.per_expected_elem", 572, 1)); + // VEC_SWAP + Vector::push_back(&mut table, new_gas_entry(b"instr.vec_swap.base", 1436, 1)); + + Vector::push_back(&mut table, new_constant_entry(b"instr.ld_u16", 3)); + Vector::push_back(&mut table, new_constant_entry(b"instr.ld_u32", 2)); + Vector::push_back(&mut table, new_constant_entry(b"instr.ld_u256", 3)); + Vector::push_back(&mut table, new_constant_entry(b"instr.cast_u16", 3)); + Vector::push_back(&mut table, new_constant_entry(b"instr.cast_u32", 2)); + Vector::push_back(&mut table, new_constant_entry(b"instr.cast_u256", 3)); + + // native_schedule + //Hash::sha2_256 0 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.hash.sha2_256.per_byte", 21, 1)); + //Hash::sha3_256 1 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.hash.sha3_256.per_byte", 64, 1)); + //Signature::ed25519_verify 2 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.signature.ed25519_verify.per_byte", 61, 1)); + //ED25519_THRESHOLD_VERIFY 3 this native funciton is deprecated + //Vector::push_back(&mut table, new_gas_entry(b"", 3351, 1)); + //BSC::to_bytes 4 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.bcs.to_bytes.per_byte_serialized", 181, 1)); + //Vector::length 5 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.length.base", 98, 1)); + //Vector::empty 6 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.empty.base", 84, 1)); + //Vector::borrow 7 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.borrow.base", 1334, 1)); + //Vector::borrow_mut 8 + //Vector::push_back(&mut table, new_gas_entry(b"", 1902, 1)); + //Vector::push_back 9 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.push_back.legacy_per_abstract_memory_unit", 53, 1)); + //Vector::pop_back 10 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.pop_back.base", 227, 1)); + //Vector::destory_empty 11 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.destroy_empty.base", 572, 1)); + //Vector::swap 12 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.swap.base", 1436, 1)); + //Signature::ed25519_validate_pubkey 13 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.signature.ed25519_validate_key.per_byte", 26, 1)); + //Signer::borrow_address 14 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.signer.borrow_address.base", 353, 1)); + //Account::creator_signer 15 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.account.create_signer.base", 24, 1)); + //Account::destroy_signer 16 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.account.destroy_signer.base", 212, 1)); + //Event::emit_event 17 + Vector::push_back(&mut table, new_gas_entry(b"nursery.event.write_to_event_store.unit_cost", 52, 1)); + //BCS::to_address 18 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.bcs.to_address.per_byte", 26, 1)); + //Token::name_of 19 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.token.name_of.base", 2002, 1)); + //Hash::keccak_256 20 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.hash.keccak256.per_byte", 64, 1)); + //Hash::ripemd160 21 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.hash.ripemd160.per_byte", 64, 1)); + //Signature::native_ecrecover 22 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.signature.ec_recover.per_byte", 128, 1)); + //U256::from_bytes 23 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.from_bytes.per_byte", 2, 1)); + //U256::add 24 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.add.base", 4, 1)); + //U256::sub 25 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.sub.base", 4, 1)); + //U256::mul 26 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.mul.base", 4, 1)); + //U256::div 27 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.div.base", 10, 1)); + // U256::rem 28 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.rem.base", 4, 1)); + // U256::pow 29 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.u256.pow.base", 8, 1)); + // TODO: settle down the gas cost + // Vector::append 30 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.append.legacy_per_abstract_memory_unit", 40, 1)); + // Vector::remove 31 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.remove.legacy_per_abstract_memory_unit", 20, 1)); + // Vector::reverse 32 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.reverse.legacy_per_abstract_memory_unit", 10, 1)); + // Table::new_table_handle 33 + Vector::push_back(&mut table, new_gas_entry(b"table.new_table_handle.base", 4, 1)); + // Table::add_box 34 + Vector::push_back(&mut table, new_gas_entry(b"table.add_box.per_byte_serialized", 4, 1)); + // Table::borrow_box 35 + Vector::push_back(&mut table, new_gas_entry(b"table.borrow_box.per_byte_serialized", 10, 1)); + // Table::remove_box 36 + Vector::push_back(&mut table, new_gas_entry(b"table.remove_box.per_byte_serialized", 8, 1)); + // Table::contains_box 37 + Vector::push_back(&mut table, new_gas_entry(b"table.contains_box.per_byte_serialized", 40, 1)); + // Table::destroy_empty_box 38 + Vector::push_back(&mut table, new_gas_entry(b"table.destroy_empty_box.base", 20, 1)); + // Table::drop_unchecked_box 39 + Vector::push_back(&mut table, new_gas_entry(b"table.drop_unchecked_box.base", 73, 1)); + // string.check_utf8 40 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.check_utf8.per_byte", 4, 1)); + // string.sub_str 41 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.sub_string.per_byte", 4, 1)); + // string.is_char_boundary 42 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.is_char_boundary.base", 4, 1)); + // Table::string.index_of 43 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.string.index_of.per_byte_searched", 4, 1)); + // Table::string.index_of 44 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.frombcs.base", 4, 1)); + // Table::string.index_of 45 + Vector::push_back(&mut table, new_gas_entry(b"starcoin_natives.secp256k1.base", 4, 1)); + // Table::string.index_of 46 + Vector::push_back(&mut table, new_gas_entry(b"move_stdlib.vector.spawn_from.legacy_per_abstract_memory_unit", 4, 1)); + + Vector::push_back(&mut table, new_constant_entry(b"nursery.debug.print.base_cost", 1)); + Vector::push_back(&mut table, new_constant_entry(b"nursery.debug.print_stack_trace.base_cost", 1)); + Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.hash.sha2_256.legacy_min_input_len", 1)); + Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.hash.sha3_256.legacy_min_input_len", 1)); + Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.bcs.to_bytes.failure", 182)); + Vector::push_back(&mut table, new_constant_entry(b"move_stdlib.bcs.to_bytes.legacy_min_output_size", 1)); + + // constant config values + Vector::push_back(&mut table, new_constant_entry(b"txn.global_memory_per_byte_cost", 4)); + Vector::push_back(&mut table, new_constant_entry(b"txn.global_memory_per_byte_write_cost", 9)); + Vector::push_back(&mut table, new_constant_entry(b"txn.min_transaction_gas_units", 600)); + Vector::push_back(&mut table, new_constant_entry(b"txn.large_transaction_cutoff", 600)); + Vector::push_back(&mut table, new_constant_entry(b"txn.intrinsic_gas_per_byte", 8)); + let maximum_number_of_gas_units: u64 = 40000000;//must less than base_block_gas_limit + if (ChainId::is_test() || ChainId::is_dev() || ChainId::is_halley()) { + maximum_number_of_gas_units = maximum_number_of_gas_units * 10 + }; + Vector::push_back(&mut table, new_constant_entry(b"txn.maximum_number_of_gas_units", maximum_number_of_gas_units)); + Vector::push_back(&mut table, new_constant_entry(b"txn.min_price_per_gas_unit", if (ChainId::is_test()) { 0 } else { 1 })); + Vector::push_back(&mut table, new_constant_entry(b"txn.max_price_per_gas_unit", 10000)); + Vector::push_back(&mut table, new_constant_entry(b"txn.max_transaction_size_in_bytes", 1024 * 128)); + Vector::push_back(&mut table, new_constant_entry(b"txn.gas_unit_scaling_factor", 1)); + Vector::push_back(&mut table, new_constant_entry(b"txn.default_account_size", 800)); + + table + } + + public fun new_gas_entry(key: vector, instr_gas: u64, mem_gas: u64): GasEntry { + GasEntry { + key, + val: instr_gas + mem_gas, + } + } + + fun new_constant_entry(key: vector, val: u64): GasEntry { + GasEntry { + key, + val, + } + } + + /// Initialize the gas schedule under the genesis account + public fun initialize(account: &signer, gas_schedule: GasSchedule) { + CoreAddresses::assert_genesis_address(account); + Config::publish_new_config( + account, + gas_schedule, + ); + } + + public fun new_gas_schedule(): GasSchedule { + GasSchedule { + entries: gas_schedule(), + } + } + + public fun new_gas_schedule_for_test(): GasSchedule { + let entry = GasEntry { + key: Vector::empty(), + val: 1, + }; + let entries = Vector::empty(); + Vector::push_back(&mut entries, entry); + + GasSchedule { + entries, + } + } + + #[test] + fun test_gas_schedule_initialized() { + use StarcoinFramework::Account; + let genesis_account = Account::create_genesis_account(CoreAddresses::GENESIS_ADDRESS()); + Self::initialize(&genesis_account, Self::new_gas_schedule_for_test()); + assert!(Config::config_exist_by_address(CoreAddresses::GENESIS_ADDRESS()), 0); + } +} +} diff --git a/release/v13/sources/Genesis.move b/release/v13/sources/Genesis.move new file mode 100644 index 00000000..368c8699 --- /dev/null +++ b/release/v13/sources/Genesis.move @@ -0,0 +1,560 @@ +address StarcoinFramework { +/// The module for init Genesis +module Genesis { + + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Account; + use StarcoinFramework::Signer; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Token; + use StarcoinFramework::STC::{Self, STC}; + use StarcoinFramework::DummyToken; + use StarcoinFramework::PackageTxnManager; + use StarcoinFramework::ConsensusConfig; + use StarcoinFramework::VMConfig; + use StarcoinFramework::Vector; + use StarcoinFramework::Block; + use StarcoinFramework::TransactionFee; + use StarcoinFramework::BlockReward; + use StarcoinFramework::ChainId; + use StarcoinFramework::ConsensusStrategy; + use StarcoinFramework::TransactionPublishOption; + use StarcoinFramework::Collection; + use StarcoinFramework::TransactionTimeoutConfig; + use StarcoinFramework::Epoch; + use StarcoinFramework::Version; + use StarcoinFramework::Config; + use StarcoinFramework::Option; + use StarcoinFramework::Treasury; + use StarcoinFramework::TreasuryWithdrawDaoProposal; + use StarcoinFramework::StdlibUpgradeScripts; + use StarcoinFramework::GenesisSignerCapability; + use StarcoinFramework::STCUSDOracle; + use StarcoinFramework::GenesisNFT; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_partial = false; + pragma aborts_if_is_strict = true; + } + + + public entry fun initialize( + stdlib_version: u64, + + // block reward config + reward_delay: u64, + + pre_mine_stc_amount: u128, + time_mint_stc_amount: u128, + time_mint_stc_period: u64, + parent_hash: vector, + association_auth_key: vector, + genesis_auth_key: vector, + chain_id: u8, + genesis_timestamp: u64, + + //consensus config + uncle_rate_target: u64, + epoch_block_count: u64, + base_block_time_target: u64, + base_block_difficulty_window: u64, + base_reward_per_block: u128, + base_reward_per_uncle_percent: u64, + min_block_time_target: u64, + max_block_time_target: u64, + base_max_uncles_per_block: u64, + base_block_gas_limit: u64, + strategy: u8, + + //vm config + script_allowed: bool, + module_publishing_allowed: bool, + instruction_schedule: vector, + native_schedule: vector, + + //gas constants + global_memory_per_byte_cost: u64, + global_memory_per_byte_write_cost: u64, + min_transaction_gas_units: u64, + large_transaction_cutoff: u64, + instrinsic_gas_per_byte: u64, + maximum_number_of_gas_units: u64, + min_price_per_gas_unit: u64, + max_price_per_gas_unit: u64, + max_transaction_size_in_bytes: u64, + gas_unit_scaling_factor: u64, + default_account_size: u64, + + // dao config + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + + // transaction timeout config + transaction_timeout: u64, + ) { + assert!(Timestamp::is_genesis(), 1); + // create genesis account + let genesis_account = Account::create_genesis_account(CoreAddresses::GENESIS_ADDRESS()); + //Init global time + Timestamp::initialize(&genesis_account, genesis_timestamp); + ChainId::initialize(&genesis_account, chain_id); + ConsensusStrategy::initialize(&genesis_account, strategy); + Block::initialize(&genesis_account, parent_hash); + TransactionPublishOption::initialize( + &genesis_account, + script_allowed, + module_publishing_allowed, + ); + // init config + VMConfig::initialize( + &genesis_account, + instruction_schedule, + native_schedule, + global_memory_per_byte_cost, + global_memory_per_byte_write_cost, + min_transaction_gas_units, + large_transaction_cutoff, + instrinsic_gas_per_byte, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit, + max_transaction_size_in_bytes, + gas_unit_scaling_factor, + default_account_size, + ); + TransactionTimeoutConfig::initialize(&genesis_account, transaction_timeout); + ConsensusConfig::initialize( + &genesis_account, + uncle_rate_target, + epoch_block_count, + base_block_time_target, + base_block_difficulty_window, + base_reward_per_block, + base_reward_per_uncle_percent, + min_block_time_target, + max_block_time_target, + base_max_uncles_per_block, + base_block_gas_limit, + strategy, + ); + Epoch::initialize(&genesis_account); + BlockReward::initialize(&genesis_account, reward_delay); + TransactionFee::initialize(&genesis_account); + let association = Account::create_genesis_account( + CoreAddresses::ASSOCIATION_ROOT_ADDRESS(), + ); + Config::publish_new_config(&genesis_account, Version::new_version(stdlib_version)); + // stdlib use two phase upgrade strategy. + PackageTxnManager::update_module_upgrade_strategy( + &genesis_account, + PackageTxnManager::get_strategy_two_phase(), + Option::some(0u64), + ); + // stc should be initialized after genesis_account's module upgrade strategy set. + { + STC::initialize(&genesis_account, voting_delay, voting_period, voting_quorum_rate, min_action_delay); + Account::do_accept_token(&genesis_account); + DummyToken::initialize(&genesis_account); + Account::do_accept_token(&association); + }; + if (pre_mine_stc_amount > 0) { + let stc = Token::mint(&genesis_account, pre_mine_stc_amount); + Account::deposit(Signer::address_of(&association), stc); + }; + if (time_mint_stc_amount > 0) { + let cap = Token::remove_mint_capability(&genesis_account); + let key = Token::issue_linear_mint_key(&cap, time_mint_stc_amount, time_mint_stc_period); + Token::add_mint_capability(&genesis_account, cap); + Collection::put(&association, key); + }; + // only dev network set genesis auth key. + if (!Vector::is_empty(&genesis_auth_key)) { + let genesis_rotate_key_cap = Account::extract_key_rotation_capability(&genesis_account); + Account::rotate_authentication_key_with_capability(&genesis_rotate_key_cap, genesis_auth_key); + Account::restore_key_rotation_capability(genesis_rotate_key_cap); + }; + let assoc_rotate_key_cap = Account::extract_key_rotation_capability(&association); + Account::rotate_authentication_key_with_capability(&assoc_rotate_key_cap, association_auth_key); + Account::restore_key_rotation_capability(assoc_rotate_key_cap); + //Start time, Timestamp::is_genesis() will return false. this call should at the end of genesis init. + Timestamp::set_time_has_started(&genesis_account); + Account::release_genesis_signer(genesis_account); + Account::release_genesis_signer(association); + } + + public entry fun initialize_v2( + stdlib_version: u64, + + // block reward and stc config + reward_delay: u64, + total_stc_amount: u128, + pre_mine_stc_amount: u128, + time_mint_stc_amount: u128, + time_mint_stc_period: u64, + + parent_hash: vector, + association_auth_key: vector, + genesis_auth_key: vector, + chain_id: u8, + genesis_timestamp: u64, + + //consensus config + uncle_rate_target: u64, + epoch_block_count: u64, + base_block_time_target: u64, + base_block_difficulty_window: u64, + base_reward_per_block: u128, + base_reward_per_uncle_percent: u64, + min_block_time_target: u64, + max_block_time_target: u64, + base_max_uncles_per_block: u64, + base_block_gas_limit: u64, + strategy: u8, + + //vm config + script_allowed: bool, + module_publishing_allowed: bool, + instruction_schedule: vector, + native_schedule: vector, + + //gas constants + global_memory_per_byte_cost: u64, + global_memory_per_byte_write_cost: u64, + min_transaction_gas_units: u64, + large_transaction_cutoff: u64, + instrinsic_gas_per_byte: u64, + maximum_number_of_gas_units: u64, + min_price_per_gas_unit: u64, + max_price_per_gas_unit: u64, + max_transaction_size_in_bytes: u64, + gas_unit_scaling_factor: u64, + default_account_size: u64, + + // dao config + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + + // transaction timeout config + transaction_timeout: u64, + ) { + Self::do_initialize( + stdlib_version, + reward_delay, + total_stc_amount, + pre_mine_stc_amount, + time_mint_stc_amount, + time_mint_stc_period, + parent_hash, + association_auth_key, + genesis_auth_key, + chain_id, + genesis_timestamp, + uncle_rate_target, + epoch_block_count, + base_block_time_target, + base_block_difficulty_window, + base_reward_per_block, + base_reward_per_uncle_percent, + min_block_time_target, + max_block_time_target, + base_max_uncles_per_block, + base_block_gas_limit, + strategy, + script_allowed, + module_publishing_allowed, + instruction_schedule, + native_schedule, + global_memory_per_byte_cost, + global_memory_per_byte_write_cost, + min_transaction_gas_units, + large_transaction_cutoff, + instrinsic_gas_per_byte, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit, + max_transaction_size_in_bytes, + gas_unit_scaling_factor, + default_account_size, + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + transaction_timeout, + ); + } + + fun do_initialize( + stdlib_version: u64, + + // block reward and stc config + reward_delay: u64, + total_stc_amount: u128, + pre_mine_stc_amount: u128, + time_mint_stc_amount: u128, + time_mint_stc_period: u64, + + parent_hash: vector, + association_auth_key: vector, + genesis_auth_key: vector, + chain_id: u8, + genesis_timestamp: u64, + + //consensus config + uncle_rate_target: u64, + epoch_block_count: u64, + base_block_time_target: u64, + base_block_difficulty_window: u64, + base_reward_per_block: u128, + base_reward_per_uncle_percent: u64, + min_block_time_target: u64, + max_block_time_target: u64, + base_max_uncles_per_block: u64, + base_block_gas_limit: u64, + strategy: u8, + + //vm config + script_allowed: bool, + module_publishing_allowed: bool, + instruction_schedule: vector, + native_schedule: vector, + + //gas constants + global_memory_per_byte_cost: u64, + global_memory_per_byte_write_cost: u64, + min_transaction_gas_units: u64, + large_transaction_cutoff: u64, + instrinsic_gas_per_byte: u64, + maximum_number_of_gas_units: u64, + min_price_per_gas_unit: u64, + max_price_per_gas_unit: u64, + max_transaction_size_in_bytes: u64, + gas_unit_scaling_factor: u64, + default_account_size: u64, + + // dao config + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + + // transaction timeout config + transaction_timeout: u64, + ){ + Timestamp::assert_genesis(); + // create genesis account + let genesis_account = Account::create_genesis_account(CoreAddresses::GENESIS_ADDRESS()); + //Init global time + Timestamp::initialize(&genesis_account, genesis_timestamp); + ChainId::initialize(&genesis_account, chain_id); + ConsensusStrategy::initialize(&genesis_account, strategy); + Block::initialize(&genesis_account, parent_hash); + TransactionPublishOption::initialize( + &genesis_account, + script_allowed, + module_publishing_allowed, + ); + // init config + VMConfig::initialize( + &genesis_account, + instruction_schedule, + native_schedule, + global_memory_per_byte_cost, + global_memory_per_byte_write_cost, + min_transaction_gas_units, + large_transaction_cutoff, + instrinsic_gas_per_byte, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit, + max_transaction_size_in_bytes, + gas_unit_scaling_factor, + default_account_size, + ); + TransactionTimeoutConfig::initialize(&genesis_account, transaction_timeout); + ConsensusConfig::initialize( + &genesis_account, + uncle_rate_target, + epoch_block_count, + base_block_time_target, + base_block_difficulty_window, + base_reward_per_block, + base_reward_per_uncle_percent, + min_block_time_target, + max_block_time_target, + base_max_uncles_per_block, + base_block_gas_limit, + strategy, + ); + Epoch::initialize(&genesis_account); + let association = Account::create_genesis_account( + CoreAddresses::ASSOCIATION_ROOT_ADDRESS(), + ); + Config::publish_new_config(&genesis_account, Version::new_version(stdlib_version)); + // stdlib use two phase upgrade strategy. + PackageTxnManager::update_module_upgrade_strategy( + &genesis_account, + PackageTxnManager::get_strategy_two_phase(), + Option::some(0u64), + ); + BlockReward::initialize(&genesis_account, reward_delay); + + // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init. + let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay); + Account::do_accept_token(&genesis_account); + Account::do_accept_token(&association); + + DummyToken::initialize(&genesis_account); + + if (pre_mine_stc_amount > 0) { + let stc = Treasury::withdraw_with_capability(&mut withdraw_cap, pre_mine_stc_amount); + Account::deposit(Signer::address_of(&association), stc); + }; + if (time_mint_stc_amount > 0) { + let liner_withdraw_cap = Treasury::issue_linear_withdraw_capability(&mut withdraw_cap, time_mint_stc_amount, time_mint_stc_period); + Treasury::add_linear_withdraw_capability(&association, liner_withdraw_cap); + }; + + // Lock the TreasuryWithdrawCapability to Dao + TreasuryWithdrawDaoProposal::plugin(&genesis_account, withdraw_cap); + + TransactionFee::initialize(&genesis_account); + + // only test/dev network set genesis auth key. + if (!Vector::is_empty(&genesis_auth_key)) { + let genesis_rotate_key_cap = Account::extract_key_rotation_capability(&genesis_account); + Account::rotate_authentication_key_with_capability(&genesis_rotate_key_cap, genesis_auth_key); + Account::restore_key_rotation_capability(genesis_rotate_key_cap); + }; + + let assoc_rotate_key_cap = Account::extract_key_rotation_capability(&association); + Account::rotate_authentication_key_with_capability(&assoc_rotate_key_cap, association_auth_key); + Account::restore_key_rotation_capability(assoc_rotate_key_cap); + + // v5 -> v6 + { + let cap = Account::remove_signer_capability(&genesis_account); + GenesisSignerCapability::initialize(&genesis_account, cap); + //register oracle + STCUSDOracle::register(&genesis_account); + let merkle_root = x"5969f0e8e19f8769276fb638e6060d5c02e40088f5fde70a6778dd69d659ee6d"; + let image = b"ipfs://QmSPcvcXgdtHHiVTAAarzTeubk5X3iWymPAoKBfiRFjPMY"; + GenesisNFT::initialize(&genesis_account, merkle_root, 1639u64, image); + }; + StdlibUpgradeScripts::do_upgrade_from_v6_to_v7_with_language_version(&genesis_account, 6); + StdlibUpgradeScripts::do_upgrade_from_v11_to_v12(&genesis_account); + StdlibUpgradeScripts::do_upgrade_from_v12_to_v13(&genesis_account); + //Start time, Timestamp::is_genesis() will return false. this call should at the end of genesis init. + Timestamp::set_time_has_started(&genesis_account); + Account::release_genesis_signer(genesis_account); + Account::release_genesis_signer(association); + } + + /// Init the genesis for unit tests + public fun initialize_for_unit_tests(){ + let stdlib_version: u64 = 6; + let reward_delay: u64 = 7; + let total_stc_amount: u128 = 3185136000000000000u128; + let pre_mine_stc_amount: u128 = 159256800000000000u128; + let time_mint_stc_amount: u128 = (85043130u128 * 3u128 + 74213670u128 * 3u128)*1000000000u128; + let time_mint_stc_period: u64 = 1000000000; + + let parent_hash: vector = x"0000000000000000000000000000000000000000000000000000000000000000"; + let association_auth_key: vector = x"0000000000000000000000000000000000000000000000000000000000000000"; + let genesis_auth_key: vector = x"0000000000000000000000000000000000000000000000000000000000000000"; + let chain_id: u8 = 255; + let genesis_timestamp: u64 =0; + + //consensus config + let uncle_rate_target: u64 = 80; + let epoch_block_count: u64 = 240; + let base_block_time_target: u64 = 10000; + let base_block_difficulty_window: u64 = 24; + let base_reward_per_block: u128 = 1000000000; + let base_reward_per_uncle_percent: u64 = 10; + let min_block_time_target: u64 = 1000; + let max_block_time_target: u64 = 20000; + let base_max_uncles_per_block: u64 = 2; + let base_block_gas_limit: u64 = 500000000; + let strategy: u8 = 0; + + //vm config + let script_allowed: bool = true; + let module_publishing_allowed: bool = true; + //TODO init the gas table. + let instruction_schedule: vector = Vector::empty(); + let native_schedule: vector = Vector::empty(); + + //gas constants + let global_memory_per_byte_cost: u64 = 1; + let global_memory_per_byte_write_cost: u64 = 1; + let min_transaction_gas_units: u64 = 1; + let large_transaction_cutoff: u64 = 1; + let instrinsic_gas_per_byte: u64 = 1; + let maximum_number_of_gas_units: u64 = 1; + let min_price_per_gas_unit: u64 = 1; + let max_price_per_gas_unit: u64 = 10000; + let max_transaction_size_in_bytes: u64 = 1024*1024; + let gas_unit_scaling_factor: u64 = 1; + let default_account_size: u64 = 600; + + // dao config + let voting_delay: u64 = 1000; + let voting_period: u64 = 6000; + let voting_quorum_rate: u8 = 4; + let min_action_delay: u64 = 1000; + + // transaction timeout config + let transaction_timeout: u64 = 10000; + + Self::do_initialize( + stdlib_version, + reward_delay, + total_stc_amount, + pre_mine_stc_amount, + time_mint_stc_amount, + time_mint_stc_period, + parent_hash, + association_auth_key, + genesis_auth_key, + chain_id, + genesis_timestamp, + uncle_rate_target, + epoch_block_count, + base_block_time_target, + base_block_difficulty_window, + base_reward_per_block, + base_reward_per_uncle_percent, + min_block_time_target, + max_block_time_target, + base_max_uncles_per_block, + base_block_gas_limit, + strategy, + script_allowed, + module_publishing_allowed, + instruction_schedule, + native_schedule, + global_memory_per_byte_cost, + global_memory_per_byte_write_cost, + min_transaction_gas_units, + large_transaction_cutoff, + instrinsic_gas_per_byte, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit, + max_transaction_size_in_bytes, + gas_unit_scaling_factor, + default_account_size, + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + transaction_timeout, + ); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/GenesisNFT.move b/release/v13/sources/GenesisNFT.move new file mode 100644 index 00000000..a8cc72a0 --- /dev/null +++ b/release/v13/sources/GenesisNFT.move @@ -0,0 +1,82 @@ +module StarcoinFramework::GenesisNFT { + use StarcoinFramework::IdentifierNFT; + use StarcoinFramework::Option::Option; + use StarcoinFramework::NFT::{Self, MintCapability}; + use StarcoinFramework::MerkleNFTDistributor; + use StarcoinFramework::CoreAddresses; + + spec module { + pragma verify = false; + } + + struct GenesisNFT has store{} + struct GenesisNFTMeta has copy, store, drop{ + index: u64 + } + struct GenesisNFTInfo has key, copy, store, drop{ + merkle_root: vector, + total_supply: u64, + } + struct GenesisNFTMintCapability has key{ + cap: MintCapability + } + + public fun initialize(sender: &signer, merkle_root: vector, leafs: u64, image: vector){ + CoreAddresses::assert_genesis_address(sender); + let metadata = NFT::new_meta_with_image(b"StarcoinGenesisNFT", image, b"The starcoin genesis NFT"); + let nft_info = GenesisNFTInfo{merkle_root: *&merkle_root, total_supply: leafs}; + let cap = MerkleNFTDistributor::register(sender, merkle_root, leafs, nft_info, metadata); + move_to(sender, GenesisNFTMintCapability{cap}); + } + + public fun upgrade_to_nft_type_info_v2(sender: &signer) acquires GenesisNFTMintCapability{ + CoreAddresses::assert_genesis_address(sender); + let cap = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + NFT::upgrade_nft_type_info_from_v1_to_v2(sender, &mut cap.cap); + let nft_info = NFT::remove_compat_info(&mut cap.cap); + move_to(sender, nft_info); + } + + public entry fun mint_entry(sender: signer, index: u64, merkle_proof:vector>) + acquires GenesisNFTMintCapability { + mint(&sender, index, merkle_proof); + } + + public fun mint(sender: &signer, index: u64, merkle_proof:vector>) + acquires GenesisNFTMintCapability { + let metadata = NFT::empty_meta(); + let cap = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + let nft = MerkleNFTDistributor::mint_with_cap(sender, &mut cap.cap, CoreAddresses::GENESIS_ADDRESS(), index, metadata, GenesisNFTMeta{index}, GenesisNFT{}, merkle_proof); + IdentifierNFT::grant(&mut cap.cap, sender, nft); + } + + public fun verify(account: address, index: u64, merkle_proof: vector>): bool { + MerkleNFTDistributor::verify_proof(account, CoreAddresses::GENESIS_ADDRESS(), index, merkle_proof) + } + + public fun get_info(owner: address): Option>{ + IdentifierNFT::get_nft_info(owner) + } + + public fun is_minted(index: u64): bool { + let creator = CoreAddresses::GENESIS_ADDRESS(); + MerkleNFTDistributor::is_minted(creator, index) + } + + public fun genesis_nft_info(): GenesisNFTInfo acquires GenesisNFTInfo{ + *borrow_global(CoreAddresses::GENESIS_ADDRESS()) + } +} + +module StarcoinFramework::GenesisNFTScripts { + use StarcoinFramework::GenesisNFT; + + spec module { + pragma verify = false; + } + + /// Mint a GenesisNFT + public entry fun mint(sender: signer, index: u64, merkle_proof:vector>) { + GenesisNFT::mint_entry(sender, index, merkle_proof); + } +} diff --git a/release/v13/sources/GenesisNFTScripts.move b/release/v13/sources/GenesisNFTScripts.move new file mode 100644 index 00000000..a8cc72a0 --- /dev/null +++ b/release/v13/sources/GenesisNFTScripts.move @@ -0,0 +1,82 @@ +module StarcoinFramework::GenesisNFT { + use StarcoinFramework::IdentifierNFT; + use StarcoinFramework::Option::Option; + use StarcoinFramework::NFT::{Self, MintCapability}; + use StarcoinFramework::MerkleNFTDistributor; + use StarcoinFramework::CoreAddresses; + + spec module { + pragma verify = false; + } + + struct GenesisNFT has store{} + struct GenesisNFTMeta has copy, store, drop{ + index: u64 + } + struct GenesisNFTInfo has key, copy, store, drop{ + merkle_root: vector, + total_supply: u64, + } + struct GenesisNFTMintCapability has key{ + cap: MintCapability + } + + public fun initialize(sender: &signer, merkle_root: vector, leafs: u64, image: vector){ + CoreAddresses::assert_genesis_address(sender); + let metadata = NFT::new_meta_with_image(b"StarcoinGenesisNFT", image, b"The starcoin genesis NFT"); + let nft_info = GenesisNFTInfo{merkle_root: *&merkle_root, total_supply: leafs}; + let cap = MerkleNFTDistributor::register(sender, merkle_root, leafs, nft_info, metadata); + move_to(sender, GenesisNFTMintCapability{cap}); + } + + public fun upgrade_to_nft_type_info_v2(sender: &signer) acquires GenesisNFTMintCapability{ + CoreAddresses::assert_genesis_address(sender); + let cap = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + NFT::upgrade_nft_type_info_from_v1_to_v2(sender, &mut cap.cap); + let nft_info = NFT::remove_compat_info(&mut cap.cap); + move_to(sender, nft_info); + } + + public entry fun mint_entry(sender: signer, index: u64, merkle_proof:vector>) + acquires GenesisNFTMintCapability { + mint(&sender, index, merkle_proof); + } + + public fun mint(sender: &signer, index: u64, merkle_proof:vector>) + acquires GenesisNFTMintCapability { + let metadata = NFT::empty_meta(); + let cap = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + let nft = MerkleNFTDistributor::mint_with_cap(sender, &mut cap.cap, CoreAddresses::GENESIS_ADDRESS(), index, metadata, GenesisNFTMeta{index}, GenesisNFT{}, merkle_proof); + IdentifierNFT::grant(&mut cap.cap, sender, nft); + } + + public fun verify(account: address, index: u64, merkle_proof: vector>): bool { + MerkleNFTDistributor::verify_proof(account, CoreAddresses::GENESIS_ADDRESS(), index, merkle_proof) + } + + public fun get_info(owner: address): Option>{ + IdentifierNFT::get_nft_info(owner) + } + + public fun is_minted(index: u64): bool { + let creator = CoreAddresses::GENESIS_ADDRESS(); + MerkleNFTDistributor::is_minted(creator, index) + } + + public fun genesis_nft_info(): GenesisNFTInfo acquires GenesisNFTInfo{ + *borrow_global(CoreAddresses::GENESIS_ADDRESS()) + } +} + +module StarcoinFramework::GenesisNFTScripts { + use StarcoinFramework::GenesisNFT; + + spec module { + pragma verify = false; + } + + /// Mint a GenesisNFT + public entry fun mint(sender: signer, index: u64, merkle_proof:vector>) { + GenesisNFT::mint_entry(sender, index, merkle_proof); + } +} diff --git a/release/v13/sources/GenesisSignerCapability.move b/release/v13/sources/GenesisSignerCapability.move new file mode 100644 index 00000000..618eb536 --- /dev/null +++ b/release/v13/sources/GenesisSignerCapability.move @@ -0,0 +1,39 @@ +module StarcoinFramework::GenesisSignerCapability { + use StarcoinFramework::Account; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + + friend StarcoinFramework::NFT; + friend StarcoinFramework::Oracle; + friend StarcoinFramework::Genesis; + friend StarcoinFramework::StdlibUpgradeScripts; + friend StarcoinFramework::EasyGas; + + const ENOT_GENESIS_ACCOUNT: u64 = 11; + + struct GenesisSignerCapability has key { + cap: Account::SignerCapability, + } + + public(friend) fun initialize(signer: &signer, cap: Account::SignerCapability) { + CoreAddresses::assert_genesis_address(signer); + assert!( + Account::signer_address(&cap) == CoreAddresses::GENESIS_ADDRESS(), + Errors::invalid_argument(ENOT_GENESIS_ACCOUNT) + ); + move_to(signer, GenesisSignerCapability{cap}); + } + + public(friend) fun get_genesis_signer(): signer acquires 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() + } +} \ No newline at end of file diff --git a/release/v13/sources/Hash.move b/release/v13/sources/Hash.move new file mode 100644 index 00000000..df8d473d --- /dev/null +++ b/release/v13/sources/Hash.move @@ -0,0 +1,14 @@ +address StarcoinFramework { +/// The module provide sha-hash functionality for Move. +module Hash { + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + native public fun sha2_256(data: vector): vector; + native public fun sha3_256(data: vector): vector; + native public fun keccak_256(data: vector): vector; + native public fun ripemd160(data: vector): vector; +} + +} diff --git a/release/v13/sources/IdentifierNFT.move b/release/v13/sources/IdentifierNFT.move new file mode 100644 index 00000000..d1ac25f8 --- /dev/null +++ b/release/v13/sources/IdentifierNFT.move @@ -0,0 +1,1023 @@ +address StarcoinFramework { +/// Non-fungible token standard and implementations. +module NFT { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Account; + use StarcoinFramework::Vector; + use StarcoinFramework::Event; + use StarcoinFramework::GenesisSignerCapability; + + const ERR_NO_MINT_CAPABILITY: u64 = 101; + const ERR_NO_BURN_CAPABILITY: u64 = 102; + const ERR_NO_UPDATE_CAPABILITY: u64 = 103; + const ERR_CANOT_EMPTY: u64 = 104; + const ERR_NFT_TYPE_ALREADY_REGISTERED: u64 = 105; + const ERR_NFT_TYPE_NO_REGISTERED: u64 = 106; + + spec module { + pragma verify = false; + } + + struct MintEvent has drop, store { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + struct BurnEvent has drop, store { + id: u64, + } + + /// The info of NFT type, this type is deprecated, please use NFTTypeInfoV2 + struct NFTTypeInfo has key, store { + counter: u64, + meta: Metadata, + info: NFTTypeInfoExt, + mint_events: Event::EventHandle>, + } + + /// The info of NFT type + struct NFTTypeInfoV2 has key, store { + register: address, + counter: u64, + meta: Metadata, + mint_events: Event::EventHandle>, + burn_events: Event::EventHandle>, + } + + struct NFTTypeInfoCompat has key { + info: NFTTypeInfoExt, + } + + /// Deprecated. Use `new_nft_type_info_v2` instead. + fun new_nft_type_info( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ): NFTTypeInfo { + NFTTypeInfo { + counter: 0, + info, + meta, + mint_events: Event::new_event_handle>(sender), + } + } + + fun new_nft_type_info_v2(sender: &signer, meta: Metadata): NFTTypeInfoV2 { + NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter: 0, + meta, + mint_events: Event::new_event_handle>(sender), + burn_events: Event::new_event_handle>(sender), + } + } + + /// Note: this function is deprecated + public fun nft_type_info_ex_info( + ): NFTTypeInfoExt acquires NFTTypeInfo, NFTTypeInfoCompat { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } + } + + /// Note: this function is deprecated, please use nft_type_info_counter_v2 + public fun nft_type_info_counter( + ): u64 acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + Self::nft_type_info_counter_v2() + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + } + + public fun nft_type_info_counter_v2(): u64 acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + + public fun nft_type_info_meta(): Metadata acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.meta + } + + public fun upgrade_nft_type_info_from_v1_to_v2( + sender: &signer, + _cap: &mut MintCapability + ) acquires NFTTypeInfo { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfo { counter, meta, info, mint_events } = nft_type_info; + + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let nft_type_info_v2 = NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter, + meta, + mint_events, + burn_events: Event::new_event_handle>(sender), + }; + move_to(&genesis_account, nft_type_info_v2); + move_to(&genesis_account, NFTTypeInfoCompat { info }); + } + } + + public fun remove_compat_info( + _cap: &mut MintCapability + ): NFTTypeInfoExt acquires NFTTypeInfoCompat { + let compat_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfoCompat{info} = compat_info; + info + } + /// deprecated. + struct GenesisSignerCapability has key { + cap: Account::SignerCapability, + } + /// The capability to mint the nft. + struct MintCapability has key, store {} + /// The Capability to burn the nft. + struct BurnCapability has key, store {} + /// The Capability to update the nft metadata. + struct UpdateCapability has key, store {} + + struct Metadata has copy, store, drop { + /// NFT name's utf8 bytes. + name: vector, + /// Image link, such as ipfs://xxxx + image: vector, + /// Image bytes data, image or image_data can not empty for both. + image_data: vector, + /// NFT description utf8 bytes. + description: vector, + } + + public fun empty_meta(): Metadata { + Metadata { + name: Vector::empty(), + image: Vector::empty(), + image_data: Vector::empty(), + description: Vector::empty(), + } + } + + public fun new_meta(name: vector, description: vector): Metadata { + Metadata { + name, + image: Vector::empty(), + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image(name: vector, image: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image, + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image_data(name: vector, image_data: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image_data), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image: Vector::empty(), + image_data, + description, + } + } + + public fun meta_name(metadata: &Metadata): vector { + *&metadata.name + } + + public fun meta_image(metadata: &Metadata): vector { + *&metadata.image + } + + public fun meta_image_data(metadata: &Metadata): vector { + *&metadata.image_data + } + + public fun meta_description(metadata: &Metadata): vector { + *&metadata.description + } + + struct NFT has store { + /// The creator of NFT + creator: address, + /// The unique id of NFT under NFTMeta type + id: u64, + /// The metadata of NFT + base_meta: Metadata, + /// The extension metadata of NFT + type_meta: NFTMeta, + /// The body of NFT, NFT is a box for NFTBody + body: NFTBody, + } + + /// The information of NFT instance return by get_nft_info + struct NFTInfo has copy, store, drop { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + public fun get_info(nft: &NFT): NFTInfo { + NFTInfo { + id: nft.id, + creator: nft.creator, + base_meta: *&nft.base_meta, + type_meta: *&nft.type_meta, + } + } + + public fun unpack_info( + nft_info: NFTInfo + ): (u64, address, Metadata, NFTMeta) { + let NFTInfo { id, creator, base_meta, type_meta } = nft_info; + (id, creator, base_meta, type_meta) + } + + public fun get_id(nft: &NFT): u64 { + return nft.id + } + + public fun get_base_meta(nft: &NFT): &Metadata { + return &nft.base_meta + } + + public fun get_type_meta(nft: &NFT): &NFTMeta { + return &nft.type_meta + } + + public fun get_creator(nft: &NFT): address { + return nft.creator + } + + /// deprecated. + public fun initialize(_signer: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, + /// in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability { + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register a NFT type to genesis + /// Note: this function is deprecated, please use `register_v2` + public fun register( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ) acquires NFTTypeInfo { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + let type_info = new_nft_type_info(sender, info, meta); + move_to>(&genesis_account, type_info); + let mint_cap = MintCapability {}; + + Self::upgrade_nft_type_info_from_v1_to_v2(sender, &mut mint_cap); + + move_to>(sender, mint_cap); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Register a NFT type to genesis + public fun register_v2(sender: &signer, meta: Metadata) { + assert!(!is_registered(), Errors::invalid_argument(ERR_NFT_TYPE_ALREADY_REGISTERED)); + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let type_info = new_nft_type_info_v2(sender, meta); + move_to>(&genesis_account, type_info); + move_to>(sender, MintCapability {}); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Check the NFTMeta is register + public fun is_registered(): bool { + exists>(CoreAddresses::GENESIS_ADDRESS()) + } + + /// deprecated. Use "is_registered" instead. + public fun is_register(): bool { + is_registered() + } + + /// Add MintCapability to `sender` + public fun add_mint_capability(sender: &signer, cap: MintCapability) { + move_to(sender, cap); + } + + /// Remove the MintCapability from `sender` + public fun remove_mint_capability( + sender: &signer + ): MintCapability acquires MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the MintCapability + public fun destroy_mint_capability(cap: MintCapability) { + let MintCapability {} = cap; + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + /// Note: this function is deprecated, please use `mint_with_cap_v2` + public fun mint_with_cap( + creator: address, + cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + mint_with_cap_v2(creator, cap, base_meta, type_meta, body) + } else { + let nft_type_info = + borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id: id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + public fun mint_with_cap_v2( + creator: address, + _cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2 { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + + /// Mint nft, the `sender` must have MintCapability + /// Note: this function is deprecated, please use `mint_v2` + public fun mint( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap(addr, cap, base_meta, type_meta, body) + } + + /// Mint nft, the `sender` must have MintCapability + public fun mint_v2( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap_v2(addr, cap, base_meta, type_meta, body) + } + + /// Add BurnCapability to `sender` + public fun add_burn_capability(sender: &signer, cap: BurnCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_burn_capability( + sender: &signer + ): BurnCapability acquires BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the BurnCapability + public fun destroy_burn_capability(cap: BurnCapability) { + let BurnCapability {} = cap; + } + + /// Burn nft with BurnCapability + public fun burn_with_cap( + _cap: &mut BurnCapability, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2 { + let NFT { creator: _, id: id, base_meta: _, type_meta: _, body } = nft; + // only NFTTypeInfoV2 has burn_events EventHandle + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + Event::emit_event(&mut nft_type_info.burn_events, BurnEvent { + id, + }); + }; + body + } + + /// Burn nft, the `sender` must have BurnCapability + public fun burn( + sender: &signer, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2, BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + let cap = borrow_global_mut>(addr); + burn_with_cap(cap, nft) + } + + /// Add UpdateCapability to `sender` + public fun add_update_capability(sender: &signer, cap: UpdateCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_update_capability( + sender: &signer + ): UpdateCapability acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the UpdateCapability + public fun destroy_update_capability(cap: UpdateCapability) { + let UpdateCapability {} = cap; + } + + /// Update the NFTTypeInfoV2 metadata with UpdateCapability + public fun update_nft_type_info_meta_with_cap( + _cap: &mut UpdateCapability, + new_meta: Metadata + ) acquires NFTTypeInfoV2{ + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + info.meta = new_meta; + } + + /// Update the NFTTypeInfoV2 metadata, the `sender` must have UpdateCapability + public fun update_nft_type_info_meta( + sender: &signer, + new_meta: Metadata + ) acquires UpdateCapability, NFTTypeInfoV2 { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_nft_type_info_meta_with_cap(cap, new_meta) + } + + /// Update the nft's base_meta and type_meta with UpdateCapability + public fun update_meta_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT, + base_meta: Metadata, type_meta: NFTMeta + ) { + nft.base_meta = base_meta; + nft.type_meta = type_meta; + } + + /// Update the nft's base_meta and type_meta, the `sender` must have UpdateCapability + public fun update_meta( + sender: &signer, + nft: &mut NFT, + base_meta: Metadata, + type_meta: NFTMeta + ) acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_meta_with_cap(cap, nft, base_meta, type_meta) + } + + /// Borrow NFTBody ref + public fun borrow_body(nft: &NFT): &NFTBody { + &nft.body + } + + /// Borrow NFTBody mut ref for update body with UpdateCapability + public fun borrow_body_mut_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT + ): &mut NFTBody { + &mut nft.body + } +} + +/// IdentifierNFT using NFT as identifier for an on chain account +/// The NFT can not been transfer by owner. +module IdentifierNFT { + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::NFT::{Self, NFT, MintCapability, BurnCapability, UpdateCapability}; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + const ERR_NFT_EXISTS: u64 = 101; + const ERR_NFT_NOT_EXISTS: u64 = 102; + const ERR_NFT_NOT_ACCEPT: u64 = 103; + const ERR_BORROW_ADDR_NOT_SAME: u64 = 104; + + spec module { + pragma verify = false; + } + + struct IdentifierNFT has key { + nft: Option>, + } + + //Used when borrowing or returning NFT, note: there is no drop ability, it must be returned after borrowing + struct BorrowNFT { + nft: NFT, + addr:address + } + + /// Check the `owner` is prepared with IdentifierNFT for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Accept NFT, prepare an empty IdentifierNFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let addr = Signer::address_of(sender); + if (!is_accept(addr)) { + move_to(sender, IdentifierNFT { + nft: Option::none(), + }); + } + } + + /// Destroy the empty IdentifierNFT + public entry fun destroy_empty_entry(sender: signer) acquires IdentifierNFT { + destroy_empty(&sender); + } + + public fun destroy_empty(sender: &signer) acquires IdentifierNFT { + let addr = Signer::address_of(sender); + if (exists>(addr)) { + let id_nft = move_from>(addr); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_none(nft); + } + } + + /// Grant nft as IdentifierNFT to `sender` with MintCapability, sender will auto accept the NFT. + public fun grant( + cap: &mut MintCapability, + sender: &signer, + nft: NFT + ) acquires IdentifierNFT { + Self::accept(sender); + Self::grant_to(cap, Signer::address_of(sender), nft); + } + + /// Grant nft as IdentifierNFT to `receiver` with MintCapability, the receiver should accept the NFT first. + public fun grant_to( + _cap: &mut MintCapability, + receiver: address, + nft: NFT + ) acquires IdentifierNFT { + assert!(exists>(receiver), Errors::not_published(ERR_NFT_NOT_ACCEPT)); + let id_nft = borrow_global_mut>(receiver); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + Option::fill(&mut id_nft.nft, nft); + } + + /// Revoke the NFT from owner. + public fun revoke( + _cap: &mut BurnCapability, + owner: address + ): NFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = move_from>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_some(nft) + } + + /// borrow_out the NFT from owner. + public fun borrow_out( + _cap: &mut UpdateCapability, + owner: address + ): BorrowNFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let id_nft = borrow_global_mut>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let nft = Option::extract(&mut id_nft.nft); + + BorrowNFT{ + nft : nft, + addr: owner + } + } + + /// return_back the NFT to owner. + public fun return_back( + borrownft: BorrowNFT, + ) acquires IdentifierNFT { + + let BorrowNFT{ + nft: nft, + addr: owner + } = borrownft ; + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = borrow_global_mut>(owner); + + Option::fill(&mut id_nft.nft , nft) + } + + public fun borrow_nft( + borrownft:&BorrowNFT + ) : & NFT { + & borrownft.nft + } + + public fun borrow_nft_mut ( + borrownft:&mut BorrowNFT + ) : &mut NFT { + &mut borrownft.nft + } + + /// Check `owner` is owns the IdentifierNFT + public fun owns(owner: address): bool acquires IdentifierNFT { + if (!exists>(owner)) { + return false + }; + let id_nft = borrow_global>(owner); + Option::is_some(&id_nft.nft) + } + /// deprecated. Use `owns()` instead. + public fun is_owns(owner: address): bool acquires IdentifierNFT { + owns(owner) + } + + public fun get_nft_info( + owner: address + ): Option> acquires IdentifierNFT { + if (!exists>(owner)) { + return Option::none>() + }; + let id_nft = borrow_global>(owner); + let info = if (Option::is_some(&id_nft.nft)) { + let nft = Option::borrow(&id_nft.nft); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + info + } +} + +module IdentifierNFTScripts { + use StarcoinFramework::IdentifierNFT; + spec module { + pragma verify = false; + } + + /// Init IdentifierNFT for accept NFT as Identifier. + public entry fun accept(sender: signer) { + IdentifierNFT::accept_entry(sender); + } + + /// Destroy empty IdentifierNFT + public entry fun destroy_empty(sender: signer) { + IdentifierNFT::destroy_empty_entry(sender); + } +} + +/// NFTGallery is user collection of NFT. +module NFTGallery { + use StarcoinFramework::Signer; + use StarcoinFramework::NFT::{Self, NFT}; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::Event; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + + const ERR_NFT_NOT_EXISTS: u64 = 101; + + const ERR_NFTGALLERY_NOT_EXISTS:u64 = 102; + + spec module { + pragma verify = false; + } + + struct WithdrawEvent has drop, store { + owner: address, + id: u64, + } + + struct DepositEvent has drop, store { + owner: address, + id: u64, + } + + struct NFTGallery has key, store { + withdraw_events: Event::EventHandle>, + deposit_events: Event::EventHandle>, + items: vector>, + } + + /// Check the `owner` is prepared with NFTGallery for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Init a NFTGallery to accept NFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let sender_addr = Signer::address_of(sender); + if (!is_accept(sender_addr)) { + let gallery = NFTGallery { + withdraw_events: Event::new_event_handle>(sender), + deposit_events: Event::new_event_handle>(sender), + items: Vector::empty>(), + }; + move_to(sender, gallery); + } + } + + /// Transfer NFT from `sender` to `receiver` + public entry fun transfer_entry( + sender: signer, + id: u64, receiver: address + ) acquires NFTGallery { + transfer(&sender, id, receiver); + } + + public fun transfer( + sender: &signer, + id: u64, + receiver: address + ) acquires NFTGallery { + let nft = withdraw(sender, id); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let nft = Option::destroy_some(nft); + deposit_to(receiver, nft) + } + + /// Get the NFT info by the NFT id. + public fun get_nft_info_by_id( + owner: address, + id: u64 + ): Option> acquires NFTGallery { + if(!is_accept(owner)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(owner); + let idx = find_by_id(&gallery.items, id); + + let info = if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::borrow>(&gallery.items, i); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + return info + } + + /// Get the NFT info by the NFT idx in NFTGallery + public fun get_nft_info_by_idx( + owner: address, + idx: u64 + ): NFT::NFTInfo acquires NFTGallery { + assert!(exists>(owner), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(owner); + let nft = Vector::borrow>(&gallery.items, idx); + NFT::get_info(nft) + } + + /// Get the all NFT info + public fun get_nft_infos( + owner: address + ): vector> acquires NFTGallery { + if(!is_accept(owner)){ + return Vector::empty>() + }; + let gallery = borrow_global_mut>(owner); + let infos = Vector::empty(); + let len = Vector::length(&gallery.items); + let idx = 0; + while (len > idx) { + let nft = Vector::borrow>(&gallery.items, idx); + Vector::push_back(&mut infos, NFT::get_info(nft)); + idx = idx + 1; + }; + infos + } + + /// Deposit nft to `sender` NFTGallery + public fun deposit( + sender: &signer, + nft: NFT + ) acquires NFTGallery { + Self::accept(sender); + let sender_addr = Signer::address_of(sender); + deposit_to(sender_addr, nft) + } + + /// Deposit nft to `receiver` NFTGallery + public fun deposit_to( + receiver: address, + nft: NFT + ) acquires NFTGallery { + assert!(exists>(receiver), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(receiver); + Event::emit_event(&mut gallery.deposit_events, DepositEvent { id: NFT::get_id(&nft), owner: receiver }); + Vector::push_back(&mut gallery.items, nft); + } + + /// Withdraw one nft of NFTMeta from `sender`, caller should ensure at least one NFT in the Gallery. + public fun withdraw_one( + sender: &signer + ): NFT acquires NFTGallery { + let nft = do_withdraw(sender, Option::none()); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + Option::destroy_some(nft) + } + + /// Withdraw nft of NFTMeta and id from `sender` + public fun withdraw( + sender: &signer, + id: u64 + ): Option> acquires NFTGallery { + do_withdraw(sender, Option::some(id)) + } + + /// Withdraw nft of NFTMeta and id from `sender` + fun do_withdraw( + sender: &signer, + id: Option + ): Option> acquires NFTGallery { + let sender_addr = Signer::address_of(sender); + if(!is_accept(sender_addr)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(sender_addr); + let len = Vector::length(&gallery.items); + let nft = if (len == 0) { + Option::none() + } else { + let idx = if (Option::is_some(&id)) { + let id = Option::extract(&mut id); + find_by_id(&gallery.items, id) + } else { + //default withdraw the last nft. + Option::some(len - 1) + }; + + if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::remove>(&mut gallery.items, i); + Event::emit_event( + &mut gallery.withdraw_events, + WithdrawEvent { id: NFT::get_id(&nft), owner: sender_addr } + ); + Option::some(nft) + } else { + Option::none() + } + }; + nft + } + + fun find_by_id( + c: &vector>, + id: u64 + ): Option { + let len = Vector::length(c); + if (len == 0) { + return Option::none() + }; + let idx = len - 1; + loop { + let nft = Vector::borrow(c, idx); + if (NFT::get_id(nft) == id) { + return Option::some(idx) + }; + if (idx == 0) { + return Option::none() + }; + idx = idx - 1; + } + } + + /// Count all NFTs assigned to an owner + public fun count_of(owner: address): u64 acquires NFTGallery { + if(!is_accept(owner)){ + return 0 + }; + let gallery = borrow_global_mut>(owner); + Vector::length(&gallery.items) + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery_entry(sender: signer) acquires NFTGallery { + remove_empty_gallery(&sender); + } + + public fun remove_empty_gallery(sender: &signer) acquires NFTGallery{ + let sender_addr = Signer::address_of(sender); + assert!(exists>(sender_addr), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let NFTGallery {withdraw_events, deposit_events, items} = move_from>(sender_addr); + + Event::destroy_handle>(withdraw_events); + Event::destroy_handle>(deposit_events); + Vector::destroy_empty>(items); + } + + spec remove_empty_gallery { + let sender_addr = Signer::address_of(sender); + aborts_if !exists>(sender_addr); + + let gallery = global>(sender_addr); + aborts_if Vector::length>(gallery.items) > 0; + + ensures !exists>(sender_addr); + } + +} + +module NFTGalleryScripts { + use StarcoinFramework::NFTGallery; + + spec module { + pragma verify = false; + } + + /// Init a NFTGallery for accept NFT + public entry fun accept(sender: signer) { + NFTGallery::accept_entry(sender); + } + /// Transfer NFT with `id` from `sender` to `receiver` + public entry fun transfer( + sender: signer, + id: u64, receiver: address + ) { + NFTGallery::transfer_entry(sender, id, receiver); + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery(sender: signer) { + NFTGallery::remove_empty_gallery_entry(sender); + } +} +} diff --git a/release/v13/sources/IdentifierNFTScripts.move b/release/v13/sources/IdentifierNFTScripts.move new file mode 100644 index 00000000..d1ac25f8 --- /dev/null +++ b/release/v13/sources/IdentifierNFTScripts.move @@ -0,0 +1,1023 @@ +address StarcoinFramework { +/// Non-fungible token standard and implementations. +module NFT { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Account; + use StarcoinFramework::Vector; + use StarcoinFramework::Event; + use StarcoinFramework::GenesisSignerCapability; + + const ERR_NO_MINT_CAPABILITY: u64 = 101; + const ERR_NO_BURN_CAPABILITY: u64 = 102; + const ERR_NO_UPDATE_CAPABILITY: u64 = 103; + const ERR_CANOT_EMPTY: u64 = 104; + const ERR_NFT_TYPE_ALREADY_REGISTERED: u64 = 105; + const ERR_NFT_TYPE_NO_REGISTERED: u64 = 106; + + spec module { + pragma verify = false; + } + + struct MintEvent has drop, store { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + struct BurnEvent has drop, store { + id: u64, + } + + /// The info of NFT type, this type is deprecated, please use NFTTypeInfoV2 + struct NFTTypeInfo has key, store { + counter: u64, + meta: Metadata, + info: NFTTypeInfoExt, + mint_events: Event::EventHandle>, + } + + /// The info of NFT type + struct NFTTypeInfoV2 has key, store { + register: address, + counter: u64, + meta: Metadata, + mint_events: Event::EventHandle>, + burn_events: Event::EventHandle>, + } + + struct NFTTypeInfoCompat has key { + info: NFTTypeInfoExt, + } + + /// Deprecated. Use `new_nft_type_info_v2` instead. + fun new_nft_type_info( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ): NFTTypeInfo { + NFTTypeInfo { + counter: 0, + info, + meta, + mint_events: Event::new_event_handle>(sender), + } + } + + fun new_nft_type_info_v2(sender: &signer, meta: Metadata): NFTTypeInfoV2 { + NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter: 0, + meta, + mint_events: Event::new_event_handle>(sender), + burn_events: Event::new_event_handle>(sender), + } + } + + /// Note: this function is deprecated + public fun nft_type_info_ex_info( + ): NFTTypeInfoExt acquires NFTTypeInfo, NFTTypeInfoCompat { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } + } + + /// Note: this function is deprecated, please use nft_type_info_counter_v2 + public fun nft_type_info_counter( + ): u64 acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + Self::nft_type_info_counter_v2() + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + } + + public fun nft_type_info_counter_v2(): u64 acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + + public fun nft_type_info_meta(): Metadata acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.meta + } + + public fun upgrade_nft_type_info_from_v1_to_v2( + sender: &signer, + _cap: &mut MintCapability + ) acquires NFTTypeInfo { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfo { counter, meta, info, mint_events } = nft_type_info; + + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let nft_type_info_v2 = NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter, + meta, + mint_events, + burn_events: Event::new_event_handle>(sender), + }; + move_to(&genesis_account, nft_type_info_v2); + move_to(&genesis_account, NFTTypeInfoCompat { info }); + } + } + + public fun remove_compat_info( + _cap: &mut MintCapability + ): NFTTypeInfoExt acquires NFTTypeInfoCompat { + let compat_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfoCompat{info} = compat_info; + info + } + /// deprecated. + struct GenesisSignerCapability has key { + cap: Account::SignerCapability, + } + /// The capability to mint the nft. + struct MintCapability has key, store {} + /// The Capability to burn the nft. + struct BurnCapability has key, store {} + /// The Capability to update the nft metadata. + struct UpdateCapability has key, store {} + + struct Metadata has copy, store, drop { + /// NFT name's utf8 bytes. + name: vector, + /// Image link, such as ipfs://xxxx + image: vector, + /// Image bytes data, image or image_data can not empty for both. + image_data: vector, + /// NFT description utf8 bytes. + description: vector, + } + + public fun empty_meta(): Metadata { + Metadata { + name: Vector::empty(), + image: Vector::empty(), + image_data: Vector::empty(), + description: Vector::empty(), + } + } + + public fun new_meta(name: vector, description: vector): Metadata { + Metadata { + name, + image: Vector::empty(), + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image(name: vector, image: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image, + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image_data(name: vector, image_data: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image_data), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image: Vector::empty(), + image_data, + description, + } + } + + public fun meta_name(metadata: &Metadata): vector { + *&metadata.name + } + + public fun meta_image(metadata: &Metadata): vector { + *&metadata.image + } + + public fun meta_image_data(metadata: &Metadata): vector { + *&metadata.image_data + } + + public fun meta_description(metadata: &Metadata): vector { + *&metadata.description + } + + struct NFT has store { + /// The creator of NFT + creator: address, + /// The unique id of NFT under NFTMeta type + id: u64, + /// The metadata of NFT + base_meta: Metadata, + /// The extension metadata of NFT + type_meta: NFTMeta, + /// The body of NFT, NFT is a box for NFTBody + body: NFTBody, + } + + /// The information of NFT instance return by get_nft_info + struct NFTInfo has copy, store, drop { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + public fun get_info(nft: &NFT): NFTInfo { + NFTInfo { + id: nft.id, + creator: nft.creator, + base_meta: *&nft.base_meta, + type_meta: *&nft.type_meta, + } + } + + public fun unpack_info( + nft_info: NFTInfo + ): (u64, address, Metadata, NFTMeta) { + let NFTInfo { id, creator, base_meta, type_meta } = nft_info; + (id, creator, base_meta, type_meta) + } + + public fun get_id(nft: &NFT): u64 { + return nft.id + } + + public fun get_base_meta(nft: &NFT): &Metadata { + return &nft.base_meta + } + + public fun get_type_meta(nft: &NFT): &NFTMeta { + return &nft.type_meta + } + + public fun get_creator(nft: &NFT): address { + return nft.creator + } + + /// deprecated. + public fun initialize(_signer: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, + /// in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability { + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register a NFT type to genesis + /// Note: this function is deprecated, please use `register_v2` + public fun register( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ) acquires NFTTypeInfo { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + let type_info = new_nft_type_info(sender, info, meta); + move_to>(&genesis_account, type_info); + let mint_cap = MintCapability {}; + + Self::upgrade_nft_type_info_from_v1_to_v2(sender, &mut mint_cap); + + move_to>(sender, mint_cap); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Register a NFT type to genesis + public fun register_v2(sender: &signer, meta: Metadata) { + assert!(!is_registered(), Errors::invalid_argument(ERR_NFT_TYPE_ALREADY_REGISTERED)); + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let type_info = new_nft_type_info_v2(sender, meta); + move_to>(&genesis_account, type_info); + move_to>(sender, MintCapability {}); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Check the NFTMeta is register + public fun is_registered(): bool { + exists>(CoreAddresses::GENESIS_ADDRESS()) + } + + /// deprecated. Use "is_registered" instead. + public fun is_register(): bool { + is_registered() + } + + /// Add MintCapability to `sender` + public fun add_mint_capability(sender: &signer, cap: MintCapability) { + move_to(sender, cap); + } + + /// Remove the MintCapability from `sender` + public fun remove_mint_capability( + sender: &signer + ): MintCapability acquires MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the MintCapability + public fun destroy_mint_capability(cap: MintCapability) { + let MintCapability {} = cap; + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + /// Note: this function is deprecated, please use `mint_with_cap_v2` + public fun mint_with_cap( + creator: address, + cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + mint_with_cap_v2(creator, cap, base_meta, type_meta, body) + } else { + let nft_type_info = + borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id: id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + public fun mint_with_cap_v2( + creator: address, + _cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2 { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + + /// Mint nft, the `sender` must have MintCapability + /// Note: this function is deprecated, please use `mint_v2` + public fun mint( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap(addr, cap, base_meta, type_meta, body) + } + + /// Mint nft, the `sender` must have MintCapability + public fun mint_v2( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap_v2(addr, cap, base_meta, type_meta, body) + } + + /// Add BurnCapability to `sender` + public fun add_burn_capability(sender: &signer, cap: BurnCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_burn_capability( + sender: &signer + ): BurnCapability acquires BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the BurnCapability + public fun destroy_burn_capability(cap: BurnCapability) { + let BurnCapability {} = cap; + } + + /// Burn nft with BurnCapability + public fun burn_with_cap( + _cap: &mut BurnCapability, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2 { + let NFT { creator: _, id: id, base_meta: _, type_meta: _, body } = nft; + // only NFTTypeInfoV2 has burn_events EventHandle + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + Event::emit_event(&mut nft_type_info.burn_events, BurnEvent { + id, + }); + }; + body + } + + /// Burn nft, the `sender` must have BurnCapability + public fun burn( + sender: &signer, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2, BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + let cap = borrow_global_mut>(addr); + burn_with_cap(cap, nft) + } + + /// Add UpdateCapability to `sender` + public fun add_update_capability(sender: &signer, cap: UpdateCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_update_capability( + sender: &signer + ): UpdateCapability acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the UpdateCapability + public fun destroy_update_capability(cap: UpdateCapability) { + let UpdateCapability {} = cap; + } + + /// Update the NFTTypeInfoV2 metadata with UpdateCapability + public fun update_nft_type_info_meta_with_cap( + _cap: &mut UpdateCapability, + new_meta: Metadata + ) acquires NFTTypeInfoV2{ + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + info.meta = new_meta; + } + + /// Update the NFTTypeInfoV2 metadata, the `sender` must have UpdateCapability + public fun update_nft_type_info_meta( + sender: &signer, + new_meta: Metadata + ) acquires UpdateCapability, NFTTypeInfoV2 { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_nft_type_info_meta_with_cap(cap, new_meta) + } + + /// Update the nft's base_meta and type_meta with UpdateCapability + public fun update_meta_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT, + base_meta: Metadata, type_meta: NFTMeta + ) { + nft.base_meta = base_meta; + nft.type_meta = type_meta; + } + + /// Update the nft's base_meta and type_meta, the `sender` must have UpdateCapability + public fun update_meta( + sender: &signer, + nft: &mut NFT, + base_meta: Metadata, + type_meta: NFTMeta + ) acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_meta_with_cap(cap, nft, base_meta, type_meta) + } + + /// Borrow NFTBody ref + public fun borrow_body(nft: &NFT): &NFTBody { + &nft.body + } + + /// Borrow NFTBody mut ref for update body with UpdateCapability + public fun borrow_body_mut_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT + ): &mut NFTBody { + &mut nft.body + } +} + +/// IdentifierNFT using NFT as identifier for an on chain account +/// The NFT can not been transfer by owner. +module IdentifierNFT { + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::NFT::{Self, NFT, MintCapability, BurnCapability, UpdateCapability}; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + const ERR_NFT_EXISTS: u64 = 101; + const ERR_NFT_NOT_EXISTS: u64 = 102; + const ERR_NFT_NOT_ACCEPT: u64 = 103; + const ERR_BORROW_ADDR_NOT_SAME: u64 = 104; + + spec module { + pragma verify = false; + } + + struct IdentifierNFT has key { + nft: Option>, + } + + //Used when borrowing or returning NFT, note: there is no drop ability, it must be returned after borrowing + struct BorrowNFT { + nft: NFT, + addr:address + } + + /// Check the `owner` is prepared with IdentifierNFT for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Accept NFT, prepare an empty IdentifierNFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let addr = Signer::address_of(sender); + if (!is_accept(addr)) { + move_to(sender, IdentifierNFT { + nft: Option::none(), + }); + } + } + + /// Destroy the empty IdentifierNFT + public entry fun destroy_empty_entry(sender: signer) acquires IdentifierNFT { + destroy_empty(&sender); + } + + public fun destroy_empty(sender: &signer) acquires IdentifierNFT { + let addr = Signer::address_of(sender); + if (exists>(addr)) { + let id_nft = move_from>(addr); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_none(nft); + } + } + + /// Grant nft as IdentifierNFT to `sender` with MintCapability, sender will auto accept the NFT. + public fun grant( + cap: &mut MintCapability, + sender: &signer, + nft: NFT + ) acquires IdentifierNFT { + Self::accept(sender); + Self::grant_to(cap, Signer::address_of(sender), nft); + } + + /// Grant nft as IdentifierNFT to `receiver` with MintCapability, the receiver should accept the NFT first. + public fun grant_to( + _cap: &mut MintCapability, + receiver: address, + nft: NFT + ) acquires IdentifierNFT { + assert!(exists>(receiver), Errors::not_published(ERR_NFT_NOT_ACCEPT)); + let id_nft = borrow_global_mut>(receiver); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + Option::fill(&mut id_nft.nft, nft); + } + + /// Revoke the NFT from owner. + public fun revoke( + _cap: &mut BurnCapability, + owner: address + ): NFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = move_from>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_some(nft) + } + + /// borrow_out the NFT from owner. + public fun borrow_out( + _cap: &mut UpdateCapability, + owner: address + ): BorrowNFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let id_nft = borrow_global_mut>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let nft = Option::extract(&mut id_nft.nft); + + BorrowNFT{ + nft : nft, + addr: owner + } + } + + /// return_back the NFT to owner. + public fun return_back( + borrownft: BorrowNFT, + ) acquires IdentifierNFT { + + let BorrowNFT{ + nft: nft, + addr: owner + } = borrownft ; + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = borrow_global_mut>(owner); + + Option::fill(&mut id_nft.nft , nft) + } + + public fun borrow_nft( + borrownft:&BorrowNFT + ) : & NFT { + & borrownft.nft + } + + public fun borrow_nft_mut ( + borrownft:&mut BorrowNFT + ) : &mut NFT { + &mut borrownft.nft + } + + /// Check `owner` is owns the IdentifierNFT + public fun owns(owner: address): bool acquires IdentifierNFT { + if (!exists>(owner)) { + return false + }; + let id_nft = borrow_global>(owner); + Option::is_some(&id_nft.nft) + } + /// deprecated. Use `owns()` instead. + public fun is_owns(owner: address): bool acquires IdentifierNFT { + owns(owner) + } + + public fun get_nft_info( + owner: address + ): Option> acquires IdentifierNFT { + if (!exists>(owner)) { + return Option::none>() + }; + let id_nft = borrow_global>(owner); + let info = if (Option::is_some(&id_nft.nft)) { + let nft = Option::borrow(&id_nft.nft); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + info + } +} + +module IdentifierNFTScripts { + use StarcoinFramework::IdentifierNFT; + spec module { + pragma verify = false; + } + + /// Init IdentifierNFT for accept NFT as Identifier. + public entry fun accept(sender: signer) { + IdentifierNFT::accept_entry(sender); + } + + /// Destroy empty IdentifierNFT + public entry fun destroy_empty(sender: signer) { + IdentifierNFT::destroy_empty_entry(sender); + } +} + +/// NFTGallery is user collection of NFT. +module NFTGallery { + use StarcoinFramework::Signer; + use StarcoinFramework::NFT::{Self, NFT}; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::Event; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + + const ERR_NFT_NOT_EXISTS: u64 = 101; + + const ERR_NFTGALLERY_NOT_EXISTS:u64 = 102; + + spec module { + pragma verify = false; + } + + struct WithdrawEvent has drop, store { + owner: address, + id: u64, + } + + struct DepositEvent has drop, store { + owner: address, + id: u64, + } + + struct NFTGallery has key, store { + withdraw_events: Event::EventHandle>, + deposit_events: Event::EventHandle>, + items: vector>, + } + + /// Check the `owner` is prepared with NFTGallery for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Init a NFTGallery to accept NFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let sender_addr = Signer::address_of(sender); + if (!is_accept(sender_addr)) { + let gallery = NFTGallery { + withdraw_events: Event::new_event_handle>(sender), + deposit_events: Event::new_event_handle>(sender), + items: Vector::empty>(), + }; + move_to(sender, gallery); + } + } + + /// Transfer NFT from `sender` to `receiver` + public entry fun transfer_entry( + sender: signer, + id: u64, receiver: address + ) acquires NFTGallery { + transfer(&sender, id, receiver); + } + + public fun transfer( + sender: &signer, + id: u64, + receiver: address + ) acquires NFTGallery { + let nft = withdraw(sender, id); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let nft = Option::destroy_some(nft); + deposit_to(receiver, nft) + } + + /// Get the NFT info by the NFT id. + public fun get_nft_info_by_id( + owner: address, + id: u64 + ): Option> acquires NFTGallery { + if(!is_accept(owner)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(owner); + let idx = find_by_id(&gallery.items, id); + + let info = if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::borrow>(&gallery.items, i); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + return info + } + + /// Get the NFT info by the NFT idx in NFTGallery + public fun get_nft_info_by_idx( + owner: address, + idx: u64 + ): NFT::NFTInfo acquires NFTGallery { + assert!(exists>(owner), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(owner); + let nft = Vector::borrow>(&gallery.items, idx); + NFT::get_info(nft) + } + + /// Get the all NFT info + public fun get_nft_infos( + owner: address + ): vector> acquires NFTGallery { + if(!is_accept(owner)){ + return Vector::empty>() + }; + let gallery = borrow_global_mut>(owner); + let infos = Vector::empty(); + let len = Vector::length(&gallery.items); + let idx = 0; + while (len > idx) { + let nft = Vector::borrow>(&gallery.items, idx); + Vector::push_back(&mut infos, NFT::get_info(nft)); + idx = idx + 1; + }; + infos + } + + /// Deposit nft to `sender` NFTGallery + public fun deposit( + sender: &signer, + nft: NFT + ) acquires NFTGallery { + Self::accept(sender); + let sender_addr = Signer::address_of(sender); + deposit_to(sender_addr, nft) + } + + /// Deposit nft to `receiver` NFTGallery + public fun deposit_to( + receiver: address, + nft: NFT + ) acquires NFTGallery { + assert!(exists>(receiver), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(receiver); + Event::emit_event(&mut gallery.deposit_events, DepositEvent { id: NFT::get_id(&nft), owner: receiver }); + Vector::push_back(&mut gallery.items, nft); + } + + /// Withdraw one nft of NFTMeta from `sender`, caller should ensure at least one NFT in the Gallery. + public fun withdraw_one( + sender: &signer + ): NFT acquires NFTGallery { + let nft = do_withdraw(sender, Option::none()); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + Option::destroy_some(nft) + } + + /// Withdraw nft of NFTMeta and id from `sender` + public fun withdraw( + sender: &signer, + id: u64 + ): Option> acquires NFTGallery { + do_withdraw(sender, Option::some(id)) + } + + /// Withdraw nft of NFTMeta and id from `sender` + fun do_withdraw( + sender: &signer, + id: Option + ): Option> acquires NFTGallery { + let sender_addr = Signer::address_of(sender); + if(!is_accept(sender_addr)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(sender_addr); + let len = Vector::length(&gallery.items); + let nft = if (len == 0) { + Option::none() + } else { + let idx = if (Option::is_some(&id)) { + let id = Option::extract(&mut id); + find_by_id(&gallery.items, id) + } else { + //default withdraw the last nft. + Option::some(len - 1) + }; + + if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::remove>(&mut gallery.items, i); + Event::emit_event( + &mut gallery.withdraw_events, + WithdrawEvent { id: NFT::get_id(&nft), owner: sender_addr } + ); + Option::some(nft) + } else { + Option::none() + } + }; + nft + } + + fun find_by_id( + c: &vector>, + id: u64 + ): Option { + let len = Vector::length(c); + if (len == 0) { + return Option::none() + }; + let idx = len - 1; + loop { + let nft = Vector::borrow(c, idx); + if (NFT::get_id(nft) == id) { + return Option::some(idx) + }; + if (idx == 0) { + return Option::none() + }; + idx = idx - 1; + } + } + + /// Count all NFTs assigned to an owner + public fun count_of(owner: address): u64 acquires NFTGallery { + if(!is_accept(owner)){ + return 0 + }; + let gallery = borrow_global_mut>(owner); + Vector::length(&gallery.items) + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery_entry(sender: signer) acquires NFTGallery { + remove_empty_gallery(&sender); + } + + public fun remove_empty_gallery(sender: &signer) acquires NFTGallery{ + let sender_addr = Signer::address_of(sender); + assert!(exists>(sender_addr), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let NFTGallery {withdraw_events, deposit_events, items} = move_from>(sender_addr); + + Event::destroy_handle>(withdraw_events); + Event::destroy_handle>(deposit_events); + Vector::destroy_empty>(items); + } + + spec remove_empty_gallery { + let sender_addr = Signer::address_of(sender); + aborts_if !exists>(sender_addr); + + let gallery = global>(sender_addr); + aborts_if Vector::length>(gallery.items) > 0; + + ensures !exists>(sender_addr); + } + +} + +module NFTGalleryScripts { + use StarcoinFramework::NFTGallery; + + spec module { + pragma verify = false; + } + + /// Init a NFTGallery for accept NFT + public entry fun accept(sender: signer) { + NFTGallery::accept_entry(sender); + } + /// Transfer NFT with `id` from `sender` to `receiver` + public entry fun transfer( + sender: signer, + id: u64, receiver: address + ) { + NFTGallery::transfer_entry(sender, id, receiver); + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery(sender: signer) { + NFTGallery::remove_empty_gallery_entry(sender); + } +} +} diff --git a/release/v13/sources/LanguageVersion.move b/release/v13/sources/LanguageVersion.move new file mode 100644 index 00000000..82dc1d5b --- /dev/null +++ b/release/v13/sources/LanguageVersion.move @@ -0,0 +1,22 @@ +address StarcoinFramework { +module LanguageVersion { + struct LanguageVersion has copy, drop, store { + major: u64, + } + + public fun new(version: u64): LanguageVersion { + LanguageVersion {major: version} + } + + public fun version(version: &LanguageVersion): u64 { + version.major + } + + spec new { + pragma verify = false; + } + spec version { + pragma verify = false; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Math.move b/release/v13/sources/Math.move new file mode 100644 index 00000000..ccd25206 --- /dev/null +++ b/release/v13/sources/Math.move @@ -0,0 +1,155 @@ +address StarcoinFramework { +/// The module provide some improved math calculations. +module Math { + use StarcoinFramework::Vector; + + // TODO: verify the module. + spec module { + pragma verify = false; + pragma aborts_if_is_strict; + } + + const U64_MAX:u64 = 18446744073709551615; + const U128_MAX:u128 = 340282366920938463463374607431768211455; + + /// u64::MAX + public fun u64_max(): u64 { + U64_MAX + } + + /// u128::MAX + public fun u128_max(): u128 { + U128_MAX + } + + /// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) + public fun sqrt(y: u128): u64 { + if (y < 4) { + if (y == 0) { + 0u64 + } else { + 1u64 + } + } else { + let z = y; + let x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + }; + (z as u64) + } + } + + spec sqrt { + pragma opaque = true; + pragma verify = false; //while loop + aborts_if [abstract] false; + ensures [abstract] result == spec_sqrt(); + } + + /// We use an uninterpreted function to represent the result of sqrt. The actual value + /// does not matter for the verification of callers. + spec fun spec_sqrt(): u128; + + /// calculate the `y` pow of `x`. + public fun pow(x: u64, y: u64): u128 { + let result = 1u128; + let z = y; + let u = (x as u128); + while (z > 0) { + if (z % 2 == 1) { + result = (u * result as u128); + }; + u = (u * u as u128); + z = z / 2; + }; + result + } + + spec pow { + pragma opaque = true; + pragma verify = false; //while loop + aborts_if [abstract] false; + ensures [abstract] result == spec_pow(); + } + + /// We use an uninterpreted function to represent the result of pow. The actual value + /// does not matter for the verification of callers. + spec fun spec_pow(): u128; + + /// https://medium.com/coinmonks/math-in-solidity-part-3-percents-and-proportions-4db014e080b1 + /// calculate x * y /z with as little loss of precision as possible and avoid overflow + public fun mul_div(x: u128, y: u128, z: u128): u128 { + if (y == z) { + return x + }; + if (x == z) { + return y + }; + let a = x / z; + let b = x % z; + //x = a * z + b; + let c = y / z; + let d = y % z; + //y = c * z + d; + a * c * z + a * d + b * c + b * d / z + } + + spec mul_div { + pragma opaque = true; + include MulDivAbortsIf; + aborts_if [abstract] false; + ensures [abstract] result == spec_mul_div(); + } + + spec schema MulDivAbortsIf { + x: u128; + y: u128; + z: u128; + aborts_if y != z && x > z && z == 0; + aborts_if y != z && x > z && z!=0 && x/z*y > MAX_U128; + aborts_if y != z && x <= z && z == 0; + //a * b overflow + aborts_if y != z && x <= z && x / z * (x % z) > MAX_U128; + //a * b * z overflow + aborts_if y != z && x <= z && x / z * (x % z) * z > MAX_U128; + //a * d overflow + aborts_if y != z && x <= z && x / z * (y % z) > MAX_U128; + //a * b * z + a * d overflow + aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) > MAX_U128; + //b * c overflow + aborts_if y != z && x <= z && x % z * (y / z) > MAX_U128; + //b * d overflow + aborts_if y != z && x <= z && x % z * (y % z) > MAX_U128; + //b * d / z overflow + aborts_if y != z && x <= z && x % z * (y % z) / z > MAX_U128; + //a * b * z + a * d + b * c overflow + aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) + x % z * (y / z) > MAX_U128; + //a * b * z + a * d + b * c + b * d / z overflow + aborts_if y != z && x <= z && x / z * (x % z) * z + x / z * (y % z) + x % z * (y / z) + x % z * (y % z) / z > MAX_U128; + + } + + spec fun spec_mul_div(): u128; + + /// calculate sum of nums + public fun sum(nums: &vector): u128 { + let len = Vector::length(nums); + let i = 0; + let sum = 0; + while (i < len){ + sum = sum + *Vector::borrow(nums, i); + i = i + 1; + }; + sum + } + + /// calculate average of nums + public fun avg(nums: &vector): u128{ + let len = Vector::length(nums); + let sum = sum(nums); + sum/(len as u128) + } +} +} \ No newline at end of file diff --git a/release/v13/sources/MerkleNFTDistributor.move b/release/v13/sources/MerkleNFTDistributor.move new file mode 100644 index 00000000..be992e67 --- /dev/null +++ b/release/v13/sources/MerkleNFTDistributor.move @@ -0,0 +1,131 @@ +module StarcoinFramework::MerkleProof { + use StarcoinFramework::Hash; + use StarcoinFramework::Vector; + use StarcoinFramework::Compare; + + /// verify leaf node with hash of `leaf` with `proof` againest merkle `root`. + public fun verify(proof: &vector>, root: &vector, leaf: vector): bool { + let computed_hash = leaf; + let i = 0; + let proof_length = Vector::length(proof); + while (i < proof_length) { + let sibling = Vector::borrow(proof, i); + // computed_hash is left. + if (Compare::cmp_bytes( &computed_hash, sibling) < 2) { + let concated = concat(computed_hash, * sibling); + computed_hash = Hash::sha3_256(concated); + } else { + let concated = concat(*sibling, computed_hash); + computed_hash = Hash::sha3_256(concated); + }; + + i = i + 1; + }; + &computed_hash == root + } + + fun concat(v1: vector, v2: vector): vector { + Vector::append( &mut v1, v2); + v1 + } +} + +module StarcoinFramework::MerkleNFTDistributor { + use StarcoinFramework::Vector; + use StarcoinFramework::NFT::{Self, NFT, Metadata, MintCapability}; + use StarcoinFramework::Hash; + use StarcoinFramework::BCS; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::MerkleProof; + const ALREADY_MINTED: u64 = 1000; + const INVALID_PROOF: u64 = 1001; + const ERR_NO_MINT_CAPABILITY: u64 = 1002; + + struct MerkleNFTDistribution has key { + merkle_root: vector, + claimed_bitmap: vector, + } + + public fun register(signer: &signer, merkle_root: vector, leafs: u64, info: Info, meta: Metadata): MintCapability { + let bitmap_count = leafs / 128; + if (bitmap_count * 128 < leafs) { + bitmap_count = bitmap_count + 1; + }; + let claimed_bitmap = Vector::empty(); + let j = 0; + while (j < bitmap_count) { + Vector::push_back( &mut claimed_bitmap, 0u128); + j = j + 1; + }; + let distribution = MerkleNFTDistribution{ + merkle_root, + claimed_bitmap + }; + NFT::register(signer, info, meta); + move_to(signer, distribution); + NFT::remove_mint_capability(signer) + } + + public fun mint_with_cap(sender: &signer, cap:&mut MintCapability, creator: address, index: u64, base_meta: Metadata, type_meta: NFTMeta, body: NFTBody, merkle_proof:vector>): NFT + acquires MerkleNFTDistribution { + let addr = Signer::address_of(sender); + let distribution = borrow_global_mut>(creator); + let minted = is_minted_(distribution, index); + assert!(!minted, Errors::custom(ALREADY_MINTED)); + let leaf_data = encode_leaf(&index, &addr); + let verified = MerkleProof::verify(&merkle_proof, &distribution.merkle_root, Hash::sha3_256(leaf_data)); + assert!(verified, Errors::custom(INVALID_PROOF)); + set_minted_(distribution, index); + let nft = NFT::mint_with_cap(creator, cap, base_meta, type_meta, body); + return nft + } + + fun encode_leaf(index: &u64, account: &address): vector { + let leaf = Vector::empty(); + Vector::append(&mut leaf, BCS::to_bytes(index)); + Vector::append(&mut leaf, BCS::to_bytes(account)); + leaf + } + + fun set_minted_(distribution: &mut MerkleNFTDistribution, index: u64) { + let claimed_word_index = index / 128; + let claimed_bit_index = ((index % 128) as u8); + let word = Vector::borrow_mut(&mut distribution.claimed_bitmap, claimed_word_index); + // word | (1 << bit_index) + let mask = 1u128 << claimed_bit_index; + *word = (*word | mask); + } + + spec set_minted_ { + pragma verify = false; // Bitwise operator + pragma opaque; + } + + public fun verify_proof(account: address, creator: address, index: u64, merkle_proof:vector>): bool + acquires MerkleNFTDistribution { + let distribution = borrow_global_mut>(creator); + let leaf_data = encode_leaf(&index, &account); + MerkleProof::verify(&merkle_proof, &distribution.merkle_root, Hash::sha3_256(leaf_data)) + } + + public fun is_minted(creator: address, index: u64): bool + acquires MerkleNFTDistribution { + let distribution = borrow_global_mut>(creator); + is_minted_(distribution, index) + } + + fun is_minted_(distribution: &MerkleNFTDistribution, index: u64): bool { + let claimed_word_index = index / 128; + let claimed_bit_index = ((index % 128) as u8); + let word = Vector::borrow( &distribution.claimed_bitmap, claimed_word_index); + let mask = 1u128 << claimed_bit_index; + (*word & mask) == mask + } + + spec is_minted_ { + pragma verify = false; // Bitwise operator + pragma opaque; + } + +} diff --git a/release/v13/sources/MerkleProof.move b/release/v13/sources/MerkleProof.move new file mode 100644 index 00000000..be992e67 --- /dev/null +++ b/release/v13/sources/MerkleProof.move @@ -0,0 +1,131 @@ +module StarcoinFramework::MerkleProof { + use StarcoinFramework::Hash; + use StarcoinFramework::Vector; + use StarcoinFramework::Compare; + + /// verify leaf node with hash of `leaf` with `proof` againest merkle `root`. + public fun verify(proof: &vector>, root: &vector, leaf: vector): bool { + let computed_hash = leaf; + let i = 0; + let proof_length = Vector::length(proof); + while (i < proof_length) { + let sibling = Vector::borrow(proof, i); + // computed_hash is left. + if (Compare::cmp_bytes( &computed_hash, sibling) < 2) { + let concated = concat(computed_hash, * sibling); + computed_hash = Hash::sha3_256(concated); + } else { + let concated = concat(*sibling, computed_hash); + computed_hash = Hash::sha3_256(concated); + }; + + i = i + 1; + }; + &computed_hash == root + } + + fun concat(v1: vector, v2: vector): vector { + Vector::append( &mut v1, v2); + v1 + } +} + +module StarcoinFramework::MerkleNFTDistributor { + use StarcoinFramework::Vector; + use StarcoinFramework::NFT::{Self, NFT, Metadata, MintCapability}; + use StarcoinFramework::Hash; + use StarcoinFramework::BCS; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::MerkleProof; + const ALREADY_MINTED: u64 = 1000; + const INVALID_PROOF: u64 = 1001; + const ERR_NO_MINT_CAPABILITY: u64 = 1002; + + struct MerkleNFTDistribution has key { + merkle_root: vector, + claimed_bitmap: vector, + } + + public fun register(signer: &signer, merkle_root: vector, leafs: u64, info: Info, meta: Metadata): MintCapability { + let bitmap_count = leafs / 128; + if (bitmap_count * 128 < leafs) { + bitmap_count = bitmap_count + 1; + }; + let claimed_bitmap = Vector::empty(); + let j = 0; + while (j < bitmap_count) { + Vector::push_back( &mut claimed_bitmap, 0u128); + j = j + 1; + }; + let distribution = MerkleNFTDistribution{ + merkle_root, + claimed_bitmap + }; + NFT::register(signer, info, meta); + move_to(signer, distribution); + NFT::remove_mint_capability(signer) + } + + public fun mint_with_cap(sender: &signer, cap:&mut MintCapability, creator: address, index: u64, base_meta: Metadata, type_meta: NFTMeta, body: NFTBody, merkle_proof:vector>): NFT + acquires MerkleNFTDistribution { + let addr = Signer::address_of(sender); + let distribution = borrow_global_mut>(creator); + let minted = is_minted_(distribution, index); + assert!(!minted, Errors::custom(ALREADY_MINTED)); + let leaf_data = encode_leaf(&index, &addr); + let verified = MerkleProof::verify(&merkle_proof, &distribution.merkle_root, Hash::sha3_256(leaf_data)); + assert!(verified, Errors::custom(INVALID_PROOF)); + set_minted_(distribution, index); + let nft = NFT::mint_with_cap(creator, cap, base_meta, type_meta, body); + return nft + } + + fun encode_leaf(index: &u64, account: &address): vector { + let leaf = Vector::empty(); + Vector::append(&mut leaf, BCS::to_bytes(index)); + Vector::append(&mut leaf, BCS::to_bytes(account)); + leaf + } + + fun set_minted_(distribution: &mut MerkleNFTDistribution, index: u64) { + let claimed_word_index = index / 128; + let claimed_bit_index = ((index % 128) as u8); + let word = Vector::borrow_mut(&mut distribution.claimed_bitmap, claimed_word_index); + // word | (1 << bit_index) + let mask = 1u128 << claimed_bit_index; + *word = (*word | mask); + } + + spec set_minted_ { + pragma verify = false; // Bitwise operator + pragma opaque; + } + + public fun verify_proof(account: address, creator: address, index: u64, merkle_proof:vector>): bool + acquires MerkleNFTDistribution { + let distribution = borrow_global_mut>(creator); + let leaf_data = encode_leaf(&index, &account); + MerkleProof::verify(&merkle_proof, &distribution.merkle_root, Hash::sha3_256(leaf_data)) + } + + public fun is_minted(creator: address, index: u64): bool + acquires MerkleNFTDistribution { + let distribution = borrow_global_mut>(creator); + is_minted_(distribution, index) + } + + fun is_minted_(distribution: &MerkleNFTDistribution, index: u64): bool { + let claimed_word_index = index / 128; + let claimed_bit_index = ((index % 128) as u8); + let word = Vector::borrow( &distribution.claimed_bitmap, claimed_word_index); + let mask = 1u128 << claimed_bit_index; + (*word & mask) == mask + } + + spec is_minted_ { + pragma verify = false; // Bitwise operator + pragma opaque; + } + +} diff --git a/release/v13/sources/MintDaoProposal.move b/release/v13/sources/MintDaoProposal.move new file mode 100644 index 00000000..18ff68cc --- /dev/null +++ b/release/v13/sources/MintDaoProposal.move @@ -0,0 +1,98 @@ +address StarcoinFramework { +/// MintDaoProposal is a dao proposal for mint extra tokens. +module MintDaoProposal { + use StarcoinFramework::Token; + use StarcoinFramework::Signer; + use StarcoinFramework::Dao; + use StarcoinFramework::Account; + use StarcoinFramework::Errors; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_strict; + pragma aborts_if_is_partial; + } + + /// A wrapper of Token MintCapability. + struct WrappedMintCapability has key { + cap: Token::MintCapability, + } + + /// MintToken request. + struct MintToken has copy, drop, store { + /// the receiver of minted tokens. + receiver: address, + /// how many tokens to mint. + amount: u128, + } + + const ERR_NOT_AUTHORIZED: u64 = 401; + + /// Plugin method of the module. + /// Should be called by token issuer. + public fun plugin(signer: &signer) { + let token_issuer = Token::token_address(); + assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + let mint_cap = Token::remove_mint_capability(signer); + move_to(signer, WrappedMintCapability { cap: mint_cap }); + } + spec plugin { + pragma aborts_if_is_partial = false; + let sender = Signer::address_of(signer); + aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if !exists>(sender); + aborts_if exists>(sender); + + ensures !exists>(sender); + ensures exists>(sender); + } + + + /// Entrypoint for the proposal. + public fun propose_mint_to(signer: &signer, receiver: address, amount: u128, exec_delay: u64) { + Dao::propose( + signer, + MintToken { receiver, amount }, + exec_delay, + ); + } + spec propose_mint_to { + use StarcoinFramework::Timestamp; + use StarcoinFramework::CoreAddresses; + pragma aborts_if_is_partial = false; + + // copy from Dao::propose spec. + include Dao::AbortIfDaoConfigNotExist; + include Dao::AbortIfDaoInfoNotExist; + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config().min_action_delay; + include Dao::CheckQuorumVotes; + let sender = Signer::address_of(signer); + aborts_if exists>(sender); + } + + /// Once the proposal is agreed, anyone can call the method to make the proposal happen. + public fun execute_mint_proposal( + proposer_address: address, + proposal_id: u64, + ) acquires WrappedMintCapability { + let MintToken { receiver, amount } = Dao::extract_proposal_action( + proposer_address, + proposal_id, + ); + let cap = borrow_global>(Token::token_address()); + let tokens = Token::mint_with_capability(&cap.cap, amount); + Account::deposit(receiver, tokens); + } + + spec execute_mint_proposal { + use StarcoinFramework::Option; + pragma aborts_if_is_partial = true; + let expected_states = vec(6); + include Dao::CheckProposalStates{expected_states}; + let proposal = global>(proposer_address); + aborts_if Option::is_none(proposal.action); + aborts_if !exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/MintScripts.move b/release/v13/sources/MintScripts.move new file mode 100644 index 00000000..cdfb599e --- /dev/null +++ b/release/v13/sources/MintScripts.move @@ -0,0 +1,4 @@ +address StarcoinFramework { +module MintScripts { +} +} \ No newline at end of file diff --git a/release/v13/sources/ModifyDaoConfigProposal.move b/release/v13/sources/ModifyDaoConfigProposal.move new file mode 100644 index 00000000..65c3cfb1 --- /dev/null +++ b/release/v13/sources/ModifyDaoConfigProposal.move @@ -0,0 +1,125 @@ +address StarcoinFramework { +/// A proposal module which is used to modify Token's DAO configuration. +module ModifyDaoConfigProposal { + // use StarcoinFramework::Config; + use StarcoinFramework::Token; + use StarcoinFramework::Signer; + use StarcoinFramework::Config; + use StarcoinFramework::Dao; + use StarcoinFramework::Errors; + use StarcoinFramework::Option; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_strict; + pragma aborts_if_is_partial; + } + + /// A wrapper of `Config::ModifyConfigCapability>`. + struct DaoConfigModifyCapability has key { + cap: Config::ModifyConfigCapability>, + } + + const ERR_NOT_AUTHORIZED: u64 = 401; + const ERR_QUORUM_RATE_INVALID: u64 = 402; + + /// a proposal action to update dao config. + /// if any field is `0`, that means the proposal want to update. + struct DaoConfigUpdate has copy, drop, store { + /// new voting delay setting. + voting_delay: u64, + /// new voting period setting. + voting_period: u64, + /// new voting quorum rate setting. + voting_quorum_rate: u8, + /// new min action delay setting. + min_action_delay: u64, + } + + /// Plugin method of the module. + /// Should be called by token issuer. + public fun plugin(signer: &signer) { + let token_issuer = Token::token_address(); + assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + let dao_config_modify_cap = Config::extract_modify_config_capability< + Dao::DaoConfig, + >(signer); + assert!(Config::account_address(&dao_config_modify_cap) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + let cap = DaoConfigModifyCapability { cap: dao_config_modify_cap }; + move_to(signer, cap); + } + + spec plugin { + pragma aborts_if_is_partial = false; + let sender = Signer::address_of(signer); + aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS(); + include Config::AbortsIfCapNotExist>{address: sender}; + let config_cap = Config::spec_cap>(sender); + aborts_if Option::is_none(config_cap); + aborts_if Option::borrow(config_cap).account_address != sender; + aborts_if exists>(sender); + ensures exists>(sender); + } + + /// Entrypoint for the proposal. + public entry fun propose( + signer: signer, + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + exec_delay: u64, + ) { + assert!(voting_quorum_rate <= 100, Errors::invalid_argument(ERR_QUORUM_RATE_INVALID)); + let action = DaoConfigUpdate { + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + }; + Dao::propose(&signer, action, exec_delay); + } + spec propose { + use StarcoinFramework::Timestamp; + use StarcoinFramework::CoreAddresses; + pragma aborts_if_is_partial = false; + aborts_if voting_quorum_rate > 100; + + // copy from Dao::propose spec. + include Dao::AbortIfDaoConfigNotExist; + include Dao::AbortIfDaoInfoNotExist; + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config().min_action_delay; + include Dao::CheckQuorumVotes; + let sender = Signer::address_of(signer); + aborts_if exists>(sender); + + } + /// Once the proposal is agreed, anyone can call the method to make the proposal happen. + public entry fun execute(proposer_address: address, proposal_id: u64) + acquires DaoConfigModifyCapability { + let DaoConfigUpdate { + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + } = Dao::extract_proposal_action(proposer_address, proposal_id); + let cap = borrow_global_mut>( + Token::token_address(), + ); + Dao::modify_dao_config( + &mut cap.cap, + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + ); + } + spec execute { + pragma aborts_if_is_partial = true; + // let expected_states = vec(6); + // include Dao::CheckProposalStates{expected_states}; + aborts_if !exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/ModuleUpgradeScripts.move b/release/v13/sources/ModuleUpgradeScripts.move new file mode 100644 index 00000000..3d28887b --- /dev/null +++ b/release/v13/sources/ModuleUpgradeScripts.move @@ -0,0 +1,116 @@ +address StarcoinFramework { +module ModuleUpgradeScripts { + use StarcoinFramework::PackageTxnManager; + use StarcoinFramework::Config; + use StarcoinFramework::Signer; + use StarcoinFramework::Version; + use StarcoinFramework::Option; + use StarcoinFramework::UpgradeModuleDaoProposal; + use StarcoinFramework::Errors; + + const ERR_WRONG_UPGRADE_STRATEGY: u64 = 100; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_partial = false; + pragma aborts_if_is_strict = true; + } + + public entry fun propose_module_upgrade_v2( + signer: signer, + module_address: address, + package_hash: vector, + version: u64, + exec_delay: u64, + enforced: bool, + ) { + UpgradeModuleDaoProposal::propose_module_upgrade_v2( + &signer, + module_address, + package_hash, + version, + exec_delay, + enforced + ); + } + + ///Update `sender`'s module upgrade strategy to `strategy` + public entry fun update_module_upgrade_strategy( + sender: signer, + strategy: u8, + ) { + // 1. check version + if (strategy == PackageTxnManager::get_strategy_two_phase()) { + if (!Config::config_exist_by_address(Signer::address_of(&sender))) { + Config::publish_new_config(&sender, Version::new_version(1)); + } + }; + + // 2. update strategy + PackageTxnManager::update_module_upgrade_strategy( + &sender, + strategy, + Option::none(), + ); + } + + /// Update `sender`'s module upgrade strategy to `strategy` with min_time_limit. + /// This can only be invoked when strategy is STRATEGY_TWO_PHASE. + public entry fun update_module_upgrade_strategy_with_min_time( + sender: signer, + strategy: u8, + min_time_limit: u64, + ){ + // 1. check version + assert!(strategy == PackageTxnManager::get_strategy_two_phase(), Errors::invalid_argument(ERR_WRONG_UPGRADE_STRATEGY)); + // 2. update strategy + PackageTxnManager::update_module_upgrade_strategy( + &sender, + strategy, + Option::some(min_time_limit), + ); + } + + /// a alias of execute_module_upgrade_plan_propose, will deprecated in the future. + public entry fun submit_module_upgrade_plan( + sender: signer, + proposer_address: address, + proposal_id: u64, + ) { + Self::execute_module_upgrade_plan_propose(sender, proposer_address, proposal_id); + } + + ///Execute module upgrade plan propose by submit module upgrade plan, the propose must been agreed, and anyone can execute this function. + public entry fun execute_module_upgrade_plan_propose( + _sender: signer, + proposer_address: address, + proposal_id: u64, + ) { + UpgradeModuleDaoProposal::submit_module_upgrade_plan(proposer_address, proposal_id); + } + + spec execute_module_upgrade_plan_propose { + pragma verify = false; + } + + ///Directly submit a upgrade plan, the `sender`'s module upgrade plan must been PackageTxnManager::STRATEGY_TWO_PHASE and have UpgradePlanCapability + public entry fun submit_upgrade_plan(sender: signer, package_hash: vector, version:u64, enforced: bool) { + PackageTxnManager::submit_upgrade_plan_v2(&sender, package_hash, version, enforced); + } + + spec submit_upgrade_plan { + pragma verify = false; + } + + ///Cancel current upgrade plan, the `sender` must have `UpgradePlanCapability`. + public entry fun cancel_upgrade_plan( + signer: signer, + ) { + PackageTxnManager::cancel_upgrade_plan(&signer); + } + + spec cancel_upgrade_plan { + pragma verify = false; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/NFT.move b/release/v13/sources/NFT.move new file mode 100644 index 00000000..d1ac25f8 --- /dev/null +++ b/release/v13/sources/NFT.move @@ -0,0 +1,1023 @@ +address StarcoinFramework { +/// Non-fungible token standard and implementations. +module NFT { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Account; + use StarcoinFramework::Vector; + use StarcoinFramework::Event; + use StarcoinFramework::GenesisSignerCapability; + + const ERR_NO_MINT_CAPABILITY: u64 = 101; + const ERR_NO_BURN_CAPABILITY: u64 = 102; + const ERR_NO_UPDATE_CAPABILITY: u64 = 103; + const ERR_CANOT_EMPTY: u64 = 104; + const ERR_NFT_TYPE_ALREADY_REGISTERED: u64 = 105; + const ERR_NFT_TYPE_NO_REGISTERED: u64 = 106; + + spec module { + pragma verify = false; + } + + struct MintEvent has drop, store { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + struct BurnEvent has drop, store { + id: u64, + } + + /// The info of NFT type, this type is deprecated, please use NFTTypeInfoV2 + struct NFTTypeInfo has key, store { + counter: u64, + meta: Metadata, + info: NFTTypeInfoExt, + mint_events: Event::EventHandle>, + } + + /// The info of NFT type + struct NFTTypeInfoV2 has key, store { + register: address, + counter: u64, + meta: Metadata, + mint_events: Event::EventHandle>, + burn_events: Event::EventHandle>, + } + + struct NFTTypeInfoCompat has key { + info: NFTTypeInfoExt, + } + + /// Deprecated. Use `new_nft_type_info_v2` instead. + fun new_nft_type_info( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ): NFTTypeInfo { + NFTTypeInfo { + counter: 0, + info, + meta, + mint_events: Event::new_event_handle>(sender), + } + } + + fun new_nft_type_info_v2(sender: &signer, meta: Metadata): NFTTypeInfoV2 { + NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter: 0, + meta, + mint_events: Event::new_event_handle>(sender), + burn_events: Event::new_event_handle>(sender), + } + } + + /// Note: this function is deprecated + public fun nft_type_info_ex_info( + ): NFTTypeInfoExt acquires NFTTypeInfo, NFTTypeInfoCompat { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } + } + + /// Note: this function is deprecated, please use nft_type_info_counter_v2 + public fun nft_type_info_counter( + ): u64 acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + Self::nft_type_info_counter_v2() + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + } + + public fun nft_type_info_counter_v2(): u64 acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + + public fun nft_type_info_meta(): Metadata acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.meta + } + + public fun upgrade_nft_type_info_from_v1_to_v2( + sender: &signer, + _cap: &mut MintCapability + ) acquires NFTTypeInfo { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfo { counter, meta, info, mint_events } = nft_type_info; + + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let nft_type_info_v2 = NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter, + meta, + mint_events, + burn_events: Event::new_event_handle>(sender), + }; + move_to(&genesis_account, nft_type_info_v2); + move_to(&genesis_account, NFTTypeInfoCompat { info }); + } + } + + public fun remove_compat_info( + _cap: &mut MintCapability + ): NFTTypeInfoExt acquires NFTTypeInfoCompat { + let compat_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfoCompat{info} = compat_info; + info + } + /// deprecated. + struct GenesisSignerCapability has key { + cap: Account::SignerCapability, + } + /// The capability to mint the nft. + struct MintCapability has key, store {} + /// The Capability to burn the nft. + struct BurnCapability has key, store {} + /// The Capability to update the nft metadata. + struct UpdateCapability has key, store {} + + struct Metadata has copy, store, drop { + /// NFT name's utf8 bytes. + name: vector, + /// Image link, such as ipfs://xxxx + image: vector, + /// Image bytes data, image or image_data can not empty for both. + image_data: vector, + /// NFT description utf8 bytes. + description: vector, + } + + public fun empty_meta(): Metadata { + Metadata { + name: Vector::empty(), + image: Vector::empty(), + image_data: Vector::empty(), + description: Vector::empty(), + } + } + + public fun new_meta(name: vector, description: vector): Metadata { + Metadata { + name, + image: Vector::empty(), + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image(name: vector, image: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image, + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image_data(name: vector, image_data: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image_data), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image: Vector::empty(), + image_data, + description, + } + } + + public fun meta_name(metadata: &Metadata): vector { + *&metadata.name + } + + public fun meta_image(metadata: &Metadata): vector { + *&metadata.image + } + + public fun meta_image_data(metadata: &Metadata): vector { + *&metadata.image_data + } + + public fun meta_description(metadata: &Metadata): vector { + *&metadata.description + } + + struct NFT has store { + /// The creator of NFT + creator: address, + /// The unique id of NFT under NFTMeta type + id: u64, + /// The metadata of NFT + base_meta: Metadata, + /// The extension metadata of NFT + type_meta: NFTMeta, + /// The body of NFT, NFT is a box for NFTBody + body: NFTBody, + } + + /// The information of NFT instance return by get_nft_info + struct NFTInfo has copy, store, drop { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + public fun get_info(nft: &NFT): NFTInfo { + NFTInfo { + id: nft.id, + creator: nft.creator, + base_meta: *&nft.base_meta, + type_meta: *&nft.type_meta, + } + } + + public fun unpack_info( + nft_info: NFTInfo + ): (u64, address, Metadata, NFTMeta) { + let NFTInfo { id, creator, base_meta, type_meta } = nft_info; + (id, creator, base_meta, type_meta) + } + + public fun get_id(nft: &NFT): u64 { + return nft.id + } + + public fun get_base_meta(nft: &NFT): &Metadata { + return &nft.base_meta + } + + public fun get_type_meta(nft: &NFT): &NFTMeta { + return &nft.type_meta + } + + public fun get_creator(nft: &NFT): address { + return nft.creator + } + + /// deprecated. + public fun initialize(_signer: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, + /// in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability { + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register a NFT type to genesis + /// Note: this function is deprecated, please use `register_v2` + public fun register( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ) acquires NFTTypeInfo { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + let type_info = new_nft_type_info(sender, info, meta); + move_to>(&genesis_account, type_info); + let mint_cap = MintCapability {}; + + Self::upgrade_nft_type_info_from_v1_to_v2(sender, &mut mint_cap); + + move_to>(sender, mint_cap); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Register a NFT type to genesis + public fun register_v2(sender: &signer, meta: Metadata) { + assert!(!is_registered(), Errors::invalid_argument(ERR_NFT_TYPE_ALREADY_REGISTERED)); + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let type_info = new_nft_type_info_v2(sender, meta); + move_to>(&genesis_account, type_info); + move_to>(sender, MintCapability {}); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Check the NFTMeta is register + public fun is_registered(): bool { + exists>(CoreAddresses::GENESIS_ADDRESS()) + } + + /// deprecated. Use "is_registered" instead. + public fun is_register(): bool { + is_registered() + } + + /// Add MintCapability to `sender` + public fun add_mint_capability(sender: &signer, cap: MintCapability) { + move_to(sender, cap); + } + + /// Remove the MintCapability from `sender` + public fun remove_mint_capability( + sender: &signer + ): MintCapability acquires MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the MintCapability + public fun destroy_mint_capability(cap: MintCapability) { + let MintCapability {} = cap; + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + /// Note: this function is deprecated, please use `mint_with_cap_v2` + public fun mint_with_cap( + creator: address, + cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + mint_with_cap_v2(creator, cap, base_meta, type_meta, body) + } else { + let nft_type_info = + borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id: id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + public fun mint_with_cap_v2( + creator: address, + _cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2 { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + + /// Mint nft, the `sender` must have MintCapability + /// Note: this function is deprecated, please use `mint_v2` + public fun mint( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap(addr, cap, base_meta, type_meta, body) + } + + /// Mint nft, the `sender` must have MintCapability + public fun mint_v2( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap_v2(addr, cap, base_meta, type_meta, body) + } + + /// Add BurnCapability to `sender` + public fun add_burn_capability(sender: &signer, cap: BurnCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_burn_capability( + sender: &signer + ): BurnCapability acquires BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the BurnCapability + public fun destroy_burn_capability(cap: BurnCapability) { + let BurnCapability {} = cap; + } + + /// Burn nft with BurnCapability + public fun burn_with_cap( + _cap: &mut BurnCapability, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2 { + let NFT { creator: _, id: id, base_meta: _, type_meta: _, body } = nft; + // only NFTTypeInfoV2 has burn_events EventHandle + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + Event::emit_event(&mut nft_type_info.burn_events, BurnEvent { + id, + }); + }; + body + } + + /// Burn nft, the `sender` must have BurnCapability + public fun burn( + sender: &signer, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2, BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + let cap = borrow_global_mut>(addr); + burn_with_cap(cap, nft) + } + + /// Add UpdateCapability to `sender` + public fun add_update_capability(sender: &signer, cap: UpdateCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_update_capability( + sender: &signer + ): UpdateCapability acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the UpdateCapability + public fun destroy_update_capability(cap: UpdateCapability) { + let UpdateCapability {} = cap; + } + + /// Update the NFTTypeInfoV2 metadata with UpdateCapability + public fun update_nft_type_info_meta_with_cap( + _cap: &mut UpdateCapability, + new_meta: Metadata + ) acquires NFTTypeInfoV2{ + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + info.meta = new_meta; + } + + /// Update the NFTTypeInfoV2 metadata, the `sender` must have UpdateCapability + public fun update_nft_type_info_meta( + sender: &signer, + new_meta: Metadata + ) acquires UpdateCapability, NFTTypeInfoV2 { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_nft_type_info_meta_with_cap(cap, new_meta) + } + + /// Update the nft's base_meta and type_meta with UpdateCapability + public fun update_meta_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT, + base_meta: Metadata, type_meta: NFTMeta + ) { + nft.base_meta = base_meta; + nft.type_meta = type_meta; + } + + /// Update the nft's base_meta and type_meta, the `sender` must have UpdateCapability + public fun update_meta( + sender: &signer, + nft: &mut NFT, + base_meta: Metadata, + type_meta: NFTMeta + ) acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_meta_with_cap(cap, nft, base_meta, type_meta) + } + + /// Borrow NFTBody ref + public fun borrow_body(nft: &NFT): &NFTBody { + &nft.body + } + + /// Borrow NFTBody mut ref for update body with UpdateCapability + public fun borrow_body_mut_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT + ): &mut NFTBody { + &mut nft.body + } +} + +/// IdentifierNFT using NFT as identifier for an on chain account +/// The NFT can not been transfer by owner. +module IdentifierNFT { + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::NFT::{Self, NFT, MintCapability, BurnCapability, UpdateCapability}; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + const ERR_NFT_EXISTS: u64 = 101; + const ERR_NFT_NOT_EXISTS: u64 = 102; + const ERR_NFT_NOT_ACCEPT: u64 = 103; + const ERR_BORROW_ADDR_NOT_SAME: u64 = 104; + + spec module { + pragma verify = false; + } + + struct IdentifierNFT has key { + nft: Option>, + } + + //Used when borrowing or returning NFT, note: there is no drop ability, it must be returned after borrowing + struct BorrowNFT { + nft: NFT, + addr:address + } + + /// Check the `owner` is prepared with IdentifierNFT for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Accept NFT, prepare an empty IdentifierNFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let addr = Signer::address_of(sender); + if (!is_accept(addr)) { + move_to(sender, IdentifierNFT { + nft: Option::none(), + }); + } + } + + /// Destroy the empty IdentifierNFT + public entry fun destroy_empty_entry(sender: signer) acquires IdentifierNFT { + destroy_empty(&sender); + } + + public fun destroy_empty(sender: &signer) acquires IdentifierNFT { + let addr = Signer::address_of(sender); + if (exists>(addr)) { + let id_nft = move_from>(addr); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_none(nft); + } + } + + /// Grant nft as IdentifierNFT to `sender` with MintCapability, sender will auto accept the NFT. + public fun grant( + cap: &mut MintCapability, + sender: &signer, + nft: NFT + ) acquires IdentifierNFT { + Self::accept(sender); + Self::grant_to(cap, Signer::address_of(sender), nft); + } + + /// Grant nft as IdentifierNFT to `receiver` with MintCapability, the receiver should accept the NFT first. + public fun grant_to( + _cap: &mut MintCapability, + receiver: address, + nft: NFT + ) acquires IdentifierNFT { + assert!(exists>(receiver), Errors::not_published(ERR_NFT_NOT_ACCEPT)); + let id_nft = borrow_global_mut>(receiver); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + Option::fill(&mut id_nft.nft, nft); + } + + /// Revoke the NFT from owner. + public fun revoke( + _cap: &mut BurnCapability, + owner: address + ): NFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = move_from>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_some(nft) + } + + /// borrow_out the NFT from owner. + public fun borrow_out( + _cap: &mut UpdateCapability, + owner: address + ): BorrowNFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let id_nft = borrow_global_mut>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let nft = Option::extract(&mut id_nft.nft); + + BorrowNFT{ + nft : nft, + addr: owner + } + } + + /// return_back the NFT to owner. + public fun return_back( + borrownft: BorrowNFT, + ) acquires IdentifierNFT { + + let BorrowNFT{ + nft: nft, + addr: owner + } = borrownft ; + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = borrow_global_mut>(owner); + + Option::fill(&mut id_nft.nft , nft) + } + + public fun borrow_nft( + borrownft:&BorrowNFT + ) : & NFT { + & borrownft.nft + } + + public fun borrow_nft_mut ( + borrownft:&mut BorrowNFT + ) : &mut NFT { + &mut borrownft.nft + } + + /// Check `owner` is owns the IdentifierNFT + public fun owns(owner: address): bool acquires IdentifierNFT { + if (!exists>(owner)) { + return false + }; + let id_nft = borrow_global>(owner); + Option::is_some(&id_nft.nft) + } + /// deprecated. Use `owns()` instead. + public fun is_owns(owner: address): bool acquires IdentifierNFT { + owns(owner) + } + + public fun get_nft_info( + owner: address + ): Option> acquires IdentifierNFT { + if (!exists>(owner)) { + return Option::none>() + }; + let id_nft = borrow_global>(owner); + let info = if (Option::is_some(&id_nft.nft)) { + let nft = Option::borrow(&id_nft.nft); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + info + } +} + +module IdentifierNFTScripts { + use StarcoinFramework::IdentifierNFT; + spec module { + pragma verify = false; + } + + /// Init IdentifierNFT for accept NFT as Identifier. + public entry fun accept(sender: signer) { + IdentifierNFT::accept_entry(sender); + } + + /// Destroy empty IdentifierNFT + public entry fun destroy_empty(sender: signer) { + IdentifierNFT::destroy_empty_entry(sender); + } +} + +/// NFTGallery is user collection of NFT. +module NFTGallery { + use StarcoinFramework::Signer; + use StarcoinFramework::NFT::{Self, NFT}; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::Event; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + + const ERR_NFT_NOT_EXISTS: u64 = 101; + + const ERR_NFTGALLERY_NOT_EXISTS:u64 = 102; + + spec module { + pragma verify = false; + } + + struct WithdrawEvent has drop, store { + owner: address, + id: u64, + } + + struct DepositEvent has drop, store { + owner: address, + id: u64, + } + + struct NFTGallery has key, store { + withdraw_events: Event::EventHandle>, + deposit_events: Event::EventHandle>, + items: vector>, + } + + /// Check the `owner` is prepared with NFTGallery for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Init a NFTGallery to accept NFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let sender_addr = Signer::address_of(sender); + if (!is_accept(sender_addr)) { + let gallery = NFTGallery { + withdraw_events: Event::new_event_handle>(sender), + deposit_events: Event::new_event_handle>(sender), + items: Vector::empty>(), + }; + move_to(sender, gallery); + } + } + + /// Transfer NFT from `sender` to `receiver` + public entry fun transfer_entry( + sender: signer, + id: u64, receiver: address + ) acquires NFTGallery { + transfer(&sender, id, receiver); + } + + public fun transfer( + sender: &signer, + id: u64, + receiver: address + ) acquires NFTGallery { + let nft = withdraw(sender, id); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let nft = Option::destroy_some(nft); + deposit_to(receiver, nft) + } + + /// Get the NFT info by the NFT id. + public fun get_nft_info_by_id( + owner: address, + id: u64 + ): Option> acquires NFTGallery { + if(!is_accept(owner)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(owner); + let idx = find_by_id(&gallery.items, id); + + let info = if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::borrow>(&gallery.items, i); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + return info + } + + /// Get the NFT info by the NFT idx in NFTGallery + public fun get_nft_info_by_idx( + owner: address, + idx: u64 + ): NFT::NFTInfo acquires NFTGallery { + assert!(exists>(owner), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(owner); + let nft = Vector::borrow>(&gallery.items, idx); + NFT::get_info(nft) + } + + /// Get the all NFT info + public fun get_nft_infos( + owner: address + ): vector> acquires NFTGallery { + if(!is_accept(owner)){ + return Vector::empty>() + }; + let gallery = borrow_global_mut>(owner); + let infos = Vector::empty(); + let len = Vector::length(&gallery.items); + let idx = 0; + while (len > idx) { + let nft = Vector::borrow>(&gallery.items, idx); + Vector::push_back(&mut infos, NFT::get_info(nft)); + idx = idx + 1; + }; + infos + } + + /// Deposit nft to `sender` NFTGallery + public fun deposit( + sender: &signer, + nft: NFT + ) acquires NFTGallery { + Self::accept(sender); + let sender_addr = Signer::address_of(sender); + deposit_to(sender_addr, nft) + } + + /// Deposit nft to `receiver` NFTGallery + public fun deposit_to( + receiver: address, + nft: NFT + ) acquires NFTGallery { + assert!(exists>(receiver), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(receiver); + Event::emit_event(&mut gallery.deposit_events, DepositEvent { id: NFT::get_id(&nft), owner: receiver }); + Vector::push_back(&mut gallery.items, nft); + } + + /// Withdraw one nft of NFTMeta from `sender`, caller should ensure at least one NFT in the Gallery. + public fun withdraw_one( + sender: &signer + ): NFT acquires NFTGallery { + let nft = do_withdraw(sender, Option::none()); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + Option::destroy_some(nft) + } + + /// Withdraw nft of NFTMeta and id from `sender` + public fun withdraw( + sender: &signer, + id: u64 + ): Option> acquires NFTGallery { + do_withdraw(sender, Option::some(id)) + } + + /// Withdraw nft of NFTMeta and id from `sender` + fun do_withdraw( + sender: &signer, + id: Option + ): Option> acquires NFTGallery { + let sender_addr = Signer::address_of(sender); + if(!is_accept(sender_addr)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(sender_addr); + let len = Vector::length(&gallery.items); + let nft = if (len == 0) { + Option::none() + } else { + let idx = if (Option::is_some(&id)) { + let id = Option::extract(&mut id); + find_by_id(&gallery.items, id) + } else { + //default withdraw the last nft. + Option::some(len - 1) + }; + + if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::remove>(&mut gallery.items, i); + Event::emit_event( + &mut gallery.withdraw_events, + WithdrawEvent { id: NFT::get_id(&nft), owner: sender_addr } + ); + Option::some(nft) + } else { + Option::none() + } + }; + nft + } + + fun find_by_id( + c: &vector>, + id: u64 + ): Option { + let len = Vector::length(c); + if (len == 0) { + return Option::none() + }; + let idx = len - 1; + loop { + let nft = Vector::borrow(c, idx); + if (NFT::get_id(nft) == id) { + return Option::some(idx) + }; + if (idx == 0) { + return Option::none() + }; + idx = idx - 1; + } + } + + /// Count all NFTs assigned to an owner + public fun count_of(owner: address): u64 acquires NFTGallery { + if(!is_accept(owner)){ + return 0 + }; + let gallery = borrow_global_mut>(owner); + Vector::length(&gallery.items) + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery_entry(sender: signer) acquires NFTGallery { + remove_empty_gallery(&sender); + } + + public fun remove_empty_gallery(sender: &signer) acquires NFTGallery{ + let sender_addr = Signer::address_of(sender); + assert!(exists>(sender_addr), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let NFTGallery {withdraw_events, deposit_events, items} = move_from>(sender_addr); + + Event::destroy_handle>(withdraw_events); + Event::destroy_handle>(deposit_events); + Vector::destroy_empty>(items); + } + + spec remove_empty_gallery { + let sender_addr = Signer::address_of(sender); + aborts_if !exists>(sender_addr); + + let gallery = global>(sender_addr); + aborts_if Vector::length>(gallery.items) > 0; + + ensures !exists>(sender_addr); + } + +} + +module NFTGalleryScripts { + use StarcoinFramework::NFTGallery; + + spec module { + pragma verify = false; + } + + /// Init a NFTGallery for accept NFT + public entry fun accept(sender: signer) { + NFTGallery::accept_entry(sender); + } + /// Transfer NFT with `id` from `sender` to `receiver` + public entry fun transfer( + sender: signer, + id: u64, receiver: address + ) { + NFTGallery::transfer_entry(sender, id, receiver); + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery(sender: signer) { + NFTGallery::remove_empty_gallery_entry(sender); + } +} +} diff --git a/release/v13/sources/NFTGallery.move b/release/v13/sources/NFTGallery.move new file mode 100644 index 00000000..d1ac25f8 --- /dev/null +++ b/release/v13/sources/NFTGallery.move @@ -0,0 +1,1023 @@ +address StarcoinFramework { +/// Non-fungible token standard and implementations. +module NFT { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Account; + use StarcoinFramework::Vector; + use StarcoinFramework::Event; + use StarcoinFramework::GenesisSignerCapability; + + const ERR_NO_MINT_CAPABILITY: u64 = 101; + const ERR_NO_BURN_CAPABILITY: u64 = 102; + const ERR_NO_UPDATE_CAPABILITY: u64 = 103; + const ERR_CANOT_EMPTY: u64 = 104; + const ERR_NFT_TYPE_ALREADY_REGISTERED: u64 = 105; + const ERR_NFT_TYPE_NO_REGISTERED: u64 = 106; + + spec module { + pragma verify = false; + } + + struct MintEvent has drop, store { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + struct BurnEvent has drop, store { + id: u64, + } + + /// The info of NFT type, this type is deprecated, please use NFTTypeInfoV2 + struct NFTTypeInfo has key, store { + counter: u64, + meta: Metadata, + info: NFTTypeInfoExt, + mint_events: Event::EventHandle>, + } + + /// The info of NFT type + struct NFTTypeInfoV2 has key, store { + register: address, + counter: u64, + meta: Metadata, + mint_events: Event::EventHandle>, + burn_events: Event::EventHandle>, + } + + struct NFTTypeInfoCompat has key { + info: NFTTypeInfoExt, + } + + /// Deprecated. Use `new_nft_type_info_v2` instead. + fun new_nft_type_info( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ): NFTTypeInfo { + NFTTypeInfo { + counter: 0, + info, + meta, + mint_events: Event::new_event_handle>(sender), + } + } + + fun new_nft_type_info_v2(sender: &signer, meta: Metadata): NFTTypeInfoV2 { + NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter: 0, + meta, + mint_events: Event::new_event_handle>(sender), + burn_events: Event::new_event_handle>(sender), + } + } + + /// Note: this function is deprecated + public fun nft_type_info_ex_info( + ): NFTTypeInfoExt acquires NFTTypeInfo, NFTTypeInfoCompat { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } + } + + /// Note: this function is deprecated, please use nft_type_info_counter_v2 + public fun nft_type_info_counter( + ): u64 acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + Self::nft_type_info_counter_v2() + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + } + + public fun nft_type_info_counter_v2(): u64 acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + + public fun nft_type_info_meta(): Metadata acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.meta + } + + public fun upgrade_nft_type_info_from_v1_to_v2( + sender: &signer, + _cap: &mut MintCapability + ) acquires NFTTypeInfo { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfo { counter, meta, info, mint_events } = nft_type_info; + + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let nft_type_info_v2 = NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter, + meta, + mint_events, + burn_events: Event::new_event_handle>(sender), + }; + move_to(&genesis_account, nft_type_info_v2); + move_to(&genesis_account, NFTTypeInfoCompat { info }); + } + } + + public fun remove_compat_info( + _cap: &mut MintCapability + ): NFTTypeInfoExt acquires NFTTypeInfoCompat { + let compat_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfoCompat{info} = compat_info; + info + } + /// deprecated. + struct GenesisSignerCapability has key { + cap: Account::SignerCapability, + } + /// The capability to mint the nft. + struct MintCapability has key, store {} + /// The Capability to burn the nft. + struct BurnCapability has key, store {} + /// The Capability to update the nft metadata. + struct UpdateCapability has key, store {} + + struct Metadata has copy, store, drop { + /// NFT name's utf8 bytes. + name: vector, + /// Image link, such as ipfs://xxxx + image: vector, + /// Image bytes data, image or image_data can not empty for both. + image_data: vector, + /// NFT description utf8 bytes. + description: vector, + } + + public fun empty_meta(): Metadata { + Metadata { + name: Vector::empty(), + image: Vector::empty(), + image_data: Vector::empty(), + description: Vector::empty(), + } + } + + public fun new_meta(name: vector, description: vector): Metadata { + Metadata { + name, + image: Vector::empty(), + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image(name: vector, image: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image, + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image_data(name: vector, image_data: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image_data), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image: Vector::empty(), + image_data, + description, + } + } + + public fun meta_name(metadata: &Metadata): vector { + *&metadata.name + } + + public fun meta_image(metadata: &Metadata): vector { + *&metadata.image + } + + public fun meta_image_data(metadata: &Metadata): vector { + *&metadata.image_data + } + + public fun meta_description(metadata: &Metadata): vector { + *&metadata.description + } + + struct NFT has store { + /// The creator of NFT + creator: address, + /// The unique id of NFT under NFTMeta type + id: u64, + /// The metadata of NFT + base_meta: Metadata, + /// The extension metadata of NFT + type_meta: NFTMeta, + /// The body of NFT, NFT is a box for NFTBody + body: NFTBody, + } + + /// The information of NFT instance return by get_nft_info + struct NFTInfo has copy, store, drop { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + public fun get_info(nft: &NFT): NFTInfo { + NFTInfo { + id: nft.id, + creator: nft.creator, + base_meta: *&nft.base_meta, + type_meta: *&nft.type_meta, + } + } + + public fun unpack_info( + nft_info: NFTInfo + ): (u64, address, Metadata, NFTMeta) { + let NFTInfo { id, creator, base_meta, type_meta } = nft_info; + (id, creator, base_meta, type_meta) + } + + public fun get_id(nft: &NFT): u64 { + return nft.id + } + + public fun get_base_meta(nft: &NFT): &Metadata { + return &nft.base_meta + } + + public fun get_type_meta(nft: &NFT): &NFTMeta { + return &nft.type_meta + } + + public fun get_creator(nft: &NFT): address { + return nft.creator + } + + /// deprecated. + public fun initialize(_signer: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, + /// in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability { + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register a NFT type to genesis + /// Note: this function is deprecated, please use `register_v2` + public fun register( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ) acquires NFTTypeInfo { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + let type_info = new_nft_type_info(sender, info, meta); + move_to>(&genesis_account, type_info); + let mint_cap = MintCapability {}; + + Self::upgrade_nft_type_info_from_v1_to_v2(sender, &mut mint_cap); + + move_to>(sender, mint_cap); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Register a NFT type to genesis + public fun register_v2(sender: &signer, meta: Metadata) { + assert!(!is_registered(), Errors::invalid_argument(ERR_NFT_TYPE_ALREADY_REGISTERED)); + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let type_info = new_nft_type_info_v2(sender, meta); + move_to>(&genesis_account, type_info); + move_to>(sender, MintCapability {}); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Check the NFTMeta is register + public fun is_registered(): bool { + exists>(CoreAddresses::GENESIS_ADDRESS()) + } + + /// deprecated. Use "is_registered" instead. + public fun is_register(): bool { + is_registered() + } + + /// Add MintCapability to `sender` + public fun add_mint_capability(sender: &signer, cap: MintCapability) { + move_to(sender, cap); + } + + /// Remove the MintCapability from `sender` + public fun remove_mint_capability( + sender: &signer + ): MintCapability acquires MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the MintCapability + public fun destroy_mint_capability(cap: MintCapability) { + let MintCapability {} = cap; + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + /// Note: this function is deprecated, please use `mint_with_cap_v2` + public fun mint_with_cap( + creator: address, + cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + mint_with_cap_v2(creator, cap, base_meta, type_meta, body) + } else { + let nft_type_info = + borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id: id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + public fun mint_with_cap_v2( + creator: address, + _cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2 { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + + /// Mint nft, the `sender` must have MintCapability + /// Note: this function is deprecated, please use `mint_v2` + public fun mint( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap(addr, cap, base_meta, type_meta, body) + } + + /// Mint nft, the `sender` must have MintCapability + public fun mint_v2( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap_v2(addr, cap, base_meta, type_meta, body) + } + + /// Add BurnCapability to `sender` + public fun add_burn_capability(sender: &signer, cap: BurnCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_burn_capability( + sender: &signer + ): BurnCapability acquires BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the BurnCapability + public fun destroy_burn_capability(cap: BurnCapability) { + let BurnCapability {} = cap; + } + + /// Burn nft with BurnCapability + public fun burn_with_cap( + _cap: &mut BurnCapability, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2 { + let NFT { creator: _, id: id, base_meta: _, type_meta: _, body } = nft; + // only NFTTypeInfoV2 has burn_events EventHandle + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + Event::emit_event(&mut nft_type_info.burn_events, BurnEvent { + id, + }); + }; + body + } + + /// Burn nft, the `sender` must have BurnCapability + public fun burn( + sender: &signer, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2, BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + let cap = borrow_global_mut>(addr); + burn_with_cap(cap, nft) + } + + /// Add UpdateCapability to `sender` + public fun add_update_capability(sender: &signer, cap: UpdateCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_update_capability( + sender: &signer + ): UpdateCapability acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the UpdateCapability + public fun destroy_update_capability(cap: UpdateCapability) { + let UpdateCapability {} = cap; + } + + /// Update the NFTTypeInfoV2 metadata with UpdateCapability + public fun update_nft_type_info_meta_with_cap( + _cap: &mut UpdateCapability, + new_meta: Metadata + ) acquires NFTTypeInfoV2{ + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + info.meta = new_meta; + } + + /// Update the NFTTypeInfoV2 metadata, the `sender` must have UpdateCapability + public fun update_nft_type_info_meta( + sender: &signer, + new_meta: Metadata + ) acquires UpdateCapability, NFTTypeInfoV2 { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_nft_type_info_meta_with_cap(cap, new_meta) + } + + /// Update the nft's base_meta and type_meta with UpdateCapability + public fun update_meta_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT, + base_meta: Metadata, type_meta: NFTMeta + ) { + nft.base_meta = base_meta; + nft.type_meta = type_meta; + } + + /// Update the nft's base_meta and type_meta, the `sender` must have UpdateCapability + public fun update_meta( + sender: &signer, + nft: &mut NFT, + base_meta: Metadata, + type_meta: NFTMeta + ) acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_meta_with_cap(cap, nft, base_meta, type_meta) + } + + /// Borrow NFTBody ref + public fun borrow_body(nft: &NFT): &NFTBody { + &nft.body + } + + /// Borrow NFTBody mut ref for update body with UpdateCapability + public fun borrow_body_mut_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT + ): &mut NFTBody { + &mut nft.body + } +} + +/// IdentifierNFT using NFT as identifier for an on chain account +/// The NFT can not been transfer by owner. +module IdentifierNFT { + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::NFT::{Self, NFT, MintCapability, BurnCapability, UpdateCapability}; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + const ERR_NFT_EXISTS: u64 = 101; + const ERR_NFT_NOT_EXISTS: u64 = 102; + const ERR_NFT_NOT_ACCEPT: u64 = 103; + const ERR_BORROW_ADDR_NOT_SAME: u64 = 104; + + spec module { + pragma verify = false; + } + + struct IdentifierNFT has key { + nft: Option>, + } + + //Used when borrowing or returning NFT, note: there is no drop ability, it must be returned after borrowing + struct BorrowNFT { + nft: NFT, + addr:address + } + + /// Check the `owner` is prepared with IdentifierNFT for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Accept NFT, prepare an empty IdentifierNFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let addr = Signer::address_of(sender); + if (!is_accept(addr)) { + move_to(sender, IdentifierNFT { + nft: Option::none(), + }); + } + } + + /// Destroy the empty IdentifierNFT + public entry fun destroy_empty_entry(sender: signer) acquires IdentifierNFT { + destroy_empty(&sender); + } + + public fun destroy_empty(sender: &signer) acquires IdentifierNFT { + let addr = Signer::address_of(sender); + if (exists>(addr)) { + let id_nft = move_from>(addr); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_none(nft); + } + } + + /// Grant nft as IdentifierNFT to `sender` with MintCapability, sender will auto accept the NFT. + public fun grant( + cap: &mut MintCapability, + sender: &signer, + nft: NFT + ) acquires IdentifierNFT { + Self::accept(sender); + Self::grant_to(cap, Signer::address_of(sender), nft); + } + + /// Grant nft as IdentifierNFT to `receiver` with MintCapability, the receiver should accept the NFT first. + public fun grant_to( + _cap: &mut MintCapability, + receiver: address, + nft: NFT + ) acquires IdentifierNFT { + assert!(exists>(receiver), Errors::not_published(ERR_NFT_NOT_ACCEPT)); + let id_nft = borrow_global_mut>(receiver); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + Option::fill(&mut id_nft.nft, nft); + } + + /// Revoke the NFT from owner. + public fun revoke( + _cap: &mut BurnCapability, + owner: address + ): NFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = move_from>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_some(nft) + } + + /// borrow_out the NFT from owner. + public fun borrow_out( + _cap: &mut UpdateCapability, + owner: address + ): BorrowNFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let id_nft = borrow_global_mut>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let nft = Option::extract(&mut id_nft.nft); + + BorrowNFT{ + nft : nft, + addr: owner + } + } + + /// return_back the NFT to owner. + public fun return_back( + borrownft: BorrowNFT, + ) acquires IdentifierNFT { + + let BorrowNFT{ + nft: nft, + addr: owner + } = borrownft ; + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = borrow_global_mut>(owner); + + Option::fill(&mut id_nft.nft , nft) + } + + public fun borrow_nft( + borrownft:&BorrowNFT + ) : & NFT { + & borrownft.nft + } + + public fun borrow_nft_mut ( + borrownft:&mut BorrowNFT + ) : &mut NFT { + &mut borrownft.nft + } + + /// Check `owner` is owns the IdentifierNFT + public fun owns(owner: address): bool acquires IdentifierNFT { + if (!exists>(owner)) { + return false + }; + let id_nft = borrow_global>(owner); + Option::is_some(&id_nft.nft) + } + /// deprecated. Use `owns()` instead. + public fun is_owns(owner: address): bool acquires IdentifierNFT { + owns(owner) + } + + public fun get_nft_info( + owner: address + ): Option> acquires IdentifierNFT { + if (!exists>(owner)) { + return Option::none>() + }; + let id_nft = borrow_global>(owner); + let info = if (Option::is_some(&id_nft.nft)) { + let nft = Option::borrow(&id_nft.nft); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + info + } +} + +module IdentifierNFTScripts { + use StarcoinFramework::IdentifierNFT; + spec module { + pragma verify = false; + } + + /// Init IdentifierNFT for accept NFT as Identifier. + public entry fun accept(sender: signer) { + IdentifierNFT::accept_entry(sender); + } + + /// Destroy empty IdentifierNFT + public entry fun destroy_empty(sender: signer) { + IdentifierNFT::destroy_empty_entry(sender); + } +} + +/// NFTGallery is user collection of NFT. +module NFTGallery { + use StarcoinFramework::Signer; + use StarcoinFramework::NFT::{Self, NFT}; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::Event; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + + const ERR_NFT_NOT_EXISTS: u64 = 101; + + const ERR_NFTGALLERY_NOT_EXISTS:u64 = 102; + + spec module { + pragma verify = false; + } + + struct WithdrawEvent has drop, store { + owner: address, + id: u64, + } + + struct DepositEvent has drop, store { + owner: address, + id: u64, + } + + struct NFTGallery has key, store { + withdraw_events: Event::EventHandle>, + deposit_events: Event::EventHandle>, + items: vector>, + } + + /// Check the `owner` is prepared with NFTGallery for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Init a NFTGallery to accept NFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let sender_addr = Signer::address_of(sender); + if (!is_accept(sender_addr)) { + let gallery = NFTGallery { + withdraw_events: Event::new_event_handle>(sender), + deposit_events: Event::new_event_handle>(sender), + items: Vector::empty>(), + }; + move_to(sender, gallery); + } + } + + /// Transfer NFT from `sender` to `receiver` + public entry fun transfer_entry( + sender: signer, + id: u64, receiver: address + ) acquires NFTGallery { + transfer(&sender, id, receiver); + } + + public fun transfer( + sender: &signer, + id: u64, + receiver: address + ) acquires NFTGallery { + let nft = withdraw(sender, id); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let nft = Option::destroy_some(nft); + deposit_to(receiver, nft) + } + + /// Get the NFT info by the NFT id. + public fun get_nft_info_by_id( + owner: address, + id: u64 + ): Option> acquires NFTGallery { + if(!is_accept(owner)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(owner); + let idx = find_by_id(&gallery.items, id); + + let info = if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::borrow>(&gallery.items, i); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + return info + } + + /// Get the NFT info by the NFT idx in NFTGallery + public fun get_nft_info_by_idx( + owner: address, + idx: u64 + ): NFT::NFTInfo acquires NFTGallery { + assert!(exists>(owner), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(owner); + let nft = Vector::borrow>(&gallery.items, idx); + NFT::get_info(nft) + } + + /// Get the all NFT info + public fun get_nft_infos( + owner: address + ): vector> acquires NFTGallery { + if(!is_accept(owner)){ + return Vector::empty>() + }; + let gallery = borrow_global_mut>(owner); + let infos = Vector::empty(); + let len = Vector::length(&gallery.items); + let idx = 0; + while (len > idx) { + let nft = Vector::borrow>(&gallery.items, idx); + Vector::push_back(&mut infos, NFT::get_info(nft)); + idx = idx + 1; + }; + infos + } + + /// Deposit nft to `sender` NFTGallery + public fun deposit( + sender: &signer, + nft: NFT + ) acquires NFTGallery { + Self::accept(sender); + let sender_addr = Signer::address_of(sender); + deposit_to(sender_addr, nft) + } + + /// Deposit nft to `receiver` NFTGallery + public fun deposit_to( + receiver: address, + nft: NFT + ) acquires NFTGallery { + assert!(exists>(receiver), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(receiver); + Event::emit_event(&mut gallery.deposit_events, DepositEvent { id: NFT::get_id(&nft), owner: receiver }); + Vector::push_back(&mut gallery.items, nft); + } + + /// Withdraw one nft of NFTMeta from `sender`, caller should ensure at least one NFT in the Gallery. + public fun withdraw_one( + sender: &signer + ): NFT acquires NFTGallery { + let nft = do_withdraw(sender, Option::none()); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + Option::destroy_some(nft) + } + + /// Withdraw nft of NFTMeta and id from `sender` + public fun withdraw( + sender: &signer, + id: u64 + ): Option> acquires NFTGallery { + do_withdraw(sender, Option::some(id)) + } + + /// Withdraw nft of NFTMeta and id from `sender` + fun do_withdraw( + sender: &signer, + id: Option + ): Option> acquires NFTGallery { + let sender_addr = Signer::address_of(sender); + if(!is_accept(sender_addr)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(sender_addr); + let len = Vector::length(&gallery.items); + let nft = if (len == 0) { + Option::none() + } else { + let idx = if (Option::is_some(&id)) { + let id = Option::extract(&mut id); + find_by_id(&gallery.items, id) + } else { + //default withdraw the last nft. + Option::some(len - 1) + }; + + if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::remove>(&mut gallery.items, i); + Event::emit_event( + &mut gallery.withdraw_events, + WithdrawEvent { id: NFT::get_id(&nft), owner: sender_addr } + ); + Option::some(nft) + } else { + Option::none() + } + }; + nft + } + + fun find_by_id( + c: &vector>, + id: u64 + ): Option { + let len = Vector::length(c); + if (len == 0) { + return Option::none() + }; + let idx = len - 1; + loop { + let nft = Vector::borrow(c, idx); + if (NFT::get_id(nft) == id) { + return Option::some(idx) + }; + if (idx == 0) { + return Option::none() + }; + idx = idx - 1; + } + } + + /// Count all NFTs assigned to an owner + public fun count_of(owner: address): u64 acquires NFTGallery { + if(!is_accept(owner)){ + return 0 + }; + let gallery = borrow_global_mut>(owner); + Vector::length(&gallery.items) + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery_entry(sender: signer) acquires NFTGallery { + remove_empty_gallery(&sender); + } + + public fun remove_empty_gallery(sender: &signer) acquires NFTGallery{ + let sender_addr = Signer::address_of(sender); + assert!(exists>(sender_addr), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let NFTGallery {withdraw_events, deposit_events, items} = move_from>(sender_addr); + + Event::destroy_handle>(withdraw_events); + Event::destroy_handle>(deposit_events); + Vector::destroy_empty>(items); + } + + spec remove_empty_gallery { + let sender_addr = Signer::address_of(sender); + aborts_if !exists>(sender_addr); + + let gallery = global>(sender_addr); + aborts_if Vector::length>(gallery.items) > 0; + + ensures !exists>(sender_addr); + } + +} + +module NFTGalleryScripts { + use StarcoinFramework::NFTGallery; + + spec module { + pragma verify = false; + } + + /// Init a NFTGallery for accept NFT + public entry fun accept(sender: signer) { + NFTGallery::accept_entry(sender); + } + /// Transfer NFT with `id` from `sender` to `receiver` + public entry fun transfer( + sender: signer, + id: u64, receiver: address + ) { + NFTGallery::transfer_entry(sender, id, receiver); + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery(sender: signer) { + NFTGallery::remove_empty_gallery_entry(sender); + } +} +} diff --git a/release/v13/sources/NFTGalleryScripts.move b/release/v13/sources/NFTGalleryScripts.move new file mode 100644 index 00000000..d1ac25f8 --- /dev/null +++ b/release/v13/sources/NFTGalleryScripts.move @@ -0,0 +1,1023 @@ +address StarcoinFramework { +/// Non-fungible token standard and implementations. +module NFT { + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Account; + use StarcoinFramework::Vector; + use StarcoinFramework::Event; + use StarcoinFramework::GenesisSignerCapability; + + const ERR_NO_MINT_CAPABILITY: u64 = 101; + const ERR_NO_BURN_CAPABILITY: u64 = 102; + const ERR_NO_UPDATE_CAPABILITY: u64 = 103; + const ERR_CANOT_EMPTY: u64 = 104; + const ERR_NFT_TYPE_ALREADY_REGISTERED: u64 = 105; + const ERR_NFT_TYPE_NO_REGISTERED: u64 = 106; + + spec module { + pragma verify = false; + } + + struct MintEvent has drop, store { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + struct BurnEvent has drop, store { + id: u64, + } + + /// The info of NFT type, this type is deprecated, please use NFTTypeInfoV2 + struct NFTTypeInfo has key, store { + counter: u64, + meta: Metadata, + info: NFTTypeInfoExt, + mint_events: Event::EventHandle>, + } + + /// The info of NFT type + struct NFTTypeInfoV2 has key, store { + register: address, + counter: u64, + meta: Metadata, + mint_events: Event::EventHandle>, + burn_events: Event::EventHandle>, + } + + struct NFTTypeInfoCompat has key { + info: NFTTypeInfoExt, + } + + /// Deprecated. Use `new_nft_type_info_v2` instead. + fun new_nft_type_info( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ): NFTTypeInfo { + NFTTypeInfo { + counter: 0, + info, + meta, + mint_events: Event::new_event_handle>(sender), + } + } + + fun new_nft_type_info_v2(sender: &signer, meta: Metadata): NFTTypeInfoV2 { + NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter: 0, + meta, + mint_events: Event::new_event_handle>(sender), + burn_events: Event::new_event_handle>(sender), + } + } + + /// Note: this function is deprecated + public fun nft_type_info_ex_info( + ): NFTTypeInfoExt acquires NFTTypeInfo, NFTTypeInfoCompat { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.info + } + } + + /// Note: this function is deprecated, please use nft_type_info_counter_v2 + public fun nft_type_info_counter( + ): u64 acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + Self::nft_type_info_counter_v2() + } else { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + } + + public fun nft_type_info_counter_v2(): u64 acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.counter + } + + public fun nft_type_info_meta(): Metadata acquires NFTTypeInfoV2 { + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&info.meta + } + + public fun upgrade_nft_type_info_from_v1_to_v2( + sender: &signer, + _cap: &mut MintCapability + ) acquires NFTTypeInfo { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfo { counter, meta, info, mint_events } = nft_type_info; + + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let nft_type_info_v2 = NFTTypeInfoV2 { + register: Signer::address_of(sender), + counter, + meta, + mint_events, + burn_events: Event::new_event_handle>(sender), + }; + move_to(&genesis_account, nft_type_info_v2); + move_to(&genesis_account, NFTTypeInfoCompat { info }); + } + } + + public fun remove_compat_info( + _cap: &mut MintCapability + ): NFTTypeInfoExt acquires NFTTypeInfoCompat { + let compat_info = move_from>(CoreAddresses::GENESIS_ADDRESS()); + let NFTTypeInfoCompat{info} = compat_info; + info + } + /// deprecated. + struct GenesisSignerCapability has key { + cap: Account::SignerCapability, + } + /// The capability to mint the nft. + struct MintCapability has key, store {} + /// The Capability to burn the nft. + struct BurnCapability has key, store {} + /// The Capability to update the nft metadata. + struct UpdateCapability has key, store {} + + struct Metadata has copy, store, drop { + /// NFT name's utf8 bytes. + name: vector, + /// Image link, such as ipfs://xxxx + image: vector, + /// Image bytes data, image or image_data can not empty for both. + image_data: vector, + /// NFT description utf8 bytes. + description: vector, + } + + public fun empty_meta(): Metadata { + Metadata { + name: Vector::empty(), + image: Vector::empty(), + image_data: Vector::empty(), + description: Vector::empty(), + } + } + + public fun new_meta(name: vector, description: vector): Metadata { + Metadata { + name, + image: Vector::empty(), + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image(name: vector, image: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image, + image_data: Vector::empty(), + description, + } + } + + public fun new_meta_with_image_data(name: vector, image_data: vector, description: vector): Metadata { + assert!(!Vector::is_empty(&name), Errors::invalid_argument(ERR_CANOT_EMPTY)); + assert!(!Vector::is_empty(&image_data), Errors::invalid_argument(ERR_CANOT_EMPTY)); + Metadata { + name, + image: Vector::empty(), + image_data, + description, + } + } + + public fun meta_name(metadata: &Metadata): vector { + *&metadata.name + } + + public fun meta_image(metadata: &Metadata): vector { + *&metadata.image + } + + public fun meta_image_data(metadata: &Metadata): vector { + *&metadata.image_data + } + + public fun meta_description(metadata: &Metadata): vector { + *&metadata.description + } + + struct NFT has store { + /// The creator of NFT + creator: address, + /// The unique id of NFT under NFTMeta type + id: u64, + /// The metadata of NFT + base_meta: Metadata, + /// The extension metadata of NFT + type_meta: NFTMeta, + /// The body of NFT, NFT is a box for NFTBody + body: NFTBody, + } + + /// The information of NFT instance return by get_nft_info + struct NFTInfo has copy, store, drop { + id: u64, + creator: address, + base_meta: Metadata, + type_meta: NFTMeta, + } + + public fun get_info(nft: &NFT): NFTInfo { + NFTInfo { + id: nft.id, + creator: nft.creator, + base_meta: *&nft.base_meta, + type_meta: *&nft.type_meta, + } + } + + public fun unpack_info( + nft_info: NFTInfo + ): (u64, address, Metadata, NFTMeta) { + let NFTInfo { id, creator, base_meta, type_meta } = nft_info; + (id, creator, base_meta, type_meta) + } + + public fun get_id(nft: &NFT): u64 { + return nft.id + } + + public fun get_base_meta(nft: &NFT): &Metadata { + return &nft.base_meta + } + + public fun get_type_meta(nft: &NFT): &NFTMeta { + return &nft.type_meta + } + + public fun get_creator(nft: &NFT): address { + return nft.creator + } + + /// deprecated. + public fun initialize(_signer: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, + /// in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability { + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register a NFT type to genesis + /// Note: this function is deprecated, please use `register_v2` + public fun register( + sender: &signer, + info: NFTTypeInfoExt, + meta: Metadata + ) acquires NFTTypeInfo { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + let type_info = new_nft_type_info(sender, info, meta); + move_to>(&genesis_account, type_info); + let mint_cap = MintCapability {}; + + Self::upgrade_nft_type_info_from_v1_to_v2(sender, &mut mint_cap); + + move_to>(sender, mint_cap); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Register a NFT type to genesis + public fun register_v2(sender: &signer, meta: Metadata) { + assert!(!is_registered(), Errors::invalid_argument(ERR_NFT_TYPE_ALREADY_REGISTERED)); + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + + let type_info = new_nft_type_info_v2(sender, meta); + move_to>(&genesis_account, type_info); + move_to>(sender, MintCapability {}); + move_to>(sender, BurnCapability {}); + move_to>(sender, UpdateCapability {}); + } + + /// Check the NFTMeta is register + public fun is_registered(): bool { + exists>(CoreAddresses::GENESIS_ADDRESS()) + } + + /// deprecated. Use "is_registered" instead. + public fun is_register(): bool { + is_registered() + } + + /// Add MintCapability to `sender` + public fun add_mint_capability(sender: &signer, cap: MintCapability) { + move_to(sender, cap); + } + + /// Remove the MintCapability from `sender` + public fun remove_mint_capability( + sender: &signer + ): MintCapability acquires MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the MintCapability + public fun destroy_mint_capability(cap: MintCapability) { + let MintCapability {} = cap; + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + /// Note: this function is deprecated, please use `mint_with_cap_v2` + public fun mint_with_cap( + creator: address, + cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2 { + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + mint_with_cap_v2(creator, cap, base_meta, type_meta, body) + } else { + let nft_type_info = + borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id: id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + } + + /// Mint nft with MintCapability, `creator` will been the NFT's creator. + public fun mint_with_cap_v2( + creator: address, + _cap: &mut MintCapability, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2 { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + nft_type_info.counter = nft_type_info.counter + 1; + let id = nft_type_info.counter; + let nft = NFT { + id, + creator, + base_meta: copy base_meta, + type_meta: copy type_meta, + body, + }; + Event::emit_event(&mut nft_type_info.mint_events, MintEvent { + id, + creator, + base_meta, + type_meta, + }); + nft + } + + /// Mint nft, the `sender` must have MintCapability + /// Note: this function is deprecated, please use `mint_v2` + public fun mint( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfo, NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap(addr, cap, base_meta, type_meta, body) + } + + /// Mint nft, the `sender` must have MintCapability + public fun mint_v2( + sender: &signer, + base_meta: Metadata, + type_meta: NFTMeta, + body: NFTBody + ): NFT acquires NFTTypeInfoV2, MintCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_MINT_CAPABILITY)); + let cap = borrow_global_mut>(addr); + mint_with_cap_v2(addr, cap, base_meta, type_meta, body) + } + + /// Add BurnCapability to `sender` + public fun add_burn_capability(sender: &signer, cap: BurnCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_burn_capability( + sender: &signer + ): BurnCapability acquires BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the BurnCapability + public fun destroy_burn_capability(cap: BurnCapability) { + let BurnCapability {} = cap; + } + + /// Burn nft with BurnCapability + public fun burn_with_cap( + _cap: &mut BurnCapability, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2 { + let NFT { creator: _, id: id, base_meta: _, type_meta: _, body } = nft; + // only NFTTypeInfoV2 has burn_events EventHandle + if (exists>(CoreAddresses::GENESIS_ADDRESS())) { + let nft_type_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + Event::emit_event(&mut nft_type_info.burn_events, BurnEvent { + id, + }); + }; + body + } + + /// Burn nft, the `sender` must have BurnCapability + public fun burn( + sender: &signer, + nft: NFT + ): NFTBody acquires NFTTypeInfoV2, BurnCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_BURN_CAPABILITY)); + let cap = borrow_global_mut>(addr); + burn_with_cap(cap, nft) + } + + /// Add UpdateCapability to `sender` + public fun add_update_capability(sender: &signer, cap: UpdateCapability) { + move_to(sender, cap); + } + + /// Remove the BurnCapability from `sender` + public fun remove_update_capability( + sender: &signer + ): UpdateCapability acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(addr) + } + + /// Destroy the UpdateCapability + public fun destroy_update_capability(cap: UpdateCapability) { + let UpdateCapability {} = cap; + } + + /// Update the NFTTypeInfoV2 metadata with UpdateCapability + public fun update_nft_type_info_meta_with_cap( + _cap: &mut UpdateCapability, + new_meta: Metadata + ) acquires NFTTypeInfoV2{ + let info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + info.meta = new_meta; + } + + /// Update the NFTTypeInfoV2 metadata, the `sender` must have UpdateCapability + public fun update_nft_type_info_meta( + sender: &signer, + new_meta: Metadata + ) acquires UpdateCapability, NFTTypeInfoV2 { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_nft_type_info_meta_with_cap(cap, new_meta) + } + + /// Update the nft's base_meta and type_meta with UpdateCapability + public fun update_meta_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT, + base_meta: Metadata, type_meta: NFTMeta + ) { + nft.base_meta = base_meta; + nft.type_meta = type_meta; + } + + /// Update the nft's base_meta and type_meta, the `sender` must have UpdateCapability + public fun update_meta( + sender: &signer, + nft: &mut NFT, + base_meta: Metadata, + type_meta: NFTMeta + ) acquires UpdateCapability { + let addr = Signer::address_of(sender); + assert!(exists>(addr), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(addr); + update_meta_with_cap(cap, nft, base_meta, type_meta) + } + + /// Borrow NFTBody ref + public fun borrow_body(nft: &NFT): &NFTBody { + &nft.body + } + + /// Borrow NFTBody mut ref for update body with UpdateCapability + public fun borrow_body_mut_with_cap( + _cap: &mut UpdateCapability, + nft: &mut NFT + ): &mut NFTBody { + &mut nft.body + } +} + +/// IdentifierNFT using NFT as identifier for an on chain account +/// The NFT can not been transfer by owner. +module IdentifierNFT { + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::NFT::{Self, NFT, MintCapability, BurnCapability, UpdateCapability}; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + const ERR_NFT_EXISTS: u64 = 101; + const ERR_NFT_NOT_EXISTS: u64 = 102; + const ERR_NFT_NOT_ACCEPT: u64 = 103; + const ERR_BORROW_ADDR_NOT_SAME: u64 = 104; + + spec module { + pragma verify = false; + } + + struct IdentifierNFT has key { + nft: Option>, + } + + //Used when borrowing or returning NFT, note: there is no drop ability, it must be returned after borrowing + struct BorrowNFT { + nft: NFT, + addr:address + } + + /// Check the `owner` is prepared with IdentifierNFT for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Accept NFT, prepare an empty IdentifierNFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let addr = Signer::address_of(sender); + if (!is_accept(addr)) { + move_to(sender, IdentifierNFT { + nft: Option::none(), + }); + } + } + + /// Destroy the empty IdentifierNFT + public entry fun destroy_empty_entry(sender: signer) acquires IdentifierNFT { + destroy_empty(&sender); + } + + public fun destroy_empty(sender: &signer) acquires IdentifierNFT { + let addr = Signer::address_of(sender); + if (exists>(addr)) { + let id_nft = move_from>(addr); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_none(nft); + } + } + + /// Grant nft as IdentifierNFT to `sender` with MintCapability, sender will auto accept the NFT. + public fun grant( + cap: &mut MintCapability, + sender: &signer, + nft: NFT + ) acquires IdentifierNFT { + Self::accept(sender); + Self::grant_to(cap, Signer::address_of(sender), nft); + } + + /// Grant nft as IdentifierNFT to `receiver` with MintCapability, the receiver should accept the NFT first. + public fun grant_to( + _cap: &mut MintCapability, + receiver: address, + nft: NFT + ) acquires IdentifierNFT { + assert!(exists>(receiver), Errors::not_published(ERR_NFT_NOT_ACCEPT)); + let id_nft = borrow_global_mut>(receiver); + assert!(Option::is_none(&id_nft.nft), Errors::already_published(ERR_NFT_EXISTS)); + Option::fill(&mut id_nft.nft, nft); + } + + /// Revoke the NFT from owner. + public fun revoke( + _cap: &mut BurnCapability, + owner: address + ): NFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = move_from>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let IdentifierNFT { nft } = id_nft; + Option::destroy_some(nft) + } + + /// borrow_out the NFT from owner. + public fun borrow_out( + _cap: &mut UpdateCapability, + owner: address + ): BorrowNFT acquires IdentifierNFT { + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let id_nft = borrow_global_mut>(owner); + assert!(Option::is_some(&id_nft.nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + + let nft = Option::extract(&mut id_nft.nft); + + BorrowNFT{ + nft : nft, + addr: owner + } + } + + /// return_back the NFT to owner. + public fun return_back( + borrownft: BorrowNFT, + ) acquires IdentifierNFT { + + let BorrowNFT{ + nft: nft, + addr: owner + } = borrownft ; + assert!(exists>(owner), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let id_nft = borrow_global_mut>(owner); + + Option::fill(&mut id_nft.nft , nft) + } + + public fun borrow_nft( + borrownft:&BorrowNFT + ) : & NFT { + & borrownft.nft + } + + public fun borrow_nft_mut ( + borrownft:&mut BorrowNFT + ) : &mut NFT { + &mut borrownft.nft + } + + /// Check `owner` is owns the IdentifierNFT + public fun owns(owner: address): bool acquires IdentifierNFT { + if (!exists>(owner)) { + return false + }; + let id_nft = borrow_global>(owner); + Option::is_some(&id_nft.nft) + } + /// deprecated. Use `owns()` instead. + public fun is_owns(owner: address): bool acquires IdentifierNFT { + owns(owner) + } + + public fun get_nft_info( + owner: address + ): Option> acquires IdentifierNFT { + if (!exists>(owner)) { + return Option::none>() + }; + let id_nft = borrow_global>(owner); + let info = if (Option::is_some(&id_nft.nft)) { + let nft = Option::borrow(&id_nft.nft); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + info + } +} + +module IdentifierNFTScripts { + use StarcoinFramework::IdentifierNFT; + spec module { + pragma verify = false; + } + + /// Init IdentifierNFT for accept NFT as Identifier. + public entry fun accept(sender: signer) { + IdentifierNFT::accept_entry(sender); + } + + /// Destroy empty IdentifierNFT + public entry fun destroy_empty(sender: signer) { + IdentifierNFT::destroy_empty_entry(sender); + } +} + +/// NFTGallery is user collection of NFT. +module NFTGallery { + use StarcoinFramework::Signer; + use StarcoinFramework::NFT::{Self, NFT}; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::Event; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + + const ERR_NFT_NOT_EXISTS: u64 = 101; + + const ERR_NFTGALLERY_NOT_EXISTS:u64 = 102; + + spec module { + pragma verify = false; + } + + struct WithdrawEvent has drop, store { + owner: address, + id: u64, + } + + struct DepositEvent has drop, store { + owner: address, + id: u64, + } + + struct NFTGallery has key, store { + withdraw_events: Event::EventHandle>, + deposit_events: Event::EventHandle>, + items: vector>, + } + + /// Check the `owner` is prepared with NFTGallery for accept the NFT + public fun is_accept(owner: address): bool { + exists>(owner) + } + + /// Init a NFTGallery to accept NFT for `sender` + public entry fun accept_entry(sender: signer) { + accept(&sender); + } + + public fun accept(sender: &signer) { + let sender_addr = Signer::address_of(sender); + if (!is_accept(sender_addr)) { + let gallery = NFTGallery { + withdraw_events: Event::new_event_handle>(sender), + deposit_events: Event::new_event_handle>(sender), + items: Vector::empty>(), + }; + move_to(sender, gallery); + } + } + + /// Transfer NFT from `sender` to `receiver` + public entry fun transfer_entry( + sender: signer, + id: u64, receiver: address + ) acquires NFTGallery { + transfer(&sender, id, receiver); + } + + public fun transfer( + sender: &signer, + id: u64, + receiver: address + ) acquires NFTGallery { + let nft = withdraw(sender, id); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + let nft = Option::destroy_some(nft); + deposit_to(receiver, nft) + } + + /// Get the NFT info by the NFT id. + public fun get_nft_info_by_id( + owner: address, + id: u64 + ): Option> acquires NFTGallery { + if(!is_accept(owner)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(owner); + let idx = find_by_id(&gallery.items, id); + + let info = if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::borrow>(&gallery.items, i); + Option::some(NFT::get_info(nft)) + } else { + Option::none>() + }; + return info + } + + /// Get the NFT info by the NFT idx in NFTGallery + public fun get_nft_info_by_idx( + owner: address, + idx: u64 + ): NFT::NFTInfo acquires NFTGallery { + assert!(exists>(owner), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(owner); + let nft = Vector::borrow>(&gallery.items, idx); + NFT::get_info(nft) + } + + /// Get the all NFT info + public fun get_nft_infos( + owner: address + ): vector> acquires NFTGallery { + if(!is_accept(owner)){ + return Vector::empty>() + }; + let gallery = borrow_global_mut>(owner); + let infos = Vector::empty(); + let len = Vector::length(&gallery.items); + let idx = 0; + while (len > idx) { + let nft = Vector::borrow>(&gallery.items, idx); + Vector::push_back(&mut infos, NFT::get_info(nft)); + idx = idx + 1; + }; + infos + } + + /// Deposit nft to `sender` NFTGallery + public fun deposit( + sender: &signer, + nft: NFT + ) acquires NFTGallery { + Self::accept(sender); + let sender_addr = Signer::address_of(sender); + deposit_to(sender_addr, nft) + } + + /// Deposit nft to `receiver` NFTGallery + public fun deposit_to( + receiver: address, + nft: NFT + ) acquires NFTGallery { + assert!(exists>(receiver), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let gallery = borrow_global_mut>(receiver); + Event::emit_event(&mut gallery.deposit_events, DepositEvent { id: NFT::get_id(&nft), owner: receiver }); + Vector::push_back(&mut gallery.items, nft); + } + + /// Withdraw one nft of NFTMeta from `sender`, caller should ensure at least one NFT in the Gallery. + public fun withdraw_one( + sender: &signer + ): NFT acquires NFTGallery { + let nft = do_withdraw(sender, Option::none()); + assert!(Option::is_some(&nft), Errors::not_published(ERR_NFT_NOT_EXISTS)); + Option::destroy_some(nft) + } + + /// Withdraw nft of NFTMeta and id from `sender` + public fun withdraw( + sender: &signer, + id: u64 + ): Option> acquires NFTGallery { + do_withdraw(sender, Option::some(id)) + } + + /// Withdraw nft of NFTMeta and id from `sender` + fun do_withdraw( + sender: &signer, + id: Option + ): Option> acquires NFTGallery { + let sender_addr = Signer::address_of(sender); + if(!is_accept(sender_addr)){ + return Option::none>() + }; + let gallery = borrow_global_mut>(sender_addr); + let len = Vector::length(&gallery.items); + let nft = if (len == 0) { + Option::none() + } else { + let idx = if (Option::is_some(&id)) { + let id = Option::extract(&mut id); + find_by_id(&gallery.items, id) + } else { + //default withdraw the last nft. + Option::some(len - 1) + }; + + if (Option::is_some(&idx)) { + let i = Option::extract(&mut idx); + let nft = Vector::remove>(&mut gallery.items, i); + Event::emit_event( + &mut gallery.withdraw_events, + WithdrawEvent { id: NFT::get_id(&nft), owner: sender_addr } + ); + Option::some(nft) + } else { + Option::none() + } + }; + nft + } + + fun find_by_id( + c: &vector>, + id: u64 + ): Option { + let len = Vector::length(c); + if (len == 0) { + return Option::none() + }; + let idx = len - 1; + loop { + let nft = Vector::borrow(c, idx); + if (NFT::get_id(nft) == id) { + return Option::some(idx) + }; + if (idx == 0) { + return Option::none() + }; + idx = idx - 1; + } + } + + /// Count all NFTs assigned to an owner + public fun count_of(owner: address): u64 acquires NFTGallery { + if(!is_accept(owner)){ + return 0 + }; + let gallery = borrow_global_mut>(owner); + Vector::length(&gallery.items) + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery_entry(sender: signer) acquires NFTGallery { + remove_empty_gallery(&sender); + } + + public fun remove_empty_gallery(sender: &signer) acquires NFTGallery{ + let sender_addr = Signer::address_of(sender); + assert!(exists>(sender_addr), Errors::not_published(ERR_NFTGALLERY_NOT_EXISTS)); + let NFTGallery {withdraw_events, deposit_events, items} = move_from>(sender_addr); + + Event::destroy_handle>(withdraw_events); + Event::destroy_handle>(deposit_events); + Vector::destroy_empty>(items); + } + + spec remove_empty_gallery { + let sender_addr = Signer::address_of(sender); + aborts_if !exists>(sender_addr); + + let gallery = global>(sender_addr); + aborts_if Vector::length>(gallery.items) > 0; + + ensures !exists>(sender_addr); + } + +} + +module NFTGalleryScripts { + use StarcoinFramework::NFTGallery; + + spec module { + pragma verify = false; + } + + /// Init a NFTGallery for accept NFT + public entry fun accept(sender: signer) { + NFTGallery::accept_entry(sender); + } + /// Transfer NFT with `id` from `sender` to `receiver` + public entry fun transfer( + sender: signer, + id: u64, receiver: address + ) { + NFTGallery::transfer_entry(sender, id, receiver); + } + + /// Remove empty NFTGallery. + public entry fun remove_empty_gallery(sender: signer) { + NFTGallery::remove_empty_gallery_entry(sender); + } +} +} diff --git a/release/v13/sources/Offer.move b/release/v13/sources/Offer.move new file mode 100644 index 00000000..cb406860 --- /dev/null +++ b/release/v13/sources/Offer.move @@ -0,0 +1,84 @@ +address StarcoinFramework { +module Offer { + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::Collection2; + + spec module { + pragma verify = true; + pragma aborts_if_is_strict = true; + } + + /// A wrapper around value `offered` that can be claimed by the address stored in `for` when after lock time. + struct Offer has key { offered: Offered, for: address, time_lock: u64 } + + /// An offer of the specified type for the account does not match + const EOFFER_DNE_FOR_ACCOUNT: u64 = 101; + + /// Offer is not unlocked yet. + const EOFFER_NOT_UNLOCKED: u64 = 102; + + /// Publish a value of type `Offered` under the sender's account. The value can be claimed by + /// either the `for` address or the transaction sender. + public fun create(account: &signer, offered: Offered, for: address, lock_period: u64) { + let time_lock = Timestamp::now_seconds() + lock_period; + //TODO should support multi Offer? + move_to(account, Offer { offered, for, time_lock }); + } + + spec create { + include Timestamp::AbortsIfTimestampNotExists; + aborts_if Timestamp::now_seconds() + lock_period > max_u64(); + aborts_if exists>(Signer::address_of(account)); + } + + /// Claim the value of type `Offered` published at `offer_address`. + /// Only succeeds if the sender is the intended recipient stored in `for` or the original + /// publisher `offer_address`, and now >= time_lock + /// Also fails if no such value exists. + public fun redeem(account: &signer, offer_address: address): Offered acquires Offer { + let Offer { offered, for, time_lock } = move_from>(offer_address); + let sender = Signer::address_of(account); + let now = Timestamp::now_seconds(); + assert!(sender == for || sender == offer_address, Errors::invalid_argument(EOFFER_DNE_FOR_ACCOUNT)); + assert!(now >= time_lock, Errors::not_published(EOFFER_NOT_UNLOCKED)); + offered + } + + spec redeem { + aborts_if !exists>(offer_address); + aborts_if Signer::address_of(account) != global>(offer_address).for && Signer::address_of(account) != offer_address; + aborts_if Timestamp::now_seconds() < global>(offer_address).time_lock; + include Timestamp::AbortsIfTimestampNotExists; + } + + /// Returns true if an offer of type `Offered` exists at `offer_address`. + public fun exists_at(offer_address: address): bool { + exists>(offer_address) + } + + spec exists_at {aborts_if false;} + + /// Returns the address of the `Offered` type stored at `offer_address`. + /// Fails if no such `Offer` exists. + public fun address_of(offer_address: address): address acquires Offer { + borrow_global>(offer_address).for + } + + spec address_of {aborts_if !exists>(offer_address);} + + /// Take Offer and put to signer's Collection. + public entry fun take_offer( + signer: signer, + offer_address: address, + ) acquires Offer { + let offered = redeem(&signer, offer_address); + Collection2::put(&signer, Signer::address_of(&signer), offered); + } + + spec take_offer { + pragma verify = false; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/OnChainConfigDao.move b/release/v13/sources/OnChainConfigDao.move new file mode 100644 index 00000000..a92e9889 --- /dev/null +++ b/release/v13/sources/OnChainConfigDao.move @@ -0,0 +1,97 @@ +address StarcoinFramework { +/// OnChainConfigDao is a DAO proposal for modify onchain configuration. +module OnChainConfigDao { + use StarcoinFramework::Token; + use StarcoinFramework::Signer; + use StarcoinFramework::Config; + use StarcoinFramework::Dao; + use StarcoinFramework::Errors; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_strict; + pragma aborts_if_is_partial; + } + + /// A wrapper of `Config::ModifyConfigCapability`. + struct WrappedConfigModifyCapability has key { + cap: Config::ModifyConfigCapability, + } + + /// request of updating configuration. + struct OnChainConfigUpdate has copy, drop, store { + value: ConfigT, + } + + const ERR_NOT_AUTHORIZED: u64 = 401; + + /// Plugin method of the module. + /// Should be called by token issuer. + public fun plugin(signer: &signer) { + let token_issuer = Token::token_address(); + assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + let config_modify_cap = Config::extract_modify_config_capability(signer); + let cap = WrappedConfigModifyCapability { cap: config_modify_cap }; + move_to(signer, cap); + } + spec plugin { + pragma aborts_if_is_partial = false; + let sender = Signer::address_of(signer); + aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS(); + include Config::AbortsIfCapNotExist{address: sender}; + aborts_if exists>(sender); + ensures exists>(sender); + } + + /// issue a proposal to update config of ConfigT goved by TokenT + public fun propose_update( + signer: &signer, + new_config: ConfigT, + exec_delay: u64, + ) { + Dao::propose>( + signer, + OnChainConfigUpdate { value: new_config }, + exec_delay, + ); + } + + spec propose_update { + use StarcoinFramework::Timestamp; + use StarcoinFramework::CoreAddresses; + pragma aborts_if_is_partial = false; + + // copy from Dao::propose spec. + include Dao::AbortIfDaoConfigNotExist; + include Dao::AbortIfDaoInfoNotExist; + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config().min_action_delay; + include Dao::CheckQuorumVotes; + let sender = Signer::address_of(signer); + aborts_if exists>>(sender); + } + + /// Once the proposal is agreed, anyone can call the method to make the proposal happen. + /// Caller need to make sure that the proposal of `proposal_id` under `proposal_address` is + /// the kind of this proposal module. + public fun execute( + proposer_address: address, + proposal_id: u64, + ) acquires WrappedConfigModifyCapability { + let OnChainConfigUpdate { value } = Dao::extract_proposal_action< + TokenT, + OnChainConfigUpdate, + >(proposer_address, proposal_id); + let cap = borrow_global_mut>( + Token::token_address(), + ); + Config::set_with_capability(&mut cap.cap, value); + } + spec execute { + pragma aborts_if_is_partial = true; + let expected_states = vec(6); + include Dao::CheckProposalStates>{expected_states}; + aborts_if !exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/OnChainConfigScripts.move b/release/v13/sources/OnChainConfigScripts.move new file mode 100644 index 00000000..7bc0bc29 --- /dev/null +++ b/release/v13/sources/OnChainConfigScripts.move @@ -0,0 +1,148 @@ +address StarcoinFramework { +module OnChainConfigScripts { + use StarcoinFramework::FlexiDagConfig; + use StarcoinFramework::ConsensusConfig; + use StarcoinFramework::OnChainConfigDao; + use StarcoinFramework::STC; + use StarcoinFramework::RewardConfig; + use StarcoinFramework::TransactionPublishOption; + use StarcoinFramework::TransactionTimeoutConfig; + use StarcoinFramework::VMConfig; + use StarcoinFramework::Signer; + use StarcoinFramework::LanguageVersion; + + public entry fun propose_update_consensus_config(account: signer, + uncle_rate_target: u64, + base_block_time_target: u64, + base_reward_per_block: u128, + base_reward_per_uncle_percent: u64, + epoch_block_count: u64, + base_block_difficulty_window: u64, + min_block_time_target: u64, + max_block_time_target: u64, + base_max_uncles_per_block: u64, + base_block_gas_limit: u64, + strategy: u8, + exec_delay: u64) { + let consensus_config = ConsensusConfig::new_consensus_config(uncle_rate_target, + base_block_time_target, + base_reward_per_block, + base_reward_per_uncle_percent, + epoch_block_count, + base_block_difficulty_window, + min_block_time_target, + max_block_time_target, + base_max_uncles_per_block, + base_block_gas_limit, + strategy); + OnChainConfigDao::propose_update(&account, consensus_config, exec_delay); + } + + spec propose_update_consensus_config { + pragma verify = false; + } + + public entry fun propose_update_reward_config(account: signer, + reward_delay: u64, + exec_delay: u64) { + let reward_config = RewardConfig::new_reward_config(reward_delay); + OnChainConfigDao::propose_update(&account, reward_config, exec_delay); + } + + spec propose_update_reward_config { + pragma verify = false; + } + + public entry fun propose_update_txn_publish_option(account: signer, + script_allowed: bool, + module_publishing_allowed: bool, + exec_delay: u64) { + let txn_publish_option = TransactionPublishOption::new_transaction_publish_option(script_allowed, module_publishing_allowed); + OnChainConfigDao::propose_update(&account, txn_publish_option, exec_delay); + } + + spec propose_update_txn_publish_option { + pragma verify = false; + } + + public entry fun propose_update_txn_timeout_config(account: signer, + duration_seconds: u64, + exec_delay: u64) { + let txn_timeout_config = TransactionTimeoutConfig::new_transaction_timeout_config(duration_seconds); + OnChainConfigDao::propose_update(&account, txn_timeout_config, exec_delay); + } + + spec propose_update_txn_timeout_config { + pragma verify = false; + } + + public entry fun propose_update_vm_config(account: signer, + instruction_schedule: vector, + native_schedule: vector, + global_memory_per_byte_cost: u64, + global_memory_per_byte_write_cost: u64, + min_transaction_gas_units: u64, + large_transaction_cutoff: u64, + instrinsic_gas_per_byte: u64, + maximum_number_of_gas_units: u64, + min_price_per_gas_unit: u64, + max_price_per_gas_unit: u64, + max_transaction_size_in_bytes: u64, + gas_unit_scaling_factor: u64, + default_account_size: u64, + exec_delay: u64, ) { + let vm_config = VMConfig::new_vm_config(instruction_schedule, + native_schedule, + global_memory_per_byte_cost, + global_memory_per_byte_write_cost, + min_transaction_gas_units, + large_transaction_cutoff, + instrinsic_gas_per_byte, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit, + max_transaction_size_in_bytes, + gas_unit_scaling_factor, + default_account_size); + OnChainConfigDao::propose_update(&account, vm_config, exec_delay); + } + + spec propose_update_vm_config { + pragma verify = false; + } + + public entry fun propose_update_move_language_version(account: signer, new_version: u64, exec_delay: u64) { + let lang_version = LanguageVersion::new(new_version); + OnChainConfigDao::propose_update(&account, lang_version, exec_delay); + } + + spec propose_update_move_language_version { + pragma verify = false; + } + + public entry fun propose_update_flexi_dag_effective_height(account: signer, new_height: u64, exec_delay: u64) { + let config = FlexiDagConfig::new_flexidag_config(new_height); + OnChainConfigDao::propose_update(&account, config, exec_delay); + } + + spec propose_update_flexi_dag_effective_height { + pragma verify = false; + } + + public entry fun execute_on_chain_config_proposal(account: signer, proposal_id: u64) { + OnChainConfigDao::execute(Signer::address_of(&account), proposal_id); + } + + spec execute_on_chain_config_proposal { + pragma verify = false; + } + + public entry fun execute_on_chain_config_proposal_v2(proposer_address: address, proposal_id: u64) { + OnChainConfigDao::execute(proposer_address, proposal_id); + } + + spec execute_on_chain_config_proposal_v2 { + pragma verify = false; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Option.move b/release/v13/sources/Option.move new file mode 100644 index 00000000..8baad1e0 --- /dev/null +++ b/release/v13/sources/Option.move @@ -0,0 +1,235 @@ +address StarcoinFramework { + +/// This module defines the Option type and its methods to represent and handle an optional value. +module Option { + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + + /// Abstraction of a value that may or may not be present. Implemented with a vector of size + /// zero or one because Move bytecode does not have ADTs. + struct Option has copy, drop, store { + vec: vector + } + spec Option { + /// The size of vector is always less than equal to 1 + /// because it's 0 for "none" or 1 for "some". + invariant len(vec) <= 1; + } + + /// The `Option` is in an invalid state for the operation attempted. + /// The `Option` is `Some` while it should be `None`. + const EOPTION_IS_SET: u64 = 0; + /// The `Option` is in an invalid state for the operation attempted. + /// The `Option` is `None` while it should be `Some`. + const EOPTION_NOT_SET: u64 = 1; + + /// Return an empty `Option` + public fun none(): Option { + Option { vec: Vector::empty() } + } + spec none { + pragma opaque; + aborts_if false; + ensures result == spec_none(); + } + spec fun spec_none(): Option { + Option{ vec: vec() } + } + + /// Return an `Option` containing `e` + public fun some(e: Element): Option { + Option { vec: Vector::singleton(e) } + } + spec some { + pragma opaque; + aborts_if false; + ensures result == spec_some(e); + } + spec fun spec_some(e: Element): Option { + Option{ vec: vec(e) } + } + + /// Return true if `t` does not hold a value + public fun is_none(t: &Option): bool { + Vector::is_empty(&t.vec) + } + spec is_none { + pragma opaque; + aborts_if false; + ensures result == is_none(t); + } + + /// Return true if `t` holds a value + public fun is_some(t: &Option): bool { + !Vector::is_empty(&t.vec) + } + spec is_some { + pragma opaque; + aborts_if false; + ensures result == is_some(t); + } + + /// Return true if the value in `t` is equal to `e_ref` + /// Always returns `false` if `t` does not hold a value + public fun contains(t: &Option, e_ref: &Element): bool { + Vector::contains(&t.vec, e_ref) + } + spec contains { + pragma opaque; + aborts_if false; + ensures result == spec_contains(t, e_ref); + } + spec fun spec_contains(t: Option, e: Element): bool { + is_some(t) && borrow(t) == e + } + + /// Return an immutable reference to the value inside `t` + /// Aborts if `t` does not hold a value + public fun borrow(t: &Option): &Element { + assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET)); + Vector::borrow(&t.vec, 0) + } + spec borrow { + pragma opaque; + include AbortsIfNone; + ensures result == borrow(t); + } + + /// Return a reference to the value inside `t` if it holds one + /// Return `default_ref` if `t` does not hold a value + public fun borrow_with_default(t: &Option, default_ref: &Element): &Element { + let vec_ref = &t.vec; + if (Vector::is_empty(vec_ref)) default_ref + else Vector::borrow(vec_ref, 0) + } + spec borrow_with_default { + pragma opaque; + aborts_if false; + ensures result == (if (is_some(t)) borrow(t) else default_ref); + } + + /// Return the value inside `t` if it holds one + /// Return `default` if `t` does not hold a value + public fun get_with_default( + t: &Option, + default: Element, + ): Element { + let vec_ref = &t.vec; + if (Vector::is_empty(vec_ref)) default + else *Vector::borrow(vec_ref, 0) + } + spec get_with_default { + pragma opaque; + aborts_if false; + ensures result == (if (is_some(t)) borrow(t) else default); + } + + /// Convert the none option `t` to a some option by adding `e`. + /// Aborts if `t` already holds a value + public fun fill(t: &mut Option, e: Element) { + let vec_ref = &mut t.vec; + if (Vector::is_empty(vec_ref)) Vector::push_back(vec_ref, e) + else abort Errors::invalid_argument(EOPTION_IS_SET) + } + spec fill { + pragma opaque; + aborts_if is_some(t) with Errors::INVALID_ARGUMENT; + ensures is_some(t); + ensures borrow(t) == e; + } + + /// Convert a `some` option to a `none` by removing and returning the value stored inside `t` + /// Aborts if `t` does not hold a value + public fun extract(t: &mut Option): Element { + assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET)); + Vector::pop_back(&mut t.vec) + } + spec extract { + pragma opaque; + include AbortsIfNone; + ensures result == borrow(old(t)); + ensures is_none(t); + } + + /// Return a mutable reference to the value inside `t` + /// Aborts if `t` does not hold a value + public fun borrow_mut(t: &mut Option): &mut Element { + assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET)); + Vector::borrow_mut(&mut t.vec, 0) + } + spec borrow_mut { + pragma opaque; + include AbortsIfNone; + ensures result == borrow(t); + } + + /// Swap the old value inside `t` with `e` and return the old value + /// Aborts if `t` does not hold a value + public fun swap(t: &mut Option, e: Element): Element { + assert!(is_some(t), Errors::invalid_argument(EOPTION_NOT_SET)); + let vec_ref = &mut t.vec; + let old_value = Vector::pop_back(vec_ref); + Vector::push_back(vec_ref, e); + old_value + } + spec swap { + pragma opaque; + include AbortsIfNone; + ensures result == borrow(old(t)); + ensures is_some(t); + ensures borrow(t) == e; + } + + /// Destroys `t.` If `t` holds a value, return it. Returns `default` otherwise + public fun destroy_with_default(t: Option, default: Element): Element { + let Option { vec } = t; + if (Vector::is_empty(&mut vec)) default + else Vector::pop_back(&mut vec) + } + spec destroy_with_default { + pragma opaque; + aborts_if false; + ensures result == (if (is_some(t)) borrow(t) else default); + } + + /// Unpack `t` and return its contents + /// Aborts if `t` does not hold a value + public fun destroy_some(t: Option): Element { + assert!(is_some(&t), Errors::invalid_argument(EOPTION_NOT_SET)); + let Option { vec } = t; + let elem = Vector::pop_back(&mut vec); + Vector::destroy_empty(vec); + elem + } + spec destroy_some { + pragma opaque; + include AbortsIfNone; + ensures result == borrow(t); + } + + /// Unpack `t` + /// Aborts if `t` holds a value + public fun destroy_none(t: Option) { + assert!(is_none(&t), Errors::invalid_argument(EOPTION_IS_SET)); + let Option { vec } = t; + Vector::destroy_empty(vec) + } + spec destroy_none { + pragma opaque; + aborts_if is_some(t) with Errors::INVALID_ARGUMENT; + } + + spec module {} // switch documentation context back to module level + + spec module { + pragma aborts_if_is_strict; + } + + /// # Helper Schema + + spec schema AbortsIfNone { + t: Option; + aborts_if is_none(t) with Errors::INVALID_ARGUMENT; + } +} +} diff --git a/release/v13/sources/Oracle.move b/release/v13/sources/Oracle.move new file mode 100644 index 00000000..9241b263 --- /dev/null +++ b/release/v13/sources/Oracle.move @@ -0,0 +1,325 @@ +address StarcoinFramework { +module Oracle { + use StarcoinFramework::Event; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::Vector; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Account; + use StarcoinFramework::GenesisSignerCapability; + + struct OracleInfo has key { + ///The datasource counter + counter: u64, + ///Ext info + info: Info, + } + + struct DataRecord has copy, store, drop { + ///The data version + version: u64, + ///The record value + value: ValueT, + ///Update timestamp millisecond + updated_at: u64, + } + + struct OracleFeed has key { + record: DataRecord, + } + + struct OracleUpdateEvent has copy,store,drop { + source_id: u64, + record: DataRecord, + } + + struct DataSource has key { + /// the id of data source of ValueT + id: u64, + /// the data version counter. + counter: u64, + update_events: Event::EventHandle>, + } + + struct UpdateCapability has store, key { + account: address, + } + + struct GenesisSignerCapability has key{ + cap: Account::SignerCapability, + } + + /// The oracle type not register. + const ERR_ORACLE_TYPE_NOT_REGISTER:u64 = 101; + /// No capability to update the oracle value. + const ERR_NO_UPDATE_CAPABILITY: u64 = 102; + const ERR_NO_DATA_SOURCE: u64 = 103; + const ERR_CAPABILITY_ACCOUNT_MISS_MATCH: u64 = 104; + + /// deprecated. + public fun initialize(_sender: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability{ + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register `OracleT` as an oracle type. + public fun register_oracle(_sender: &signer, info: Info) { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + move_to(&genesis_account, OracleInfo { + counter: 0, + info, + }); + } + + /// Get the `OracleT` oracle's counter, the counter represent how many `OracleT` datasources + public fun get_oracle_counter() : u64 acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + oracle_info.counter + } + + public fun get_oracle_info() : Info acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&oracle_info.info + } + + /// Init a data source for type `OracleT` + public fun init_data_source(sender: &signer, init_value: ValueT) acquires OracleInfo{ + assert!(exists>(CoreAddresses::GENESIS_ADDRESS()), Errors::not_published(ERR_ORACLE_TYPE_NOT_REGISTER)); + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + let now = Timestamp::now_milliseconds(); + move_to(sender, OracleFeed { + record: DataRecord { + version: 0, + value: init_value, + updated_at: now, + } + }); + let sender_addr = Signer::address_of(sender); + move_to(sender, DataSource { + id: oracle_info.counter, + counter: 1, + update_events: Event::new_event_handle>(sender), + }); + move_to(sender, UpdateCapability{account: sender_addr}); + oracle_info.counter = oracle_info.counter + 1; + } + + /// Check the DataSource is initiailzed at ds_addr + public fun is_data_source_initialized(ds_addr: address): bool { + exists>(ds_addr) + } + + /// Update Oracle's record with new value, the `sender` must have UpdateCapability + public fun update(sender: &signer, value: ValueT) acquires UpdateCapability, DataSource, OracleFeed{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(account); + update_with_cap(cap,value); + } + + /// Update Oracle's record with new value and UpdateCapability + public fun update_with_cap(cap: &mut UpdateCapability, value: ValueT) acquires DataSource,OracleFeed { + let account = cap.account; + assert!(exists>(account), Errors::requires_capability(ERR_NO_DATA_SOURCE)); + let source = borrow_global_mut>(account); + let now = Timestamp::now_milliseconds(); + let oracle_feed = borrow_global_mut>(account); + oracle_feed.record.version = source.counter; + oracle_feed.record.value = value; + oracle_feed.record.updated_at = now; + source.counter = source.counter + 1; + Event::emit_event(&mut source.update_events,OracleUpdateEvent{ + source_id: source.id, + record: *&oracle_feed.record + }); + } + + /// Read the Oracle's value from `ds_addr` + public fun read(ds_addr: address): ValueT acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record.value + } + + /// Read the Oracle's DataRecord from `ds_addr` + public fun read_record(ds_addr: address): DataRecord acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record + } + + /// Batch read Oracle's DataRecord from `ds_addrs` + public fun read_records(ds_addrs: &vector
): vector> acquires OracleFeed{ + let len = Vector::length(ds_addrs); + let results = Vector::empty(); + let i = 0; + while (i < len){ + let addr = *Vector::borrow(ds_addrs, i); + let record = Self::read_record(addr); + Vector::push_back(&mut results, record); + i = i + 1; + }; + results + } + + /// Remove UpdateCapability from current sender. + public fun remove_update_capability(sender: &signer):UpdateCapability acquires UpdateCapability{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(account) + } + + /// Add UpdateCapability to current sender + public fun add_update_capability(sender: &signer, update_cap: UpdateCapability){ + assert!(Signer::address_of(sender) == update_cap.account, Errors::invalid_argument(ERR_CAPABILITY_ACCOUNT_MISS_MATCH)); + move_to(sender, update_cap); + } + + /// Unpack Record to fields: version, oracle, updated_at. + public fun unpack_record(record: DataRecord):(u64, ValueT, u64) { + (record.version,*&record.value,record.updated_at) + } +} +module PriceOracle{ + use StarcoinFramework::Math; + use StarcoinFramework::Oracle::{Self, DataRecord, UpdateCapability}; + + struct PriceOracleInfo has copy,store,drop{ + scaling_factor: u128, + } + + public entry fun register_oracle_entry(sender: signer, precision: u8){ + register_oracle(&sender, precision); + } + + public fun register_oracle(sender: &signer, precision: u8){ + let scaling_factor = Math::pow(10, (precision as u64)); + Oracle::register_oracle(sender, PriceOracleInfo{ + scaling_factor, + }); + } + + + public entry fun init_data_source_entry(sender: signer, init_value: u128){ + init_data_source(&sender, init_value); + } + + public fun init_data_source(sender: &signer, init_value: u128){ + Oracle::init_data_source(sender, init_value); + } + + public fun is_data_source_initialized(ds_addr: address): bool{ + Oracle::is_data_source_initialized(ds_addr) + } + + public fun get_scaling_factor() : u128 { + let info = Oracle::get_oracle_info(); + info.scaling_factor + } + + public entry fun update_entry(sender: signer, value: u128){ + update(&sender, value); + } + + public fun update(sender: &signer, value: u128){ + Oracle::update(sender, value); + } + + public fun update_with_cap(cap: &mut UpdateCapability, value: u128) { + Oracle::update_with_cap(cap, value); + } + + public fun read(addr: address) : u128{ + Oracle::read(addr) + } + + public fun read_record(addr: address): DataRecord{ + Oracle::read_record(addr) + } + + public fun read_records(addrs: &vector
): vector>{ + Oracle::read_records(addrs) + } + +} + +module STCUSDOracle{ + use StarcoinFramework::Oracle::{DataRecord}; + use StarcoinFramework::PriceOracle::{Self}; + + /// The STC to USD price oracle + struct STCUSD has copy,store,drop {} + + public fun register(sender: &signer){ + PriceOracle::register_oracle(sender, 6); + } + + public fun read(ds_addr: address) : u128{ + PriceOracle::read(ds_addr) + } + + public fun read_record(ds_addr: address): DataRecord{ + PriceOracle::read_record(ds_addr) + } + + public fun read_records(ds_addrs: &vector
): vector>{ + PriceOracle::read_records(ds_addrs) + } +} + +module PriceOracleScripts{ + use StarcoinFramework::PriceOracle; + + public entry fun register_oracle(sender: signer, precision: u8){ + PriceOracle::register_oracle_entry(sender, precision); + } + + public entry fun init_data_source(sender: signer, init_value: u128){ + PriceOracle::init_data_source_entry(sender, init_value); + } + + public entry fun update(sender: signer, value: u128){ + PriceOracle::update_entry(sender, value); + } +} + +module PriceOracleAggregator{ + use StarcoinFramework::Vector; + use StarcoinFramework::Oracle; + use StarcoinFramework::PriceOracle; + use StarcoinFramework::Math; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Errors; + + /// No price data match requirement condition. + const ERR_NO_PRICE_DATA_AVIABLE:u64 = 101; + + /// Get latest price from datasources and calculate avg. + /// `addrs`: the datasource's addr, `updated_in`: the datasource should updated in x millseoconds. + public fun latest_price_average_aggregator(addrs: &vector
, updated_in: u64): u128 { + let len = Vector::length(addrs); + let price_records = PriceOracle::read_records(addrs); + let prices = Vector::empty(); + let i = 0; + let expect_updated_after = Timestamp::now_milliseconds() - updated_in; + while (i < len){ + let record = Vector::pop_back(&mut price_records); + let (_version, price, updated_at) = Oracle::unpack_record(record); + if (updated_at >= expect_updated_after) { + Vector::push_back(&mut prices, price); + }; + i = i + 1; + }; + // if all price data not match the update_in filter, abort. + assert!(!Vector::is_empty(&prices), Errors::invalid_state(ERR_NO_PRICE_DATA_AVIABLE)); + Math::avg(&prices) + } +} + + +} \ No newline at end of file diff --git a/release/v13/sources/PackageTxnManager.move b/release/v13/sources/PackageTxnManager.move new file mode 100644 index 00000000..0fb41ee4 --- /dev/null +++ b/release/v13/sources/PackageTxnManager.move @@ -0,0 +1,469 @@ +address StarcoinFramework { + /// The module provides strategies for module upgrading. + module PackageTxnManager { + use StarcoinFramework::Option::{Self,Option}; + use StarcoinFramework::Signer; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Version; + use StarcoinFramework::Event; + use StarcoinFramework::Config; + use StarcoinFramework::Timestamp; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + /// module upgrade plan + struct UpgradePlan has copy, drop, store { + package_hash: vector, + active_after_time: u64, + version: u64, + } + + /// The holder of UpgradePlanCapability for account_address can submit UpgradePlan for account_address. + struct UpgradePlanCapability has key, store { + account_address: address, + } + + const STRATEGY_ARBITRARY: u8 = 0; + const STRATEGY_TWO_PHASE: u8 = 1; + const STRATEGY_NEW_MODULE: u8 = 2; + const STRATEGY_FREEZE: u8 = 3; + const DEFAULT_MIN_TIME_LIMIT: u64 = 86400000;// one day + + /// arbitary stragegy + public fun get_strategy_arbitrary(): u8 { STRATEGY_ARBITRARY } + /// two phase stragegy + public fun get_strategy_two_phase(): u8 { STRATEGY_TWO_PHASE } + /// new module strategy + public fun get_strategy_new_module(): u8 { STRATEGY_NEW_MODULE } + /// freezed strategy + public fun get_strategy_freeze(): u8 { STRATEGY_FREEZE } + /// default min time limit + public fun get_default_min_time_limit(): u64 { DEFAULT_MIN_TIME_LIMIT } + + const EUPGRADE_PLAN_IS_NONE: u64 = 102; + const EPACKAGE_HASH_INCORRECT: u64 = 103; + const EACTIVE_TIME_INCORRECT: u64 = 104; + const ESTRATEGY_FREEZED: u64 = 105; + const ESTRATEGY_INCORRECT: u64 = 106; + const ESTRATEGY_NOT_TWO_PHASE: u64 = 107; + const EUNKNOWN_STRATEGY: u64 = 108; + const ESENDER_AND_PACKAGE_ADDRESS_MISMATCH: u64 = 109; + + struct UpgradePlanV2 has copy, drop, store { + package_hash: vector, + active_after_time: u64, + version: u64, + enforced: bool, + } + + /// module upgrade strategy + struct ModuleUpgradeStrategy has key, store { + /// 0 arbitrary + /// 1 two phase upgrade + /// 2 only new module + /// 3 freeze + strategy: u8, + } + + /// data of two phase upgrade strategy. + struct TwoPhaseUpgrade has key { + config: TwoPhaseUpgradeConfig, + plan: Option, + version_cap: Config::ModifyConfigCapability, + upgrade_event: Event::EventHandle, + } + + /// config of two phase upgrade strategy. + struct TwoPhaseUpgradeConfig has copy, drop, store { + min_time_limit: u64, + } + + /// data of two phase upgrade strategy. + struct TwoPhaseUpgradeV2 has key { + config: TwoPhaseUpgradeConfig, + plan: Option, + version_cap: Config::ModifyConfigCapability, + upgrade_event: Event::EventHandle, + } + + /// module upgrade event. + struct UpgradeEvent has drop, store { + package_address: address, + package_hash: vector, + version: u64, + } + + /// Update account's ModuleUpgradeStrategy + public fun update_module_upgrade_strategy(account: &signer, strategy: u8, min_time: Option) acquires ModuleUpgradeStrategy, TwoPhaseUpgrade, TwoPhaseUpgradeV2, UpgradePlanCapability{ + assert!(strategy == STRATEGY_ARBITRARY || strategy == STRATEGY_TWO_PHASE || strategy == STRATEGY_NEW_MODULE || strategy == STRATEGY_FREEZE, Errors::invalid_argument(EUNKNOWN_STRATEGY)); + let account_address = Signer::address_of(account); + let previous_strategy = get_module_upgrade_strategy(account_address); + assert!(strategy > previous_strategy, Errors::invalid_argument(ESTRATEGY_INCORRECT)); + if (exists(account_address)) { + borrow_global_mut(account_address).strategy = strategy; + }else{ + move_to(account, ModuleUpgradeStrategy{ strategy: strategy}); + }; + if (strategy == STRATEGY_TWO_PHASE){ + let version_cap = Config::extract_modify_config_capability(account); + let min_time_limit = Option::get_with_default(&min_time, DEFAULT_MIN_TIME_LIMIT); + move_to(account, UpgradePlanCapability{ account_address: account_address}); + move_to(account, TwoPhaseUpgradeV2{ + config: TwoPhaseUpgradeConfig{min_time_limit: min_time_limit}, + plan: Option::none(), + version_cap: version_cap, + upgrade_event: Event::new_event_handle(account)} + ); + }; + //clean two phase upgrade resource + if (previous_strategy == STRATEGY_TWO_PHASE){ + if (exists(account_address)) { + let tpu = move_from(account_address); + let TwoPhaseUpgrade{plan:_, version_cap, upgrade_event, config: _} = tpu; + Event::destroy_handle(upgrade_event); + Config::destroy_modify_config_capability(version_cap); + }; + if (exists(account_address)) { + let tpu = move_from(account_address); + let TwoPhaseUpgradeV2{plan:_, version_cap, upgrade_event, config: _} = tpu; + Event::destroy_handle(upgrade_event); + Config::destroy_modify_config_capability(version_cap); + }; + // UpgradePlanCapability may be extracted + if (exists(account_address)) { + let cap = move_from(account_address); + destroy_upgrade_plan_cap(cap); + }; + }; + } + + spec update_module_upgrade_strategy { + pragma verify = false; + aborts_if strategy != 0 && strategy != 1 && strategy != 2 && strategy != 3; + aborts_if exists(Signer::address_of(account)) && strategy <= global(Signer::address_of(account)).strategy; + aborts_if !exists(Signer::address_of(account)) && strategy == 0; + + aborts_if strategy == 1 && exists(Signer::address_of(account)); + aborts_if strategy == 1 && !exists>(Signer::address_of(account)); + let holder = global>(Signer::address_of(account)); + aborts_if strategy == 1 && Option::is_none>(holder.cap); + aborts_if strategy == 1 && exists(Signer::address_of(account)); + + aborts_if exists(Signer::address_of(account)) && global(Signer::address_of(account)).strategy == 1 + && !exists(Signer::address_of(account)); + } + + /// Get account address of UpgradePlanCapability + public fun account_address(cap: &UpgradePlanCapability): address { + cap.account_address + } + + /// destroy the given UpgradePlanCapability + public fun destroy_upgrade_plan_cap(cap: UpgradePlanCapability){ + let UpgradePlanCapability{account_address:_} = cap; + } + + spec destroy_upgrade_plan_cap { + aborts_if false; + } + + /// extract out UpgradePlanCapability from `signer`. + public fun extract_submit_upgrade_plan_cap(account: &signer): UpgradePlanCapability acquires ModuleUpgradeStrategy, UpgradePlanCapability{ + let account_address = Signer::address_of(account); + assert!(get_module_upgrade_strategy(account_address) == STRATEGY_TWO_PHASE, Errors::invalid_argument(ESTRATEGY_NOT_TWO_PHASE)); + move_from(account_address) + } + + spec extract_submit_upgrade_plan_cap { + aborts_if !exists(Signer::address_of(account)); + aborts_if global(Signer::address_of(account)).strategy != 1; + aborts_if !exists(Signer::address_of(account)); + } + + public entry fun convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2(account: signer, package_address: address) acquires TwoPhaseUpgrade { + let account_address = Signer::address_of(&account); + // sender should be package owner + assert!(account_address == package_address, Errors::requires_address(ESENDER_AND_PACKAGE_ADDRESS_MISMATCH)); + let tpu = move_from(account_address); + let TwoPhaseUpgrade{config, plan, version_cap, upgrade_event} = tpu; + if (Option::is_some(&plan)) { + let old_plan = Option::borrow(&plan); + move_to(&account, TwoPhaseUpgradeV2{ + config: config, + plan: Option::some(UpgradePlanV2 { + package_hash: *&old_plan.package_hash, + active_after_time: old_plan.active_after_time, + version: old_plan.version, + enforced: false }), + version_cap: version_cap, + upgrade_event: upgrade_event + }); + } else { + move_to(&account, TwoPhaseUpgradeV2{ + config: config, + plan: Option::none(), + version_cap: version_cap, + upgrade_event: upgrade_event + }); + }; + } + + spec convert_TwoPhaseUpgrade_to_TwoPhaseUpgradeV2 { + pragma verify = false; + } + + public fun submit_upgrade_plan_v2(account: &signer, package_hash: vector, version:u64, enforced: bool) acquires TwoPhaseUpgradeV2,UpgradePlanCapability,ModuleUpgradeStrategy{ + let account_address = Signer::address_of(account); + let cap = borrow_global(account_address); + submit_upgrade_plan_with_cap_v2(cap, package_hash, version, enforced); + } + + spec submit_upgrade_plan_v2 { + pragma verify = false; + aborts_if !exists(Signer::address_of(account)); + include SubmitUpgradePlanWithCapAbortsIf{account: global(Signer::address_of(account)).account_address}; + ensures Option::is_some(global(global(Signer::address_of(account)).account_address).plan); + } + public fun submit_upgrade_plan_with_cap_v2(cap: &UpgradePlanCapability, package_hash: vector, version: u64, enforced: bool) acquires TwoPhaseUpgradeV2,ModuleUpgradeStrategy{ + let package_address = cap.account_address; + assert!(get_module_upgrade_strategy(package_address) == STRATEGY_TWO_PHASE, Errors::invalid_argument(ESTRATEGY_NOT_TWO_PHASE)); + let tpu = borrow_global_mut(package_address); + let active_after_time = Timestamp::now_milliseconds() + tpu.config.min_time_limit; + tpu.plan = Option::some(UpgradePlanV2 { package_hash, active_after_time, version, enforced }); + } + spec submit_upgrade_plan_with_cap_v2 { + pragma verify = false; + include SubmitUpgradePlanWithCapAbortsIf{account: cap.account_address}; + ensures Option::is_some(global(cap.account_address).plan); + } + + spec schema SubmitUpgradePlanWithCapAbortsIf { + account: address; + aborts_if !exists(account); + aborts_if global(account).strategy != 1; + aborts_if !exists(account); + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if Timestamp::now_milliseconds() + global(account).config.min_time_limit > max_u64(); + } + + /// Cancel a module upgrade plan. + public fun cancel_upgrade_plan(account: &signer) acquires TwoPhaseUpgradeV2,UpgradePlanCapability,ModuleUpgradeStrategy{ + let account_address = Signer::address_of(account); + let cap = borrow_global(account_address); + cancel_upgrade_plan_with_cap(cap); + } + + spec cancel_upgrade_plan { + aborts_if !exists(Signer::address_of(account)); + include CancelUpgradePlanWithCapAbortsIf{account: global(Signer::address_of(account)).account_address}; + ensures Option::is_none(global(global(Signer::address_of(account)).account_address).plan); + } + + /// Cancel a module upgrade plan with given cap. + public fun cancel_upgrade_plan_with_cap(cap: &UpgradePlanCapability) acquires TwoPhaseUpgradeV2,ModuleUpgradeStrategy{ + let package_address = cap.account_address; + assert!(get_module_upgrade_strategy(package_address) == STRATEGY_TWO_PHASE, Errors::invalid_argument(ESTRATEGY_NOT_TWO_PHASE)); + let tpu = borrow_global_mut(package_address); + assert!(Option::is_some(&tpu.plan), Errors::invalid_state(EUPGRADE_PLAN_IS_NONE)); + tpu.plan = Option::none(); + } + + spec cancel_upgrade_plan_with_cap { + include CancelUpgradePlanWithCapAbortsIf{account: cap.account_address}; + ensures Option::is_none(global(cap.account_address).plan); + } + + spec schema CancelUpgradePlanWithCapAbortsIf { + account: address; + aborts_if !exists(account); + aborts_if global(account).strategy != 1; + aborts_if !exists(account); + aborts_if !Option::is_some(global(account).plan); + } + + /// Get module upgrade strategy of an module address. + public fun get_module_upgrade_strategy(module_address: address): u8 acquires ModuleUpgradeStrategy { + if (exists(module_address)) { + borrow_global(module_address).strategy + }else{ + 0 + } + } + + spec get_module_upgrade_strategy { + aborts_if false; + } + + spec fun spec_get_module_upgrade_strategy(module_address: address): u8 { + if (exists(module_address)) { + global(module_address).strategy + }else{ + 0 + } + } + + /// Get module upgrade plan of an address. + public fun get_upgrade_plan(_module_address: address): Option { + // DEPRECATED_CODE + Option::none() + } + + spec get_upgrade_plan { + aborts_if false; + } + + /// Get module upgrade plan of an address. + public fun get_upgrade_plan_v2(module_address: address): Option acquires TwoPhaseUpgradeV2 { + if (exists(module_address)) { + *&borrow_global(module_address).plan + } else { + Option::none() + } + } + + spec get_upgrade_plan_v2 { + pragma verify = false; + aborts_if false; + } + spec fun spec_get_upgrade_plan_v2(module_address: address): Option { + if (exists(module_address)) { + global(module_address).plan + }else{ + Option::spec_none() + } + } + + /// Check againest on the given package data. + public fun check_package_txn(package_address: address, package_hash: vector) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy{ + let strategy = get_module_upgrade_strategy(package_address); + if (strategy == STRATEGY_ARBITRARY){ + //do nothing + }else if(strategy == STRATEGY_TWO_PHASE){ + let plan_opt = get_upgrade_plan_v2(package_address); + assert!(Option::is_some(&plan_opt), Errors::invalid_argument(EUPGRADE_PLAN_IS_NONE)); + let plan = Option::borrow(&plan_opt); + assert!(*&plan.package_hash == package_hash, Errors::invalid_argument(EPACKAGE_HASH_INCORRECT)); + assert!(plan.active_after_time <= Timestamp::now_milliseconds(), Errors::invalid_argument(EACTIVE_TIME_INCORRECT)); + }else if(strategy == STRATEGY_NEW_MODULE){ + //do check at VM runtime. + }else if(strategy == STRATEGY_FREEZE){ + Errors::invalid_argument(ESTRATEGY_FREEZED); + }; + } + + spec check_package_txn { + pragma verify = false; + include CheckPackageTxnAbortsIf; + } + + public fun check_package_txn_v2(txn_sender: address, package_address: address, package_hash: vector) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy{ + let strategy = get_module_upgrade_strategy(package_address); + if (strategy == STRATEGY_ARBITRARY){ + assert!(txn_sender == package_address, Errors::requires_address(ESENDER_AND_PACKAGE_ADDRESS_MISMATCH)); + }else if(strategy == STRATEGY_TWO_PHASE){ + let plan_opt = get_upgrade_plan_v2(package_address); + assert!(Option::is_some(&plan_opt), Errors::invalid_argument(EUPGRADE_PLAN_IS_NONE)); + let plan = Option::borrow(&plan_opt); + assert!(*&plan.package_hash == package_hash, Errors::invalid_argument(EPACKAGE_HASH_INCORRECT)); + assert!(plan.active_after_time <= Timestamp::now_milliseconds(), Errors::invalid_argument(EACTIVE_TIME_INCORRECT)); + }else if(strategy == STRATEGY_NEW_MODULE){ + //do check at VM runtime. + assert!(txn_sender == package_address, Errors::requires_address(ESENDER_AND_PACKAGE_ADDRESS_MISMATCH)); + }else if(strategy == STRATEGY_FREEZE){ + Errors::invalid_argument(ESTRATEGY_FREEZED); + }; + } + + spec schema CheckPackageTxnAbortsIf { + package_address: address; + package_hash: vector; + aborts_if spec_get_module_upgrade_strategy(package_address) == 3; + aborts_if spec_get_module_upgrade_strategy(package_address) == 1 && Option::is_none(spec_get_upgrade_plan_v2(package_address)); + aborts_if spec_get_module_upgrade_strategy(package_address) == 1 && Option::borrow(spec_get_upgrade_plan_v2(package_address)).package_hash != package_hash; + aborts_if spec_get_module_upgrade_strategy(package_address) == 1 && !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if spec_get_module_upgrade_strategy(package_address) == 1 && Option::borrow(spec_get_upgrade_plan_v2(package_address)).active_after_time > Timestamp::now_milliseconds(); + } + + spec schema CheckPackageTxnAbortsIfWithType { + is_package: bool; + sender: address; + package_address: address; + package_hash: vector; + aborts_if is_package && spec_get_module_upgrade_strategy(package_address) == 3; + aborts_if is_package && spec_get_module_upgrade_strategy(package_address) == 1 && Option::is_none(spec_get_upgrade_plan_v2(package_address)); + aborts_if is_package && spec_get_module_upgrade_strategy(package_address) == 1 && Option::borrow(spec_get_upgrade_plan_v2(package_address)).package_hash != package_hash; + aborts_if is_package && spec_get_module_upgrade_strategy(package_address) == 1 && !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if is_package && spec_get_module_upgrade_strategy(package_address) == 1 && Option::borrow(spec_get_upgrade_plan_v2(package_address)).active_after_time > Timestamp::now_milliseconds(); + } + + fun finish_upgrade_plan(package_address: address) acquires TwoPhaseUpgradeV2 { + let tpu = borrow_global_mut(package_address); + if (Option::is_some(&tpu.plan)) { + let plan = Option::borrow(&tpu.plan); + Config::set_with_capability(&mut tpu.version_cap, Version::new_version(plan.version)); + Event::emit_event(&mut tpu.upgrade_event, UpgradeEvent { + package_address: package_address, + package_hash: *&plan.package_hash, + version: plan.version}); + }; + tpu.plan = Option::none(); + } + + spec finish_upgrade_plan { + pragma verify = false; + aborts_if !exists(package_address); + let tpu = global(package_address); + aborts_if Option::is_some(tpu.plan) && !exists>(tpu.version_cap.account_address); + } + + /// Prologue of package transaction. + public fun package_txn_prologue(account: &signer, package_address: address, package_hash: vector) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy { + // Can only be invoked by genesis account + CoreAddresses::assert_genesis_address(account); + check_package_txn(package_address, package_hash); + } + + spec package_txn_prologue { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + include CheckPackageTxnAbortsIf{}; + } + + public fun package_txn_prologue_v2(account: &signer, txn_sender: address, package_address: address, package_hash: vector) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy { + // Can only be invoked by genesis account + CoreAddresses::assert_genesis_address(account); + check_package_txn_v2(txn_sender, package_address, package_hash); + } + + /// Package txn finished, and clean UpgradePlan + public fun package_txn_epilogue(account: &signer, _txn_sender: address, package_address: address, success: bool) acquires TwoPhaseUpgradeV2, ModuleUpgradeStrategy { + // Can only be invoked by genesis account + CoreAddresses::assert_genesis_address(account); + let strategy = get_module_upgrade_strategy(package_address); + if(strategy == STRATEGY_TWO_PHASE){ + if (success) { + finish_upgrade_plan(package_address); + }; + }; + } + + spec schema AbortsIfPackageTxnEpilogue { + is_package: bool; + package_address: address; + success: bool; + aborts_if is_package && get_module_upgrade_strategy(package_address) == STRATEGY_TWO_PHASE && success && !exists(package_address); + } + + spec package_txn_epilogue { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if spec_get_module_upgrade_strategy(package_address) == 1 + && success && !exists(package_address); + aborts_if spec_get_module_upgrade_strategy(package_address) == 1 + && success && Option::is_some(global(package_address).plan) + && !exists>(global(package_address).version_cap.account_address); + } + + } +} \ No newline at end of file diff --git a/release/v13/sources/PriceOracle.move b/release/v13/sources/PriceOracle.move new file mode 100644 index 00000000..9241b263 --- /dev/null +++ b/release/v13/sources/PriceOracle.move @@ -0,0 +1,325 @@ +address StarcoinFramework { +module Oracle { + use StarcoinFramework::Event; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::Vector; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Account; + use StarcoinFramework::GenesisSignerCapability; + + struct OracleInfo has key { + ///The datasource counter + counter: u64, + ///Ext info + info: Info, + } + + struct DataRecord has copy, store, drop { + ///The data version + version: u64, + ///The record value + value: ValueT, + ///Update timestamp millisecond + updated_at: u64, + } + + struct OracleFeed has key { + record: DataRecord, + } + + struct OracleUpdateEvent has copy,store,drop { + source_id: u64, + record: DataRecord, + } + + struct DataSource has key { + /// the id of data source of ValueT + id: u64, + /// the data version counter. + counter: u64, + update_events: Event::EventHandle>, + } + + struct UpdateCapability has store, key { + account: address, + } + + struct GenesisSignerCapability has key{ + cap: Account::SignerCapability, + } + + /// The oracle type not register. + const ERR_ORACLE_TYPE_NOT_REGISTER:u64 = 101; + /// No capability to update the oracle value. + const ERR_NO_UPDATE_CAPABILITY: u64 = 102; + const ERR_NO_DATA_SOURCE: u64 = 103; + const ERR_CAPABILITY_ACCOUNT_MISS_MATCH: u64 = 104; + + /// deprecated. + public fun initialize(_sender: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability{ + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register `OracleT` as an oracle type. + public fun register_oracle(_sender: &signer, info: Info) { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + move_to(&genesis_account, OracleInfo { + counter: 0, + info, + }); + } + + /// Get the `OracleT` oracle's counter, the counter represent how many `OracleT` datasources + public fun get_oracle_counter() : u64 acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + oracle_info.counter + } + + public fun get_oracle_info() : Info acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&oracle_info.info + } + + /// Init a data source for type `OracleT` + public fun init_data_source(sender: &signer, init_value: ValueT) acquires OracleInfo{ + assert!(exists>(CoreAddresses::GENESIS_ADDRESS()), Errors::not_published(ERR_ORACLE_TYPE_NOT_REGISTER)); + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + let now = Timestamp::now_milliseconds(); + move_to(sender, OracleFeed { + record: DataRecord { + version: 0, + value: init_value, + updated_at: now, + } + }); + let sender_addr = Signer::address_of(sender); + move_to(sender, DataSource { + id: oracle_info.counter, + counter: 1, + update_events: Event::new_event_handle>(sender), + }); + move_to(sender, UpdateCapability{account: sender_addr}); + oracle_info.counter = oracle_info.counter + 1; + } + + /// Check the DataSource is initiailzed at ds_addr + public fun is_data_source_initialized(ds_addr: address): bool { + exists>(ds_addr) + } + + /// Update Oracle's record with new value, the `sender` must have UpdateCapability + public fun update(sender: &signer, value: ValueT) acquires UpdateCapability, DataSource, OracleFeed{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(account); + update_with_cap(cap,value); + } + + /// Update Oracle's record with new value and UpdateCapability + public fun update_with_cap(cap: &mut UpdateCapability, value: ValueT) acquires DataSource,OracleFeed { + let account = cap.account; + assert!(exists>(account), Errors::requires_capability(ERR_NO_DATA_SOURCE)); + let source = borrow_global_mut>(account); + let now = Timestamp::now_milliseconds(); + let oracle_feed = borrow_global_mut>(account); + oracle_feed.record.version = source.counter; + oracle_feed.record.value = value; + oracle_feed.record.updated_at = now; + source.counter = source.counter + 1; + Event::emit_event(&mut source.update_events,OracleUpdateEvent{ + source_id: source.id, + record: *&oracle_feed.record + }); + } + + /// Read the Oracle's value from `ds_addr` + public fun read(ds_addr: address): ValueT acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record.value + } + + /// Read the Oracle's DataRecord from `ds_addr` + public fun read_record(ds_addr: address): DataRecord acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record + } + + /// Batch read Oracle's DataRecord from `ds_addrs` + public fun read_records(ds_addrs: &vector
): vector> acquires OracleFeed{ + let len = Vector::length(ds_addrs); + let results = Vector::empty(); + let i = 0; + while (i < len){ + let addr = *Vector::borrow(ds_addrs, i); + let record = Self::read_record(addr); + Vector::push_back(&mut results, record); + i = i + 1; + }; + results + } + + /// Remove UpdateCapability from current sender. + public fun remove_update_capability(sender: &signer):UpdateCapability acquires UpdateCapability{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(account) + } + + /// Add UpdateCapability to current sender + public fun add_update_capability(sender: &signer, update_cap: UpdateCapability){ + assert!(Signer::address_of(sender) == update_cap.account, Errors::invalid_argument(ERR_CAPABILITY_ACCOUNT_MISS_MATCH)); + move_to(sender, update_cap); + } + + /// Unpack Record to fields: version, oracle, updated_at. + public fun unpack_record(record: DataRecord):(u64, ValueT, u64) { + (record.version,*&record.value,record.updated_at) + } +} +module PriceOracle{ + use StarcoinFramework::Math; + use StarcoinFramework::Oracle::{Self, DataRecord, UpdateCapability}; + + struct PriceOracleInfo has copy,store,drop{ + scaling_factor: u128, + } + + public entry fun register_oracle_entry(sender: signer, precision: u8){ + register_oracle(&sender, precision); + } + + public fun register_oracle(sender: &signer, precision: u8){ + let scaling_factor = Math::pow(10, (precision as u64)); + Oracle::register_oracle(sender, PriceOracleInfo{ + scaling_factor, + }); + } + + + public entry fun init_data_source_entry(sender: signer, init_value: u128){ + init_data_source(&sender, init_value); + } + + public fun init_data_source(sender: &signer, init_value: u128){ + Oracle::init_data_source(sender, init_value); + } + + public fun is_data_source_initialized(ds_addr: address): bool{ + Oracle::is_data_source_initialized(ds_addr) + } + + public fun get_scaling_factor() : u128 { + let info = Oracle::get_oracle_info(); + info.scaling_factor + } + + public entry fun update_entry(sender: signer, value: u128){ + update(&sender, value); + } + + public fun update(sender: &signer, value: u128){ + Oracle::update(sender, value); + } + + public fun update_with_cap(cap: &mut UpdateCapability, value: u128) { + Oracle::update_with_cap(cap, value); + } + + public fun read(addr: address) : u128{ + Oracle::read(addr) + } + + public fun read_record(addr: address): DataRecord{ + Oracle::read_record(addr) + } + + public fun read_records(addrs: &vector
): vector>{ + Oracle::read_records(addrs) + } + +} + +module STCUSDOracle{ + use StarcoinFramework::Oracle::{DataRecord}; + use StarcoinFramework::PriceOracle::{Self}; + + /// The STC to USD price oracle + struct STCUSD has copy,store,drop {} + + public fun register(sender: &signer){ + PriceOracle::register_oracle(sender, 6); + } + + public fun read(ds_addr: address) : u128{ + PriceOracle::read(ds_addr) + } + + public fun read_record(ds_addr: address): DataRecord{ + PriceOracle::read_record(ds_addr) + } + + public fun read_records(ds_addrs: &vector
): vector>{ + PriceOracle::read_records(ds_addrs) + } +} + +module PriceOracleScripts{ + use StarcoinFramework::PriceOracle; + + public entry fun register_oracle(sender: signer, precision: u8){ + PriceOracle::register_oracle_entry(sender, precision); + } + + public entry fun init_data_source(sender: signer, init_value: u128){ + PriceOracle::init_data_source_entry(sender, init_value); + } + + public entry fun update(sender: signer, value: u128){ + PriceOracle::update_entry(sender, value); + } +} + +module PriceOracleAggregator{ + use StarcoinFramework::Vector; + use StarcoinFramework::Oracle; + use StarcoinFramework::PriceOracle; + use StarcoinFramework::Math; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Errors; + + /// No price data match requirement condition. + const ERR_NO_PRICE_DATA_AVIABLE:u64 = 101; + + /// Get latest price from datasources and calculate avg. + /// `addrs`: the datasource's addr, `updated_in`: the datasource should updated in x millseoconds. + public fun latest_price_average_aggregator(addrs: &vector
, updated_in: u64): u128 { + let len = Vector::length(addrs); + let price_records = PriceOracle::read_records(addrs); + let prices = Vector::empty(); + let i = 0; + let expect_updated_after = Timestamp::now_milliseconds() - updated_in; + while (i < len){ + let record = Vector::pop_back(&mut price_records); + let (_version, price, updated_at) = Oracle::unpack_record(record); + if (updated_at >= expect_updated_after) { + Vector::push_back(&mut prices, price); + }; + i = i + 1; + }; + // if all price data not match the update_in filter, abort. + assert!(!Vector::is_empty(&prices), Errors::invalid_state(ERR_NO_PRICE_DATA_AVIABLE)); + Math::avg(&prices) + } +} + + +} \ No newline at end of file diff --git a/release/v13/sources/PriceOracleAggregator.move b/release/v13/sources/PriceOracleAggregator.move new file mode 100644 index 00000000..9241b263 --- /dev/null +++ b/release/v13/sources/PriceOracleAggregator.move @@ -0,0 +1,325 @@ +address StarcoinFramework { +module Oracle { + use StarcoinFramework::Event; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::Vector; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Account; + use StarcoinFramework::GenesisSignerCapability; + + struct OracleInfo has key { + ///The datasource counter + counter: u64, + ///Ext info + info: Info, + } + + struct DataRecord has copy, store, drop { + ///The data version + version: u64, + ///The record value + value: ValueT, + ///Update timestamp millisecond + updated_at: u64, + } + + struct OracleFeed has key { + record: DataRecord, + } + + struct OracleUpdateEvent has copy,store,drop { + source_id: u64, + record: DataRecord, + } + + struct DataSource has key { + /// the id of data source of ValueT + id: u64, + /// the data version counter. + counter: u64, + update_events: Event::EventHandle>, + } + + struct UpdateCapability has store, key { + account: address, + } + + struct GenesisSignerCapability has key{ + cap: Account::SignerCapability, + } + + /// The oracle type not register. + const ERR_ORACLE_TYPE_NOT_REGISTER:u64 = 101; + /// No capability to update the oracle value. + const ERR_NO_UPDATE_CAPABILITY: u64 = 102; + const ERR_NO_DATA_SOURCE: u64 = 103; + const ERR_CAPABILITY_ACCOUNT_MISS_MATCH: u64 = 104; + + /// deprecated. + public fun initialize(_sender: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability{ + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register `OracleT` as an oracle type. + public fun register_oracle(_sender: &signer, info: Info) { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + move_to(&genesis_account, OracleInfo { + counter: 0, + info, + }); + } + + /// Get the `OracleT` oracle's counter, the counter represent how many `OracleT` datasources + public fun get_oracle_counter() : u64 acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + oracle_info.counter + } + + public fun get_oracle_info() : Info acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&oracle_info.info + } + + /// Init a data source for type `OracleT` + public fun init_data_source(sender: &signer, init_value: ValueT) acquires OracleInfo{ + assert!(exists>(CoreAddresses::GENESIS_ADDRESS()), Errors::not_published(ERR_ORACLE_TYPE_NOT_REGISTER)); + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + let now = Timestamp::now_milliseconds(); + move_to(sender, OracleFeed { + record: DataRecord { + version: 0, + value: init_value, + updated_at: now, + } + }); + let sender_addr = Signer::address_of(sender); + move_to(sender, DataSource { + id: oracle_info.counter, + counter: 1, + update_events: Event::new_event_handle>(sender), + }); + move_to(sender, UpdateCapability{account: sender_addr}); + oracle_info.counter = oracle_info.counter + 1; + } + + /// Check the DataSource is initiailzed at ds_addr + public fun is_data_source_initialized(ds_addr: address): bool { + exists>(ds_addr) + } + + /// Update Oracle's record with new value, the `sender` must have UpdateCapability + public fun update(sender: &signer, value: ValueT) acquires UpdateCapability, DataSource, OracleFeed{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(account); + update_with_cap(cap,value); + } + + /// Update Oracle's record with new value and UpdateCapability + public fun update_with_cap(cap: &mut UpdateCapability, value: ValueT) acquires DataSource,OracleFeed { + let account = cap.account; + assert!(exists>(account), Errors::requires_capability(ERR_NO_DATA_SOURCE)); + let source = borrow_global_mut>(account); + let now = Timestamp::now_milliseconds(); + let oracle_feed = borrow_global_mut>(account); + oracle_feed.record.version = source.counter; + oracle_feed.record.value = value; + oracle_feed.record.updated_at = now; + source.counter = source.counter + 1; + Event::emit_event(&mut source.update_events,OracleUpdateEvent{ + source_id: source.id, + record: *&oracle_feed.record + }); + } + + /// Read the Oracle's value from `ds_addr` + public fun read(ds_addr: address): ValueT acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record.value + } + + /// Read the Oracle's DataRecord from `ds_addr` + public fun read_record(ds_addr: address): DataRecord acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record + } + + /// Batch read Oracle's DataRecord from `ds_addrs` + public fun read_records(ds_addrs: &vector
): vector> acquires OracleFeed{ + let len = Vector::length(ds_addrs); + let results = Vector::empty(); + let i = 0; + while (i < len){ + let addr = *Vector::borrow(ds_addrs, i); + let record = Self::read_record(addr); + Vector::push_back(&mut results, record); + i = i + 1; + }; + results + } + + /// Remove UpdateCapability from current sender. + public fun remove_update_capability(sender: &signer):UpdateCapability acquires UpdateCapability{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(account) + } + + /// Add UpdateCapability to current sender + public fun add_update_capability(sender: &signer, update_cap: UpdateCapability){ + assert!(Signer::address_of(sender) == update_cap.account, Errors::invalid_argument(ERR_CAPABILITY_ACCOUNT_MISS_MATCH)); + move_to(sender, update_cap); + } + + /// Unpack Record to fields: version, oracle, updated_at. + public fun unpack_record(record: DataRecord):(u64, ValueT, u64) { + (record.version,*&record.value,record.updated_at) + } +} +module PriceOracle{ + use StarcoinFramework::Math; + use StarcoinFramework::Oracle::{Self, DataRecord, UpdateCapability}; + + struct PriceOracleInfo has copy,store,drop{ + scaling_factor: u128, + } + + public entry fun register_oracle_entry(sender: signer, precision: u8){ + register_oracle(&sender, precision); + } + + public fun register_oracle(sender: &signer, precision: u8){ + let scaling_factor = Math::pow(10, (precision as u64)); + Oracle::register_oracle(sender, PriceOracleInfo{ + scaling_factor, + }); + } + + + public entry fun init_data_source_entry(sender: signer, init_value: u128){ + init_data_source(&sender, init_value); + } + + public fun init_data_source(sender: &signer, init_value: u128){ + Oracle::init_data_source(sender, init_value); + } + + public fun is_data_source_initialized(ds_addr: address): bool{ + Oracle::is_data_source_initialized(ds_addr) + } + + public fun get_scaling_factor() : u128 { + let info = Oracle::get_oracle_info(); + info.scaling_factor + } + + public entry fun update_entry(sender: signer, value: u128){ + update(&sender, value); + } + + public fun update(sender: &signer, value: u128){ + Oracle::update(sender, value); + } + + public fun update_with_cap(cap: &mut UpdateCapability, value: u128) { + Oracle::update_with_cap(cap, value); + } + + public fun read(addr: address) : u128{ + Oracle::read(addr) + } + + public fun read_record(addr: address): DataRecord{ + Oracle::read_record(addr) + } + + public fun read_records(addrs: &vector
): vector>{ + Oracle::read_records(addrs) + } + +} + +module STCUSDOracle{ + use StarcoinFramework::Oracle::{DataRecord}; + use StarcoinFramework::PriceOracle::{Self}; + + /// The STC to USD price oracle + struct STCUSD has copy,store,drop {} + + public fun register(sender: &signer){ + PriceOracle::register_oracle(sender, 6); + } + + public fun read(ds_addr: address) : u128{ + PriceOracle::read(ds_addr) + } + + public fun read_record(ds_addr: address): DataRecord{ + PriceOracle::read_record(ds_addr) + } + + public fun read_records(ds_addrs: &vector
): vector>{ + PriceOracle::read_records(ds_addrs) + } +} + +module PriceOracleScripts{ + use StarcoinFramework::PriceOracle; + + public entry fun register_oracle(sender: signer, precision: u8){ + PriceOracle::register_oracle_entry(sender, precision); + } + + public entry fun init_data_source(sender: signer, init_value: u128){ + PriceOracle::init_data_source_entry(sender, init_value); + } + + public entry fun update(sender: signer, value: u128){ + PriceOracle::update_entry(sender, value); + } +} + +module PriceOracleAggregator{ + use StarcoinFramework::Vector; + use StarcoinFramework::Oracle; + use StarcoinFramework::PriceOracle; + use StarcoinFramework::Math; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Errors; + + /// No price data match requirement condition. + const ERR_NO_PRICE_DATA_AVIABLE:u64 = 101; + + /// Get latest price from datasources and calculate avg. + /// `addrs`: the datasource's addr, `updated_in`: the datasource should updated in x millseoconds. + public fun latest_price_average_aggregator(addrs: &vector
, updated_in: u64): u128 { + let len = Vector::length(addrs); + let price_records = PriceOracle::read_records(addrs); + let prices = Vector::empty(); + let i = 0; + let expect_updated_after = Timestamp::now_milliseconds() - updated_in; + while (i < len){ + let record = Vector::pop_back(&mut price_records); + let (_version, price, updated_at) = Oracle::unpack_record(record); + if (updated_at >= expect_updated_after) { + Vector::push_back(&mut prices, price); + }; + i = i + 1; + }; + // if all price data not match the update_in filter, abort. + assert!(!Vector::is_empty(&prices), Errors::invalid_state(ERR_NO_PRICE_DATA_AVIABLE)); + Math::avg(&prices) + } +} + + +} \ No newline at end of file diff --git a/release/v13/sources/PriceOracleScripts.move b/release/v13/sources/PriceOracleScripts.move new file mode 100644 index 00000000..9241b263 --- /dev/null +++ b/release/v13/sources/PriceOracleScripts.move @@ -0,0 +1,325 @@ +address StarcoinFramework { +module Oracle { + use StarcoinFramework::Event; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::Vector; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Account; + use StarcoinFramework::GenesisSignerCapability; + + struct OracleInfo has key { + ///The datasource counter + counter: u64, + ///Ext info + info: Info, + } + + struct DataRecord has copy, store, drop { + ///The data version + version: u64, + ///The record value + value: ValueT, + ///Update timestamp millisecond + updated_at: u64, + } + + struct OracleFeed has key { + record: DataRecord, + } + + struct OracleUpdateEvent has copy,store,drop { + source_id: u64, + record: DataRecord, + } + + struct DataSource has key { + /// the id of data source of ValueT + id: u64, + /// the data version counter. + counter: u64, + update_events: Event::EventHandle>, + } + + struct UpdateCapability has store, key { + account: address, + } + + struct GenesisSignerCapability has key{ + cap: Account::SignerCapability, + } + + /// The oracle type not register. + const ERR_ORACLE_TYPE_NOT_REGISTER:u64 = 101; + /// No capability to update the oracle value. + const ERR_NO_UPDATE_CAPABILITY: u64 = 102; + const ERR_NO_DATA_SOURCE: u64 = 103; + const ERR_CAPABILITY_ACCOUNT_MISS_MATCH: u64 = 104; + + /// deprecated. + public fun initialize(_sender: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability{ + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register `OracleT` as an oracle type. + public fun register_oracle(_sender: &signer, info: Info) { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + move_to(&genesis_account, OracleInfo { + counter: 0, + info, + }); + } + + /// Get the `OracleT` oracle's counter, the counter represent how many `OracleT` datasources + public fun get_oracle_counter() : u64 acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + oracle_info.counter + } + + public fun get_oracle_info() : Info acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&oracle_info.info + } + + /// Init a data source for type `OracleT` + public fun init_data_source(sender: &signer, init_value: ValueT) acquires OracleInfo{ + assert!(exists>(CoreAddresses::GENESIS_ADDRESS()), Errors::not_published(ERR_ORACLE_TYPE_NOT_REGISTER)); + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + let now = Timestamp::now_milliseconds(); + move_to(sender, OracleFeed { + record: DataRecord { + version: 0, + value: init_value, + updated_at: now, + } + }); + let sender_addr = Signer::address_of(sender); + move_to(sender, DataSource { + id: oracle_info.counter, + counter: 1, + update_events: Event::new_event_handle>(sender), + }); + move_to(sender, UpdateCapability{account: sender_addr}); + oracle_info.counter = oracle_info.counter + 1; + } + + /// Check the DataSource is initiailzed at ds_addr + public fun is_data_source_initialized(ds_addr: address): bool { + exists>(ds_addr) + } + + /// Update Oracle's record with new value, the `sender` must have UpdateCapability + public fun update(sender: &signer, value: ValueT) acquires UpdateCapability, DataSource, OracleFeed{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(account); + update_with_cap(cap,value); + } + + /// Update Oracle's record with new value and UpdateCapability + public fun update_with_cap(cap: &mut UpdateCapability, value: ValueT) acquires DataSource,OracleFeed { + let account = cap.account; + assert!(exists>(account), Errors::requires_capability(ERR_NO_DATA_SOURCE)); + let source = borrow_global_mut>(account); + let now = Timestamp::now_milliseconds(); + let oracle_feed = borrow_global_mut>(account); + oracle_feed.record.version = source.counter; + oracle_feed.record.value = value; + oracle_feed.record.updated_at = now; + source.counter = source.counter + 1; + Event::emit_event(&mut source.update_events,OracleUpdateEvent{ + source_id: source.id, + record: *&oracle_feed.record + }); + } + + /// Read the Oracle's value from `ds_addr` + public fun read(ds_addr: address): ValueT acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record.value + } + + /// Read the Oracle's DataRecord from `ds_addr` + public fun read_record(ds_addr: address): DataRecord acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record + } + + /// Batch read Oracle's DataRecord from `ds_addrs` + public fun read_records(ds_addrs: &vector
): vector> acquires OracleFeed{ + let len = Vector::length(ds_addrs); + let results = Vector::empty(); + let i = 0; + while (i < len){ + let addr = *Vector::borrow(ds_addrs, i); + let record = Self::read_record(addr); + Vector::push_back(&mut results, record); + i = i + 1; + }; + results + } + + /// Remove UpdateCapability from current sender. + public fun remove_update_capability(sender: &signer):UpdateCapability acquires UpdateCapability{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(account) + } + + /// Add UpdateCapability to current sender + public fun add_update_capability(sender: &signer, update_cap: UpdateCapability){ + assert!(Signer::address_of(sender) == update_cap.account, Errors::invalid_argument(ERR_CAPABILITY_ACCOUNT_MISS_MATCH)); + move_to(sender, update_cap); + } + + /// Unpack Record to fields: version, oracle, updated_at. + public fun unpack_record(record: DataRecord):(u64, ValueT, u64) { + (record.version,*&record.value,record.updated_at) + } +} +module PriceOracle{ + use StarcoinFramework::Math; + use StarcoinFramework::Oracle::{Self, DataRecord, UpdateCapability}; + + struct PriceOracleInfo has copy,store,drop{ + scaling_factor: u128, + } + + public entry fun register_oracle_entry(sender: signer, precision: u8){ + register_oracle(&sender, precision); + } + + public fun register_oracle(sender: &signer, precision: u8){ + let scaling_factor = Math::pow(10, (precision as u64)); + Oracle::register_oracle(sender, PriceOracleInfo{ + scaling_factor, + }); + } + + + public entry fun init_data_source_entry(sender: signer, init_value: u128){ + init_data_source(&sender, init_value); + } + + public fun init_data_source(sender: &signer, init_value: u128){ + Oracle::init_data_source(sender, init_value); + } + + public fun is_data_source_initialized(ds_addr: address): bool{ + Oracle::is_data_source_initialized(ds_addr) + } + + public fun get_scaling_factor() : u128 { + let info = Oracle::get_oracle_info(); + info.scaling_factor + } + + public entry fun update_entry(sender: signer, value: u128){ + update(&sender, value); + } + + public fun update(sender: &signer, value: u128){ + Oracle::update(sender, value); + } + + public fun update_with_cap(cap: &mut UpdateCapability, value: u128) { + Oracle::update_with_cap(cap, value); + } + + public fun read(addr: address) : u128{ + Oracle::read(addr) + } + + public fun read_record(addr: address): DataRecord{ + Oracle::read_record(addr) + } + + public fun read_records(addrs: &vector
): vector>{ + Oracle::read_records(addrs) + } + +} + +module STCUSDOracle{ + use StarcoinFramework::Oracle::{DataRecord}; + use StarcoinFramework::PriceOracle::{Self}; + + /// The STC to USD price oracle + struct STCUSD has copy,store,drop {} + + public fun register(sender: &signer){ + PriceOracle::register_oracle(sender, 6); + } + + public fun read(ds_addr: address) : u128{ + PriceOracle::read(ds_addr) + } + + public fun read_record(ds_addr: address): DataRecord{ + PriceOracle::read_record(ds_addr) + } + + public fun read_records(ds_addrs: &vector
): vector>{ + PriceOracle::read_records(ds_addrs) + } +} + +module PriceOracleScripts{ + use StarcoinFramework::PriceOracle; + + public entry fun register_oracle(sender: signer, precision: u8){ + PriceOracle::register_oracle_entry(sender, precision); + } + + public entry fun init_data_source(sender: signer, init_value: u128){ + PriceOracle::init_data_source_entry(sender, init_value); + } + + public entry fun update(sender: signer, value: u128){ + PriceOracle::update_entry(sender, value); + } +} + +module PriceOracleAggregator{ + use StarcoinFramework::Vector; + use StarcoinFramework::Oracle; + use StarcoinFramework::PriceOracle; + use StarcoinFramework::Math; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Errors; + + /// No price data match requirement condition. + const ERR_NO_PRICE_DATA_AVIABLE:u64 = 101; + + /// Get latest price from datasources and calculate avg. + /// `addrs`: the datasource's addr, `updated_in`: the datasource should updated in x millseoconds. + public fun latest_price_average_aggregator(addrs: &vector
, updated_in: u64): u128 { + let len = Vector::length(addrs); + let price_records = PriceOracle::read_records(addrs); + let prices = Vector::empty(); + let i = 0; + let expect_updated_after = Timestamp::now_milliseconds() - updated_in; + while (i < len){ + let record = Vector::pop_back(&mut price_records); + let (_version, price, updated_at) = Oracle::unpack_record(record); + if (updated_at >= expect_updated_after) { + Vector::push_back(&mut prices, price); + }; + i = i + 1; + }; + // if all price data not match the update_in filter, abort. + assert!(!Vector::is_empty(&prices), Errors::invalid_state(ERR_NO_PRICE_DATA_AVIABLE)); + Math::avg(&prices) + } +} + + +} \ No newline at end of file diff --git a/release/v13/sources/RewardConfig.move b/release/v13/sources/RewardConfig.move new file mode 100644 index 00000000..07179d9c --- /dev/null +++ b/release/v13/sources/RewardConfig.move @@ -0,0 +1,71 @@ +address StarcoinFramework { +/// The module provide configuration for block reward. +module RewardConfig { + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Config; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + + /// Reward configuration + struct RewardConfig has copy, drop, store { + /// how many blocks delay reward distribution. + reward_delay: u64, + } + + const EINVALID_ARGUMENT: u64 = 18; + + /// Module initialization. + public fun initialize(account: &signer, reward_delay: u64) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + + Config::publish_new_config( + account, + new_reward_config(reward_delay) + ); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists>(Signer::address_of(account)); + include Config::PublishNewConfigAbortsIf; + include Config::PublishNewConfigEnsures; + } + + /// Create a new reward config mainly used in DAO. + public fun new_reward_config(reward_delay: u64) : RewardConfig { + RewardConfig {reward_delay: reward_delay} + } + + spec new_reward_config {} + + /// Get reward configuration. + public fun get_reward_config(): RewardConfig { + Config::get_by_address(CoreAddresses::GENESIS_ADDRESS()) + } + + spec get_reward_config { + include GetRewardConfigAbortsIf; + } + + spec schema GetRewardConfigAbortsIf { + aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Get reward delay. + public fun reward_delay() :u64 { + let reward_config = get_reward_config(); + reward_config.reward_delay + } + + spec reward_delay { + aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Ring.move b/release/v13/sources/Ring.move new file mode 100644 index 00000000..1ad9f86b --- /dev/null +++ b/release/v13/sources/Ring.move @@ -0,0 +1,152 @@ +address StarcoinFramework { + +/// A ring-shaped container that can hold any type, indexed from 0 +/// The capacity is fixed at creation time, and the accessible index is constantly growing +module Ring { + + use StarcoinFramework::Vector; + use StarcoinFramework::Option; + use StarcoinFramework::Errors; + + + /// The index into the vector is out of bounds + const ERROR_RING_INDEX_OUT_OF_BOUNDS:u64 = 101; + + struct Ring has store{ + data : vector>, + insertion_index : u64, + external_index : u64 + } + + /// Create a Ring with capacity. + public fun create_with_capacity( len: u64 ):Ring{ + let data = Vector::empty>(); + let i = 0; + while(i < len){ + Vector::push_back(&mut data , Option::none()); + i = i + 1; + }; + Ring { + data : data, + insertion_index : 0, + external_index : 0, + } + } + + spec create_with_capacity{ + pragma intrinsic = true; + } + + ///is Ring full + public fun is_full(r: &Ring):bool{ + Option::is_some(Vector::borrow(&r.data, r.insertion_index)) + } + + spec is_full{ + pragma intrinsic = true; + } + + ///Return the capacity of the Ring. + public fun capacity(r: &Ring): u64{ + Vector::length( &r.data ) + } + + spec capacity{ + } + + /// Add element `e` to the insertion_index of the Ring `r`. + public fun push (r: &mut Ring , e: Element):Option::Option{ + let op_e = Vector::borrow_mut>(&mut r.data, r.insertion_index); + let res = if( Option::is_none(op_e) ){ + Option::fill( op_e, e); + Option::none() + }else{ + Option::some( Option::swap( op_e, e) ) + }; + r.insertion_index = ( r.insertion_index + 1 ) % Vector::length(&r.data); + r.external_index = r.external_index + 1; + res + } + + spec push{ + pragma intrinsic = true; + } + + /// Return a reference to the `i`th element in the Ring `r`. + public fun borrow(r:& Ring, i: u64):&Option::Option{ + let len = capacity(r); + if( r.external_index > len - 1) { + assert!( i >= r.external_index - len && i < r.external_index , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS)); + Vector::borrow(&r.data, i % len) + }else { + assert!( i < len , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS)); + Vector::borrow(&r.data, i ) + } + } + + spec borrow{ + pragma intrinsic = true; + } + + /// Return a mutable reference to the `i`th element in the Ring `r`. + public fun borrow_mut(r: &mut Ring, i: u64):&mut Option::Option{ + let len = capacity(r); + if( r.external_index > len - 1) { + assert!( i >= r.external_index - len && i < r.external_index , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS)); + Vector::borrow_mut(&mut r.data, i % len) + }else { + assert!( i < len , Errors::invalid_argument(ERROR_RING_INDEX_OUT_OF_BOUNDS)); + Vector::borrow_mut(&mut r.data, i ) + } + + } + + spec borrow_mut { + } + + + /// Return `Option::Option` if `e` is in the Ring `r` at index `i`. + /// Otherwise, returns `Option::none`. + public fun index_of(r: &Ring, e: &Element):Option::Option{ + let i = 0; + let len = capacity(r); + while ( i < len ) { + if ( Option::borrow(Vector::borrow( &r.data, i )) == e) return Option::some(i + r.external_index - len); + i = i + 1; + }; + Option::none() + } + + spec index_of{ + pragma intrinsic = true; + } + + /// Destroy the Ring `r`. + /// Returns the vector saved by ring + public fun destroy(r: Ring):vector{ + let Ring { + data : data , + insertion_index : _, + external_index : _, + } = r ; + let len = Vector::length(&data); + let i = 0; + let vec = Vector::empty(); + while ( i < len ) { + let op_e = Vector::pop_back( &mut data ); + if ( Option::is_some(&op_e) ) { + Vector::push_back(&mut vec, Option::destroy_some(op_e)) + }else { + Option::destroy_none(op_e) + }; + i = i + 1; + }; + Vector::destroy_empty(data); + vec + } + + spec destroy{ + pragma intrinsic = true; + } +} +} diff --git a/release/v13/sources/SIP_2.move b/release/v13/sources/SIP_2.move new file mode 100644 index 00000000..effeb896 --- /dev/null +++ b/release/v13/sources/SIP_2.move @@ -0,0 +1,15 @@ +address StarcoinFramework { +/// The modules define SIP. +/// Only the SIP that needs to do hard forked needs to be defined here, every SIP as a module, and can be a feature flag. + +/// https://github.com/starcoinorg/SIPs/tree/master/sip-2 +module SIP_2 { + +} + +/// https://github.com/starcoinorg/SIPs/tree/master/sip-3 +module SIP_3 { + +} + +} diff --git a/release/v13/sources/SIP_3.move b/release/v13/sources/SIP_3.move new file mode 100644 index 00000000..effeb896 --- /dev/null +++ b/release/v13/sources/SIP_3.move @@ -0,0 +1,15 @@ +address StarcoinFramework { +/// The modules define SIP. +/// Only the SIP that needs to do hard forked needs to be defined here, every SIP as a module, and can be a feature flag. + +/// https://github.com/starcoinorg/SIPs/tree/master/sip-2 +module SIP_2 { + +} + +/// https://github.com/starcoinorg/SIPs/tree/master/sip-3 +module SIP_3 { + +} + +} diff --git a/release/v13/sources/STC.move b/release/v13/sources/STC.move new file mode 100644 index 00000000..15ab8e8f --- /dev/null +++ b/release/v13/sources/STC.move @@ -0,0 +1,162 @@ +address StarcoinFramework { +/// STC is the token of Starcoin blockchain. +/// It uses apis defined in the `Token` module. +module STC { + use StarcoinFramework::FlexiDagConfig; + use StarcoinFramework::Token::{Self, Token}; + use StarcoinFramework::Dao; + use StarcoinFramework::ModifyDaoConfigProposal; + use StarcoinFramework::UpgradeModuleDaoProposal; + use StarcoinFramework::PackageTxnManager; + use StarcoinFramework::OnChainConfigDao; + use StarcoinFramework::TransactionPublishOption; + use StarcoinFramework::VMConfig; + use StarcoinFramework::ConsensusConfig; + use StarcoinFramework::RewardConfig; + use StarcoinFramework::TransactionTimeoutConfig; + use StarcoinFramework::Treasury; + use StarcoinFramework::CoreAddresses; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + + /// STC token marker. + struct STC has copy, drop, store { } + + /// precision of STC token. + const PRECISION: u8 = 9; + + /// Burn capability of STC. + struct SharedBurnCapability has key, store { + cap: Token::BurnCapability, + } + + /// STC initialization. + public fun initialize( + account: &signer, + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + ) { + Token::register_token(account, PRECISION); + let burn_cap = Token::remove_burn_capability(account); + move_to(account, SharedBurnCapability { cap: burn_cap }); + Dao::plugin( + account, + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + ); + ModifyDaoConfigProposal::plugin(account); + let upgrade_plan_cap = PackageTxnManager::extract_submit_upgrade_plan_cap(account); + UpgradeModuleDaoProposal::plugin( + account, + upgrade_plan_cap, + ); + // the following configurations are gov-ed by Dao. + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + } + + spec initialize { + include Token::RegisterTokenAbortsIf{precision: PRECISION}; + } + + public fun upgrade_from_v1_to_v2(account: &signer,total_amount: u128,): Treasury::WithdrawCapability { + CoreAddresses::assert_genesis_address(account); + + // Mint all stc, and destroy mint capability + let total_stc = Token::mint(account, total_amount-Token::market_cap()); + let withdraw_cap = Treasury::initialize(account, total_stc); + let mint_cap = Token::remove_mint_capability(account); + Token::destroy_mint_capability(mint_cap); + withdraw_cap + } + + spec upgrade_from_v1_to_v2 { + pragma verify = false; + } + + /// STC initialization. + public fun initialize_v2( + account: &signer, + total_amount: u128, + voting_delay: u64, + voting_period: u64, + voting_quorum_rate: u8, + min_action_delay: u64, + ): Treasury::WithdrawCapability { + Token::register_token(account, PRECISION); + + // Mint all stc, and destroy mint capability + + let total_stc = Token::mint(account, total_amount); + let withdraw_cap = Treasury::initialize(account, total_stc); + let mint_cap = Token::remove_mint_capability(account); + Token::destroy_mint_capability(mint_cap); + + let burn_cap = Token::remove_burn_capability(account); + move_to(account, SharedBurnCapability { cap: burn_cap }); + Dao::plugin( + account, + voting_delay, + voting_period, + voting_quorum_rate, + min_action_delay, + ); + ModifyDaoConfigProposal::plugin(account); + let upgrade_plan_cap = PackageTxnManager::extract_submit_upgrade_plan_cap(account); + UpgradeModuleDaoProposal::plugin( + account, + upgrade_plan_cap, + ); + // the following configurations are gov-ed by Dao. + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); + withdraw_cap + } + + spec initialize_v2 { + include Token::RegisterTokenAbortsIf{precision: PRECISION}; + } + + /// Returns true if `TokenType` is `STC::STC` + public fun is_stc(): bool { + Token::is_same_token() + } + + spec is_stc { + } + + /// Burn STC tokens. + /// It can be called by anyone. + public fun burn(token: Token) acquires SharedBurnCapability { + let cap = borrow_global(token_address()); + Token::burn_with_capability(&cap.cap, token); + } + + spec burn { + aborts_if Token::spec_abstract_total_value() - token.value < 0; + aborts_if !exists(Token::SPEC_TOKEN_TEST_ADDRESS()); + } + + /// Return STC token address. + public fun token_address(): address { + Token::token_address() + } + + spec token_address { + } +} +} \ No newline at end of file diff --git a/release/v13/sources/STCUSDOracle.move b/release/v13/sources/STCUSDOracle.move new file mode 100644 index 00000000..9241b263 --- /dev/null +++ b/release/v13/sources/STCUSDOracle.move @@ -0,0 +1,325 @@ +address StarcoinFramework { +module Oracle { + use StarcoinFramework::Event; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Signer; + use StarcoinFramework::Vector; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Account; + use StarcoinFramework::GenesisSignerCapability; + + struct OracleInfo has key { + ///The datasource counter + counter: u64, + ///Ext info + info: Info, + } + + struct DataRecord has copy, store, drop { + ///The data version + version: u64, + ///The record value + value: ValueT, + ///Update timestamp millisecond + updated_at: u64, + } + + struct OracleFeed has key { + record: DataRecord, + } + + struct OracleUpdateEvent has copy,store,drop { + source_id: u64, + record: DataRecord, + } + + struct DataSource has key { + /// the id of data source of ValueT + id: u64, + /// the data version counter. + counter: u64, + update_events: Event::EventHandle>, + } + + struct UpdateCapability has store, key { + account: address, + } + + struct GenesisSignerCapability has key{ + cap: Account::SignerCapability, + } + + /// The oracle type not register. + const ERR_ORACLE_TYPE_NOT_REGISTER:u64 = 101; + /// No capability to update the oracle value. + const ERR_NO_UPDATE_CAPABILITY: u64 = 102; + const ERR_NO_DATA_SOURCE: u64 = 103; + const ERR_CAPABILITY_ACCOUNT_MISS_MATCH: u64 = 104; + + /// deprecated. + public fun initialize(_sender: &signer) { + } + + /// Used in v7->v8 upgrade. struct `GenesisSignerCapability` is deprecated, in favor of module `StarcoinFramework::GenesisSignerCapability`. + public fun extract_signer_cap(signer: &signer): Account::SignerCapability acquires GenesisSignerCapability{ + CoreAddresses::assert_genesis_address(signer); + let cap = move_from(Signer::address_of(signer)); + let GenesisSignerCapability {cap} = cap; + cap + } + + /// Register `OracleT` as an oracle type. + public fun register_oracle(_sender: &signer, info: Info) { + let genesis_account = GenesisSignerCapability::get_genesis_signer(); + move_to(&genesis_account, OracleInfo { + counter: 0, + info, + }); + } + + /// Get the `OracleT` oracle's counter, the counter represent how many `OracleT` datasources + public fun get_oracle_counter() : u64 acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + oracle_info.counter + } + + public fun get_oracle_info() : Info acquires OracleInfo { + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + *&oracle_info.info + } + + /// Init a data source for type `OracleT` + public fun init_data_source(sender: &signer, init_value: ValueT) acquires OracleInfo{ + assert!(exists>(CoreAddresses::GENESIS_ADDRESS()), Errors::not_published(ERR_ORACLE_TYPE_NOT_REGISTER)); + let oracle_info = borrow_global_mut>(CoreAddresses::GENESIS_ADDRESS()); + let now = Timestamp::now_milliseconds(); + move_to(sender, OracleFeed { + record: DataRecord { + version: 0, + value: init_value, + updated_at: now, + } + }); + let sender_addr = Signer::address_of(sender); + move_to(sender, DataSource { + id: oracle_info.counter, + counter: 1, + update_events: Event::new_event_handle>(sender), + }); + move_to(sender, UpdateCapability{account: sender_addr}); + oracle_info.counter = oracle_info.counter + 1; + } + + /// Check the DataSource is initiailzed at ds_addr + public fun is_data_source_initialized(ds_addr: address): bool { + exists>(ds_addr) + } + + /// Update Oracle's record with new value, the `sender` must have UpdateCapability + public fun update(sender: &signer, value: ValueT) acquires UpdateCapability, DataSource, OracleFeed{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + let cap = borrow_global_mut>(account); + update_with_cap(cap,value); + } + + /// Update Oracle's record with new value and UpdateCapability + public fun update_with_cap(cap: &mut UpdateCapability, value: ValueT) acquires DataSource,OracleFeed { + let account = cap.account; + assert!(exists>(account), Errors::requires_capability(ERR_NO_DATA_SOURCE)); + let source = borrow_global_mut>(account); + let now = Timestamp::now_milliseconds(); + let oracle_feed = borrow_global_mut>(account); + oracle_feed.record.version = source.counter; + oracle_feed.record.value = value; + oracle_feed.record.updated_at = now; + source.counter = source.counter + 1; + Event::emit_event(&mut source.update_events,OracleUpdateEvent{ + source_id: source.id, + record: *&oracle_feed.record + }); + } + + /// Read the Oracle's value from `ds_addr` + public fun read(ds_addr: address): ValueT acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record.value + } + + /// Read the Oracle's DataRecord from `ds_addr` + public fun read_record(ds_addr: address): DataRecord acquires OracleFeed{ + let oracle_feed = borrow_global>(ds_addr); + *&oracle_feed.record + } + + /// Batch read Oracle's DataRecord from `ds_addrs` + public fun read_records(ds_addrs: &vector
): vector> acquires OracleFeed{ + let len = Vector::length(ds_addrs); + let results = Vector::empty(); + let i = 0; + while (i < len){ + let addr = *Vector::borrow(ds_addrs, i); + let record = Self::read_record(addr); + Vector::push_back(&mut results, record); + i = i + 1; + }; + results + } + + /// Remove UpdateCapability from current sender. + public fun remove_update_capability(sender: &signer):UpdateCapability acquires UpdateCapability{ + let account = Signer::address_of(sender); + assert!(exists>(account), Errors::requires_capability(ERR_NO_UPDATE_CAPABILITY)); + move_from>(account) + } + + /// Add UpdateCapability to current sender + public fun add_update_capability(sender: &signer, update_cap: UpdateCapability){ + assert!(Signer::address_of(sender) == update_cap.account, Errors::invalid_argument(ERR_CAPABILITY_ACCOUNT_MISS_MATCH)); + move_to(sender, update_cap); + } + + /// Unpack Record to fields: version, oracle, updated_at. + public fun unpack_record(record: DataRecord):(u64, ValueT, u64) { + (record.version,*&record.value,record.updated_at) + } +} +module PriceOracle{ + use StarcoinFramework::Math; + use StarcoinFramework::Oracle::{Self, DataRecord, UpdateCapability}; + + struct PriceOracleInfo has copy,store,drop{ + scaling_factor: u128, + } + + public entry fun register_oracle_entry(sender: signer, precision: u8){ + register_oracle(&sender, precision); + } + + public fun register_oracle(sender: &signer, precision: u8){ + let scaling_factor = Math::pow(10, (precision as u64)); + Oracle::register_oracle(sender, PriceOracleInfo{ + scaling_factor, + }); + } + + + public entry fun init_data_source_entry(sender: signer, init_value: u128){ + init_data_source(&sender, init_value); + } + + public fun init_data_source(sender: &signer, init_value: u128){ + Oracle::init_data_source(sender, init_value); + } + + public fun is_data_source_initialized(ds_addr: address): bool{ + Oracle::is_data_source_initialized(ds_addr) + } + + public fun get_scaling_factor() : u128 { + let info = Oracle::get_oracle_info(); + info.scaling_factor + } + + public entry fun update_entry(sender: signer, value: u128){ + update(&sender, value); + } + + public fun update(sender: &signer, value: u128){ + Oracle::update(sender, value); + } + + public fun update_with_cap(cap: &mut UpdateCapability, value: u128) { + Oracle::update_with_cap(cap, value); + } + + public fun read(addr: address) : u128{ + Oracle::read(addr) + } + + public fun read_record(addr: address): DataRecord{ + Oracle::read_record(addr) + } + + public fun read_records(addrs: &vector
): vector>{ + Oracle::read_records(addrs) + } + +} + +module STCUSDOracle{ + use StarcoinFramework::Oracle::{DataRecord}; + use StarcoinFramework::PriceOracle::{Self}; + + /// The STC to USD price oracle + struct STCUSD has copy,store,drop {} + + public fun register(sender: &signer){ + PriceOracle::register_oracle(sender, 6); + } + + public fun read(ds_addr: address) : u128{ + PriceOracle::read(ds_addr) + } + + public fun read_record(ds_addr: address): DataRecord{ + PriceOracle::read_record(ds_addr) + } + + public fun read_records(ds_addrs: &vector
): vector>{ + PriceOracle::read_records(ds_addrs) + } +} + +module PriceOracleScripts{ + use StarcoinFramework::PriceOracle; + + public entry fun register_oracle(sender: signer, precision: u8){ + PriceOracle::register_oracle_entry(sender, precision); + } + + public entry fun init_data_source(sender: signer, init_value: u128){ + PriceOracle::init_data_source_entry(sender, init_value); + } + + public entry fun update(sender: signer, value: u128){ + PriceOracle::update_entry(sender, value); + } +} + +module PriceOracleAggregator{ + use StarcoinFramework::Vector; + use StarcoinFramework::Oracle; + use StarcoinFramework::PriceOracle; + use StarcoinFramework::Math; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Errors; + + /// No price data match requirement condition. + const ERR_NO_PRICE_DATA_AVIABLE:u64 = 101; + + /// Get latest price from datasources and calculate avg. + /// `addrs`: the datasource's addr, `updated_in`: the datasource should updated in x millseoconds. + public fun latest_price_average_aggregator(addrs: &vector
, updated_in: u64): u128 { + let len = Vector::length(addrs); + let price_records = PriceOracle::read_records(addrs); + let prices = Vector::empty(); + let i = 0; + let expect_updated_after = Timestamp::now_milliseconds() - updated_in; + while (i < len){ + let record = Vector::pop_back(&mut price_records); + let (_version, price, updated_at) = Oracle::unpack_record(record); + if (updated_at >= expect_updated_after) { + Vector::push_back(&mut prices, price); + }; + i = i + 1; + }; + // if all price data not match the update_in filter, abort. + assert!(!Vector::is_empty(&prices), Errors::invalid_state(ERR_NO_PRICE_DATA_AVIABLE)); + Math::avg(&prices) + } +} + + +} \ No newline at end of file diff --git a/release/v13/sources/Secp256k1.move b/release/v13/sources/Secp256k1.move new file mode 100644 index 00000000..98a12c44 --- /dev/null +++ b/release/v13/sources/Secp256k1.move @@ -0,0 +1,132 @@ +/// This module implements ECDSA signatures based on the prime-order secp256k1 ellptic curve (i.e., cofactor is 1). + +module StarcoinFramework::Secp256k1 { + + use StarcoinFramework::Option::Option; + use StarcoinFramework::Option; + use StarcoinFramework::Vector; + use StarcoinFramework::Errors; + + /// An error occurred while deserializing, for example due to wrong input size. + const E_DESERIALIZE: u64 = 1; // This code must be the same, if ever returned from the native Rust implementation. + + /// The size of a secp256k1-based ECDSA public key, in bytes. + const RAW_PUBLIC_KEY_NUM_BYTES: u64 = 64; + //const COMPRESSED_PUBLIC_KEY_SIZE: u64 = 33; + + /// The size of a secp256k1-based ECDSA signature, in bytes. + const SIGNATURE_NUM_BYTES: u64 = 64; + + /// A 64-byte ECDSA public key. + struct ECDSARawPublicKey has copy, drop, store { + bytes: vector + } + + /// A 64-byte ECDSA signature. + struct ECDSASignature has copy, drop, store { + bytes: vector + } + + /// Constructs an ECDSASignature struct from the given 64 bytes. + public fun ecdsa_signature_from_bytes(bytes: vector): ECDSASignature { + assert!(Vector::length(&bytes) == SIGNATURE_NUM_BYTES, Errors::invalid_argument(E_DESERIALIZE)); + ECDSASignature { bytes } + } + + /// Constructs an ECDSARawPublicKey struct, given a 64-byte raw representation. + public fun ecdsa_raw_public_key_from_64_bytes(bytes: vector): ECDSARawPublicKey { + assert!(Vector::length(&bytes) == RAW_PUBLIC_KEY_NUM_BYTES, Errors::invalid_argument(E_DESERIALIZE)); + ECDSARawPublicKey { bytes } + } + + /// Serializes an ECDSARawPublicKey struct to 64-bytes. + public fun ecdsa_raw_public_key_to_bytes(pk: &ECDSARawPublicKey): vector { + *&pk.bytes + } + + /// Serializes an ECDSASignature struct to 64-bytes. + public fun ecdsa_signature_to_bytes(sig: &ECDSASignature): vector { + *&sig.bytes + } + + /// Recovers the signer's raw (64-byte) public key from a secp256k1 ECDSA `signature` given the `recovery_id` and the signed + /// `message` (32 byte digest). + /// + /// Note that an invalid signature, or a signature from a different message, will result in the recovery of an + /// incorrect public key. This recovery algorithm can only be used to check validity of a signature if the signer's + /// public key (or its hash) is known beforehand. + public fun ecdsa_recover( + message: vector, + recovery_id: u8, + signature: &ECDSASignature, + ): Option { + let (pk, success) = ecdsa_recover_internal(message, recovery_id, *&signature.bytes); + if (success) { + Option::some(ecdsa_raw_public_key_from_64_bytes(pk)) + } else { + Option::none() + } + } + + // + // Native functions + // + + /// Returns `(public_key, true)` if `signature` verifies on `message` under the recovered `public_key` + /// and returns `([], false)` otherwise. + native fun ecdsa_recover_internal( + message: vector, + recovery_id: u8, + signature: vector + ): (vector, bool); + + spec ecdsa_recover_internal { + pragma opaque; // Native + } + + // + // Tests + // + + #[test] + /// Test on a valid secp256k1 ECDSA signature created using sk = x"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + fun test_ecdsa_recover() { + use StarcoinFramework::Hash; + + let pk = ecdsa_recover( + Hash::sha2_256(b"test aptos secp256k1"), + 0, + &ECDSASignature { bytes: x"f7ad936da03f948c14c542020e3c5f4e02aaacd1f20427c11aa6e2fbf8776477646bba0e1a37f9e7c777c423a1d2849baafd7ff6a9930814a43c3f80d59db56f" }, + ); + assert!(Option::is_some(&pk), 1); + assert!( + *&Option::extract( + &mut pk + ).bytes == x"4646ae5047316b4230d0086c8acec687f00b1cd9d1dc634f6cb358ac0a9a8ffffe77b4dd0a4bfb95851f3b7355c781dd60f8418fc8a65d14907aff47c903a559", + 1 + ); + + // Flipped bits; Signature stays valid + let pk = ecdsa_recover( + Hash::sha2_256(b"test aptos secp256k1"), + 0, + // NOTE: A '7' was flipped to an 'f' here + &ECDSASignature { bytes: x"f7ad936da03f948c14c542020e3c5f4e02aaacd1f20427c11aa6e2fbf8776477646bba0e1a37f9e7c7f7c423a1d2849baafd7ff6a9930814a43c3f80d59db56f" }, + ); + assert!(Option::is_some(&pk), 1); + assert!( + *&Option::extract( + &mut pk + ).bytes != x"4646ae5047316b4230d0086c8acec687f00b1cd9d1dc634f6cb358ac0a9a8ffffe77b4dd0a4bfb95851f3b7355c781dd60f8418fc8a65d14907aff47c903a559", + 1 + ); + + // Flipped bits; Signature becomes invalid + let pk = ecdsa_recover( + Hash::sha2_256(b"test aptos secp256k1"), + 0, + &ECDSASignature { bytes: x"ffad936da03f948c14c542020e3c5f4e02aaacd1f20427c11aa6e2fbf8776477646bba0e1a37f9e7c7f7c423a1d2849baafd7ff6a9930814a43c3f80d59db56f" }, + ); + assert!(Option::is_none(&pk), 1); + } +} diff --git a/release/v13/sources/SharedEd25519PublicKey.move b/release/v13/sources/SharedEd25519PublicKey.move new file mode 100644 index 00000000..9b513d06 --- /dev/null +++ b/release/v13/sources/SharedEd25519PublicKey.move @@ -0,0 +1,110 @@ +address StarcoinFramework { +/// Each address that holds a `SharedEd25519PublicKey` resource can rotate the public key stored in +/// this resource, but the account's authentication key will be updated in lockstep. This ensures +/// that the two keys always stay in sync. +module SharedEd25519PublicKey { + use StarcoinFramework::Authenticator; + use StarcoinFramework::Account; + use StarcoinFramework::Signature; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// A resource that forces the account associated with `rotation_cap` to use a ed25519 + /// authentication key derived from `key` + struct SharedEd25519PublicKey has key { + /// 32 byte ed25519 public key + key: vector, + /// rotation capability for an account whose authentication key is always derived from `key` + rotation_cap: Account::KeyRotationCapability, + } + + const EMALFORMED_PUBLIC_KEY: u64 = 101; + + /// (1) Rotate the authentication key of the sender to `key` + /// (2) Publish a resource containing a 32-byte ed25519 public key and the rotation capability + /// of the sender under the `account`'s address. + /// Aborts if the sender already has a `SharedEd25519PublicKey` resource. + /// Aborts if the length of `new_public_key` is not 32. + public fun publish(account: &signer, key: vector) { + let t = SharedEd25519PublicKey { + key: x"", + rotation_cap: Account::extract_key_rotation_capability(account) + }; + rotate_key_(&mut t, key); + move_to(account, t); + } + + spec publish { + aborts_if !exists(Signer::address_of(account)); + aborts_if StarcoinFramework::Option::is_none(global(Signer::address_of(account)).key_rotation_capability); + aborts_if !exists( + StarcoinFramework::Option::borrow( + global(Signer::address_of(account)) + .key_rotation_capability + ).account_address); + aborts_if !Signature::ed25519_validate_pubkey(key); + aborts_if exists(Signer::address_of(account)); + aborts_if len(Authenticator::spec_ed25519_authentication_key(key)) != 32; + } + + fun rotate_key_(shared_key: &mut SharedEd25519PublicKey, new_public_key: vector) { + // Cryptographic check of public key validity + assert!( + Signature::ed25519_validate_pubkey(copy new_public_key), + Errors::invalid_argument(EMALFORMED_PUBLIC_KEY) + ); + Account::rotate_authentication_key_with_capability( + &shared_key.rotation_cap, + Authenticator::ed25519_authentication_key(copy new_public_key) + ); + shared_key.key = new_public_key; + } + + spec rotate_key_ { + aborts_if !exists(shared_key.rotation_cap.account_address); + aborts_if !Signature::ed25519_validate_pubkey(new_public_key); + aborts_if len(Authenticator::spec_ed25519_authentication_key(new_public_key)) != 32; + } + + /// (1) rotate the public key stored `account`'s `SharedEd25519PublicKey` resource to + /// `new_public_key` + /// (2) rotate the authentication key using the capability stored in the `account`'s + /// `SharedEd25519PublicKey` to a new value derived from `new_public_key` + /// Aborts if the sender does not have a `SharedEd25519PublicKey` resource. + /// Aborts if the length of `new_public_key` is not 32. + public fun rotate_key(account: &signer, new_public_key: vector) acquires SharedEd25519PublicKey { + rotate_key_(borrow_global_mut(Signer::address_of(account)), new_public_key); + } + + spec rotate_key { + aborts_if !exists(Signer::address_of(account)); + aborts_if !exists(global(Signer::address_of(account)).rotation_cap.account_address); + aborts_if !Signature::ed25519_validate_pubkey(new_public_key); + aborts_if len(Authenticator::spec_ed25519_authentication_key(new_public_key)) != 32; + } + + /// Return the public key stored under `addr`. + /// Aborts if `addr` does not hold a `SharedEd25519PublicKey` resource. + public fun key(addr: address): vector acquires SharedEd25519PublicKey { + *&borrow_global(addr).key + } + + spec key { + aborts_if !exists(addr); + } + + /// Returns true if `addr` holds a `SharedEd25519PublicKey` resource. + public fun exists_at(addr: address): bool { + exists(addr) + } + + spec exists_at { + aborts_if false; + } +} +} diff --git a/release/v13/sources/Signature.move b/release/v13/sources/Signature.move new file mode 100644 index 00000000..044636e4 --- /dev/null +++ b/release/v13/sources/Signature.move @@ -0,0 +1,131 @@ +address StarcoinFramework { + +/// Contains functions for [ed25519](https://en.wikipedia.org/wiki/EdDSA) digital signatures. +module Signature { + + use StarcoinFramework::Vector; + use StarcoinFramework::Option::{Self, Option}; + use StarcoinFramework::EVMAddress::{Self, EVMAddress}; + + native public fun ed25519_validate_pubkey(public_key: vector): bool; + native public fun ed25519_verify(signature: vector, public_key: vector, message: vector): bool; + + /// recover address from ECDSA signature, if recover fail, return an empty vector + native fun native_ecrecover(hash: vector, signature: vector): vector; + + /// recover address from ECDSA signature, if recover fail, return None + public fun ecrecover(hash: vector, signature: vector):Option{ + let bytes = native_ecrecover(hash, signature); + if (Vector::is_empty(&bytes)){ + Option::none() + }else{ + Option::some(EVMAddress::new(bytes)) + } + } + + // verify eth secp256k1 sign and compare addr, if add equal return true + public fun secp256k1_verify(signature: vector, addr: vector, message: vector) : bool{ + let receover_address_opt:Option = ecrecover(message, signature); + let expect_address = EVMAddress::new(addr); + &Option::destroy_some(receover_address_opt) == &expect_address + } + + spec module { + pragma intrinsic = true; + } + + #[test] + fun test_ecrecover_invalid(){ + let h = b"00"; + let s = b"00"; + let addr = ecrecover(h, s); + assert!(Option::is_none(&addr), 1001); + } +} + +module EVMAddress{ + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + use StarcoinFramework::Vector; + + const EVM_ADDR_LENGTH:u64 = 20; + + struct EVMAddress has copy, store, drop{ + bytes: vector, + } + + /// Create EVMAddress from bytes, If bytes is larger than EVM_ADDR_LENGTH(20), bytes will be cropped from the left. + /// keep same as https://github.com/ethereum/go-ethereum/blob/master/common/types.go#L302 + public fun new(bytes: vector): EVMAddress{ + let len = Vector::length(&bytes); + let bytes = if (len > EVM_ADDR_LENGTH){ + let new_bytes = Vector::empty(); + let i = 0; + while (i < EVM_ADDR_LENGTH) { + Vector::push_back(&mut new_bytes, *Vector::borrow(&bytes, i)); + i = i + 1; + }; + new_bytes + }else if (len == EVM_ADDR_LENGTH){ + bytes + }else{ + let i = 0; + let new_bytes = Vector::empty(); + while (i < EVM_ADDR_LENGTH - len) { + // pad zero to address + Vector::push_back(&mut new_bytes, 0); + i = i + 1; + }; + Vector::append(&mut new_bytes, bytes); + new_bytes + }; + EVMAddress{ + bytes + } + } + + spec new { + pragma verify = false; + //TODO + } + + /// Get the inner bytes of the `addr` as a reference + public fun as_bytes(addr: &EVMAddress): &vector { + &addr.bytes + } + + spec as_bytes { + pragma verify = false; + //TODO + } + + /// Unpack the `addr` to get its backing bytes + public fun into_bytes(addr: EVMAddress): vector { + let EVMAddress { bytes } = addr; + bytes + } + + spec into_bytes { + pragma verify = false; + //TODO + } + + #[test] + fun test_evm_address_padding(){ + let addr1 = new(x"00"); + let addr2 = new(x"0000"); + assert!(&addr1.bytes == &addr2.bytes, 1001); + } + + #[test] + fun test_evm_address_crop(){ + let addr1 = new(x"01234567890123456789012345678901234567891111"); + let addr2 = new(x"01234567890123456789012345678901234567892222"); + assert!(&addr1.bytes == &addr2.bytes, 1001); + } +} +} diff --git a/release/v13/sources/SignedInteger64.move b/release/v13/sources/SignedInteger64.move new file mode 100644 index 00000000..5258cc78 --- /dev/null +++ b/release/v13/sources/SignedInteger64.move @@ -0,0 +1,109 @@ +address StarcoinFramework { +/// Implementation of i64. +module SignedInteger64 { + + /// Define a signed integer type with two 32 bits. + struct SignedInteger64 has copy, drop, store { + value: u64, + is_negative: bool, + } + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// Multiply a u64 integer by a signed integer number. + public fun multiply_u64(num: u64, multiplier: SignedInteger64): SignedInteger64 { + let product = multiplier.value * num; + SignedInteger64 { value: product, is_negative: multiplier.is_negative } + } + + /// Divide a u64 integer by a signed integer number. + public fun divide_u64(num: u64, divisor: SignedInteger64): SignedInteger64 { + let quotient = num / divisor.value; + SignedInteger64 { value: quotient, is_negative: divisor.is_negative } + } + + /// Sub: `num - minus` + public fun sub_u64(num: u64, minus: SignedInteger64): SignedInteger64 { + if (minus.is_negative) { + let result = num + minus.value; + SignedInteger64 { value: result, is_negative: false } + } else { + if (num >= minus.value) { + let result = num - minus.value; + SignedInteger64 { value: result, is_negative: false } + }else { + let result = minus.value - num; + SignedInteger64 { value: result, is_negative: true } + } + } + } + + /// Add: `num + addend` + public fun add_u64(num: u64, addend: SignedInteger64): SignedInteger64 { + if (addend.is_negative) { + if (num >= addend.value) { + let result = num - addend.value; + SignedInteger64 { value: result, is_negative: false } + }else { + let result = addend.value - num; + SignedInteger64 { value: result, is_negative: true } + } + } else { + let result = num + addend.value; + SignedInteger64 { value: result, is_negative: false } + } + } + + /// Create a signed integer value from a unsigned integer + public fun create_from_raw_value(value: u64, is_negative: bool): SignedInteger64 { + SignedInteger64 { value, is_negative } + } + + /// Get value part of i64 ignore sign part. + public fun get_value(num: SignedInteger64): u64 { + num.value + } + + /// Check if the given num is negative. + public fun is_negative(num: SignedInteger64): bool { + num.is_negative + } + + // **************** SPECIFICATIONS **************** + + spec multiply_u64 { + aborts_if multiplier.value * num > max_u64(); + } + + spec divide_u64 { + aborts_if divisor.value == 0; + } + + spec sub_u64 { + aborts_if minus.is_negative && num + minus.value > max_u64(); + } + + spec add_u64 { + aborts_if !addend.is_negative && num + addend.value > max_u64(); + } + + spec create_from_raw_value { + aborts_if false; + ensures result == SignedInteger64 { value, is_negative }; + } + + spec get_value { + aborts_if false; + ensures result == num.value; + } + + spec is_negative { + aborts_if false; + ensures result == num.is_negative; + } + +} +} diff --git a/release/v13/sources/Signer.move b/release/v13/sources/Signer.move new file mode 100644 index 00000000..47ec53be --- /dev/null +++ b/release/v13/sources/Signer.move @@ -0,0 +1,28 @@ +address StarcoinFramework { +/// Provide access methods for Signer. +module Signer { + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + /// Borrows the address of the signer + /// Conceptually, you can think of the `signer` as being a resource struct wrapper around an + /// address + /// ``` + /// resource struct Signer has key, store { addr: address } + /// ``` + /// `borrow_address` borrows this inner field + native public fun borrow_address(s: &signer): &address; + + /// Copies the address of the signer + public fun address_of(s: &signer): address { + *borrow_address(s) + } + + spec address_of { + pragma opaque = true; + aborts_if false; + ensures result == address_of(s); + } +} +} diff --git a/release/v13/sources/SimpleMap.move b/release/v13/sources/SimpleMap.move new file mode 100644 index 00000000..0b7127af --- /dev/null +++ b/release/v13/sources/SimpleMap.move @@ -0,0 +1,289 @@ +address StarcoinFramework { +/// This module provides a solution for sorted maps, that is it has the properties that +/// 1) Keys point to Values +/// 2) Each Key must be unique +/// 3) A Key can be found within O(N) time +/// 4) The keys are unsorted. +/// 5) Adds and removals take O(N) time +module SimpleMap { + use StarcoinFramework::Errors; + use StarcoinFramework::Option; + use StarcoinFramework::Vector; + + /// Map key already exists + const EKEY_ALREADY_EXISTS: u64 = 1; + /// Map key is not found + const EKEY_NOT_FOUND: u64 = 2; + + struct SimpleMap has copy, drop, store { + data: vector>, + } + + struct Element has copy, drop, store { + key: Key, + value: Value, + } + + public fun length(map: &SimpleMap): u64 { + Vector::length(&map.data) + } + + spec length { + pragma intrinsic = true; + } + + public fun create(): SimpleMap { + SimpleMap { + data: Vector::empty(), + } + } + + spec create { + pragma intrinsic = true; + } + + public fun borrow( + map: &SimpleMap, + key: &Key, + ): &Value { + let maybe_idx = find(map, key); + assert!(Option::is_some(&maybe_idx), Errors::invalid_argument(EKEY_NOT_FOUND)); + let idx = Option::extract(&mut maybe_idx); + &Vector::borrow(&map.data, idx).value + } + + spec borrow { + pragma intrinsic = true; + } + + + public fun borrow_mut( + map: &mut SimpleMap, + key: &Key, + ): &mut Value { + let maybe_idx = find(map, key); + assert!(Option::is_some(&maybe_idx), Errors::invalid_argument(EKEY_NOT_FOUND)); + let idx = Option::extract(&mut maybe_idx); + &mut Vector::borrow_mut(&mut map.data, idx).value + } + + spec borrow_mut { + pragma intrinsic = true; + } + + + public fun contains_key( + map: &SimpleMap, + key: &Key, + ): bool { + let maybe_idx = find(map, key); + Option::is_some(&maybe_idx) + } + + spec contains_key { + pragma intrinsic = true; + } + + + public fun destroy_empty(map: SimpleMap) { + let SimpleMap { data } = map; + Vector::destroy_empty(data); + } + + spec destroy_empty { + pragma intrinsic = true; + } + + public fun add( + map: &mut SimpleMap, + key: Key, + value: Value, + ) { + let maybe_idx = find(map, &key); + assert!(Option::is_none(&maybe_idx), Errors::invalid_argument(EKEY_ALREADY_EXISTS)); + + Vector::push_back(&mut map.data, Element { key, value }); + } + + spec add { + pragma intrinsic = true; + } + + + /// Insert key/value pair or update an existing key to a new value + public fun upsert( + map: &mut SimpleMap, + key: Key, + value: Value + ): (Option::Option, Option::Option) { + let data = &mut map.data; + let len = Vector::length(data); + let i = 0; + while (i < len) { + let element = Vector::borrow(data, i); + if (&element.key == &key) { + Vector::push_back(data, Element { key, value }); + Vector::swap(data, i, len); + let Element { key, value } = Vector::pop_back(data); + return (Option::some(key), Option::some(value)) + }; + i = i + 1; + }; + Vector::push_back(&mut map.data, Element { key, value }); + (Option::none(), Option::none()) + } + + spec upsert { + pragma verify=false; + } + + + public fun remove( + map: &mut SimpleMap, + key: &Key, + ): (Key, Value) { + let maybe_idx = find(map, key); + assert!(Option::is_some(&maybe_idx), Errors::invalid_argument(EKEY_NOT_FOUND)); + let placement = Option::extract(&mut maybe_idx); + let Element { key, value } = Vector::swap_remove(&mut map.data, placement); + (key, value) + } + + spec remove { + pragma intrinsic = true; + } + + fun find( + map: &SimpleMap, + key: &Key, + ): Option::Option { + let leng = Vector::length(&map.data); + let i = 0; + while (i < leng) { + let element = Vector::borrow(&map.data, i); + if (&element.key == key) { + return Option::some(i) + }; + i = i + 1; + }; + Option::none() + } + + spec find { + pragma verify=false; + } + + + #[test] + public fun add_remove_many() { + let map = create(); + + assert!(length(&map) == 0, 0); + assert!(!contains_key(&map, &3), 1); + add(&mut map, 3, 1); + assert!(length(&map) == 1, 2); + assert!(contains_key(&map, &3), 3); + assert!(borrow(&map, &3) == &1, 4); + *borrow_mut(&mut map, &3) = 2; + assert!(borrow(&map, &3) == &2, 5); + + assert!(!contains_key(&map, &2), 6); + add(&mut map, 2, 5); + assert!(length(&map) == 2, 7); + assert!(contains_key(&map, &2), 8); + assert!(borrow(&map, &2) == &5, 9); + *borrow_mut(&mut map, &2) = 9; + assert!(borrow(&map, &2) == &9, 10); + + remove(&mut map, &2); + assert!(length(&map) == 1, 11); + assert!(!contains_key(&map, &2), 12); + assert!(borrow(&map, &3) == &2, 13); + + remove(&mut map, &3); + assert!(length(&map) == 0, 14); + assert!(!contains_key(&map, &3), 15); + + destroy_empty(map); + } + + #[test] + public fun test_several() { + let map = create(); + add(&mut map, 6, 6); + add(&mut map, 1, 1); + add(&mut map, 5, 5); + add(&mut map, 2, 2); + add(&mut map, 3, 3); + add(&mut map, 0, 0); + add(&mut map, 7, 7); + add(&mut map, 4, 4); + + assert!(Option::destroy_some(find(&map, &6)) == 0, 100); + assert!(Option::destroy_some(find(&map, &1)) == 1, 101); + assert!(Option::destroy_some(find(&map, &5)) == 2, 102); + assert!(Option::destroy_some(find(&map, &2)) == 3, 103); + assert!(Option::destroy_some(find(&map, &3)) == 4, 104); + assert!(Option::destroy_some(find(&map, &0)) == 5, 105); + assert!(Option::destroy_some(find(&map, &7)) == 6, 106); + assert!(Option::destroy_some(find(&map, &4)) == 7, 107); + + remove(&mut map, &0); + remove(&mut map, &1); + remove(&mut map, &2); + remove(&mut map, &3); + remove(&mut map, &4); + remove(&mut map, &5); + remove(&mut map, &6); + remove(&mut map, &7); + + destroy_empty(map); + } + + #[test] + #[expected_failure] + public fun add_twice() { + let map = create(); + add(&mut map, 3, 1); + add(&mut map, 3, 1); + + remove(&mut map, &3); + destroy_empty(map); + } + + #[test] + #[expected_failure] + public fun remove_twice() { + let map = create(); + add(&mut map, 3, 1); + remove(&mut map, &3); + remove(&mut map, &3); + + destroy_empty(map); + } + + #[test] + public fun upsert_test() { + let map = create(); + // test adding 3 elements using upsert + upsert(&mut map, 1, 1); + upsert(&mut map, 2, 2); + upsert(&mut map, 3, 3); + + assert!(length(&map) == 3, 0); + assert!(contains_key(&map, &1), 1); + assert!(contains_key(&map, &2), 2); + assert!(contains_key(&map, &3), 3); + assert!(borrow(&map, &1) == &1, 4); + assert!(borrow(&map, &2) == &2, 5); + assert!(borrow(&map, &3) == &3, 6); + + // change mapping 1->1 to 1->4 + upsert(&mut map, 1, 4); + + assert!(length(&map) == 3, 7); + assert!(contains_key(&map, &1), 8); + assert!(borrow(&map, &1) == &4, 9); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/StarcoinVerifier.move b/release/v13/sources/StarcoinVerifier.move new file mode 100644 index 00000000..ea985cf1 --- /dev/null +++ b/release/v13/sources/StarcoinVerifier.move @@ -0,0 +1,356 @@ +address StarcoinFramework { +module StarcoinVerifier { + use StarcoinFramework::Vector; + use StarcoinFramework::Option; + use StarcoinFramework::BCS; + use StarcoinFramework::StructuredHash; + use StarcoinFramework::Hash; + + const HASH_LEN_IN_BITS: u64 = 32 * 8; + const SPARSE_MERKLE_LEAF_NODE: vector = b"SparseMerkleLeafNode"; + const SPARSE_MERKLE_INTERNAL_NODE: vector = b"SparseMerkleInternalNode"; + const BLOB_HASH_PREFIX: vector = b"Blob"; + const DEFAULT_VALUE: vector = x""; + const ACCOUNT_STORAGE_INDEX_RESOURCE: u64 = 1; + const ERROR_ACCOUNT_STORAGE_ROOTS: u64 = 101; + const ERROR_LITERAL_HASH_WRONG_LENGTH: u64 = 102; + const SPARSE_MERKLE_PLACEHOLDER_HASH_LITERAL: vector = b"SPARSE_MERKLE_PLACEHOLDER_HASH"; + + + struct AccountState has store, drop, copy { + storage_roots: vector>>, + } + + public fun bcs_deserialize_account_state(data: &vector): AccountState { + let (vec, _) = BCS::deserialize_option_bytes_vector(data, 0); + AccountState{ + storage_roots: vec + } + } + + struct StateProof has store, drop, copy { + /** + * Account state's proof for global state root. + */ + account_proof: SparseMerkleProof, + /** + * Account state including storage roots. + */ + account_state: vector, + /** + * State's proof for account storage root. + */ + proof: SparseMerkleProof, + } + + public fun new_state_proof(account_proof: SparseMerkleProof, account_state: vector, proof: SparseMerkleProof): StateProof { + StateProof{ + account_proof, + account_state, + proof, + } + } + + struct SparseMerkleProof has store, drop, copy { + siblings: vector>, + leaf: SMTNode, + } + + public fun new_sparse_merkle_proof(siblings: vector>, leaf: SMTNode): SparseMerkleProof { + SparseMerkleProof{ + siblings, + leaf, + } + } + + struct SMTNode has store, drop, copy { + hash1: vector, + hash2: vector, + } + + public fun new_smt_node(hash1: vector, hash2: vector): SMTNode { + SMTNode{ + hash1, + hash2, + } + } + + public fun empty_smt_node(): SMTNode { + SMTNode{ + hash1: Vector::empty(), + hash2: Vector::empty(), + } + } + + public fun verify_state_proof(state_proof: &StateProof, state_root: &vector, + account_address: address, resource_struct_tag: &vector, + state: &vector): bool { + let accountState: AccountState = bcs_deserialize_account_state(&state_proof.account_state); + assert!(Vector::length(&accountState.storage_roots) > ACCOUNT_STORAGE_INDEX_RESOURCE, ERROR_ACCOUNT_STORAGE_ROOTS); + + // First, verify state for storage root. + let storageRoot = Option::borrow(Vector::borrow(&accountState.storage_roots, ACCOUNT_STORAGE_INDEX_RESOURCE)); + let ok: bool = verify_smp(&state_proof.proof.siblings, + &state_proof.proof.leaf, + storageRoot, + resource_struct_tag, // resource struct tag BCS serialized as key + state); + if (!ok) { + return false + }; + + // Then, verify account state for global state root. + ok = verify_smp(&state_proof.account_proof.siblings, + &state_proof.account_proof.leaf, + state_root, + &BCS::to_bytes
(&account_address), // account address as key + &state_proof.account_state, + ); + ok + } + + #[test] + fun test_verify_state_proof() { + // miannet, block number 6495396 + let state_root = x"d337896a5cd8bae3d0130e09409c0f5eede159d93af38a642528acb15c1204b8"; + let account_address = @0x47d36856884d7fb9e91a475ea3472341; +// let state = x""; + let state = x"00000000000000000000000000000000"; + // 0x00000000000000000000000000000001::Account::Balance<0x8c109349c6bd91411d6bc962e080c4a3::STAR::STAR> + let resource_struct_tag = x"00000000000000000000000000000001074163636f756e740742616c616e636501078c109349c6bd91411d6bc962e080c4a30453544152045354415200"; + + let account_proof_sibling_nodes = Vector::empty>(); + Vector::push_back(&mut account_proof_sibling_nodes, x"b81050a469dbe041f915cda6942143c691b1735599815142c895f77cf088a656"); + Vector::push_back(&mut account_proof_sibling_nodes, x"5350415253455f4d45524b4c455f504c414345484f4c4445525f484153480000"); + Vector::push_back(&mut account_proof_sibling_nodes, x"1c0cbf70e7474e739db9ca9958470f605f37a5a0f322c7c854b24866c4330577"); + Vector::push_back(&mut account_proof_sibling_nodes, x"68dde7ba4f4a9cf6329675e598a1ab7b545f8de36e5cb8151be8ff167e479c26"); + Vector::push_back(&mut account_proof_sibling_nodes, x"3c59423b2956d25cdacf638540e39dbc53238d36ca1420d31c4321580aeff633"); + Vector::push_back(&mut account_proof_sibling_nodes, x"5befec9a99ad40f1cb6d5b44c87ca6ad26841535cd7fac27f2f88205088b55e3"); + Vector::push_back(&mut account_proof_sibling_nodes, x"32f4d82b78b1339fb5d9c60ac2e49780c87b9e9c675bee9d1cb3ace3f34a63d6"); + Vector::push_back(&mut account_proof_sibling_nodes, x"a60429524592cac0170763196269c4997e08b6a09b2ad45647775486a81559af"); + Vector::push_back(&mut account_proof_sibling_nodes, x"6b6bc4e16bad1fbc6c6df21a923a9be06ae8508827cdd3dbdd4e0e6607abdb6d"); + Vector::push_back(&mut account_proof_sibling_nodes, x"5e6165bc60b30f46611d52f9779668e0fa79eeb60bf3a0d90346b33331156155"); + Vector::push_back(&mut account_proof_sibling_nodes, x"dfc42240b0d542457748e873e3ab0ee362c68dedd91df13532cd85a1a6ea6f00"); + Vector::push_back(&mut account_proof_sibling_nodes, x"610cba3b3c467b137ddbda0f5783ef269357ca4e30aaa2cfecb96e2ee8b2c5e7"); + Vector::push_back(&mut account_proof_sibling_nodes, x"179235bb93b8ece25921f7405a2f797f80630d90f71e763e8a700734d6945b99"); + Vector::push_back(&mut account_proof_sibling_nodes, x"85d80d435c4cb8b8034d32aff6b05230efc43b583154428a0990e1f752adcf3a"); + Vector::push_back(&mut account_proof_sibling_nodes, x"a2f4a3e6f11e6b42d700c920c06a89ffe6d086d5411aa578d56d8de000704669"); + Vector::push_back(&mut account_proof_sibling_nodes, x"ee57409d642877366ac26b2bf8948f7daae3c45a545b931b28a6d902e01bdc1f"); + + let state_proof_sibling_nodes = Vector::empty>(); + Vector::push_back(&mut state_proof_sibling_nodes, x"2a3c2096fbd5a1a2e81077e4b2156c7232b9291ad3d85ea7451eb8b7cda828fd"); + Vector::push_back(&mut state_proof_sibling_nodes, x"4cc4f038091aba95645a5b8153dc088ffdbfb7c7e82dd6b166f187b33eea7432"); + Vector::push_back(&mut state_proof_sibling_nodes, x"aa140a1627b5385e108f6580062110463d09768bce681bbb88c3d9c59680d75d"); + Vector::push_back(&mut state_proof_sibling_nodes, x"7c8f59d557168dd5667fcc950ed444cfa0cbce778e032c918a8b2a2084c48c03"); + Vector::push_back(&mut state_proof_sibling_nodes, x"a0718e77be611f67f880f5fc4d7c801940aae65890f02b38a663458ed924c2f9"); + + let proof = new_state_proof( + new_sparse_merkle_proof( + account_proof_sibling_nodes, + new_smt_node( + x"3fe0547cb3576cad025fb5cfa98b85a3545a41e5b14e844fd8cad5edaa619c05", + x"ed0e07d03371a130b84bea8245f84bf546955e5a190afc20ef34f310614c6d10", + ), + ), + x"02000120ceaafd667b54252bba61993770d87bbb997b1a689b0e08899543e3c8f82adca7", + new_sparse_merkle_proof( + state_proof_sibling_nodes, + new_smt_node( + x"1de0d92e4e770fa53ceaa12c83edb8c0e51c1d19499d769c572ffd9d38cef40f", + x"6493204f1b87055adb8937a385daa238b3c08c491026f2ac50ebe4dab9133030", + ), + ), + ); + + let b = verify_state_proof( + &proof, + &state_root, + account_address, + &resource_struct_tag, + &state, + ); + assert!(b, 1110); + } + + /// Verify sparse merkle proof by key and value. + public fun verify_smp(sibling_nodes: &vector>, leaf_data: &SMTNode, expected_root: &vector, key: &vector, value: &vector): bool { + let path = hash_key(key); + let current_hash: vector; + if (*value == DEFAULT_VALUE) { + // Non-membership proof. + if (empty_smt_node() == *leaf_data) { + current_hash = placeholder(); + } else { + if (*&leaf_data.hash1 == *&path) { + return false + }; + if (!(count_common_prefix(&leaf_data.hash1, &path) >= Vector::length(sibling_nodes))) { + return false + }; + current_hash = StructuredHash::hash(SPARSE_MERKLE_LEAF_NODE, leaf_data); + }; + } else { + // Membership proof. + if (empty_smt_node() == *leaf_data) { + return false + }; + if (*&leaf_data.hash1 != *&path) { + return false + }; + let value_hash = hash_value(value); + if (*&leaf_data.hash2 != value_hash) { + return false + }; + current_hash = StructuredHash::hash(SPARSE_MERKLE_LEAF_NODE, leaf_data); + }; + + current_hash = compute_smp_root_by_path_and_node_hash(sibling_nodes, &path, ¤t_hash); + current_hash == *expected_root + } + +// #[test] +// fun test_print_storage_root(){ +// let account_state = x"02000120ceaafd667b54252bba61993770d87bbb997b1a689b0e08899543e3c8f82adca7"; +// let accountState: AccountState = bcs_deserialize_account_state(&account_state); +// let storageRoot = Option::borrow(Vector::borrow(&accountState.storage_roots, ACCOUNT_STORAGE_INDEX_RESOURCE)); +// Debug::print(storageRoot); +// } + + #[test] + fun test_verify_smp() { + let sibling_nodes = Vector::empty>(); + Vector::push_back(&mut sibling_nodes, x"2a3c2096fbd5a1a2e81077e4b2156c7232b9291ad3d85ea7451eb8b7cda828fd"); + Vector::push_back(&mut sibling_nodes, x"4cc4f038091aba95645a5b8153dc088ffdbfb7c7e82dd6b166f187b33eea7432"); + Vector::push_back(&mut sibling_nodes, x"aa140a1627b5385e108f6580062110463d09768bce681bbb88c3d9c59680d75d"); + Vector::push_back(&mut sibling_nodes, x"7c8f59d557168dd5667fcc950ed444cfa0cbce778e032c918a8b2a2084c48c03"); + Vector::push_back(&mut sibling_nodes, x"a0718e77be611f67f880f5fc4d7c801940aae65890f02b38a663458ed924c2f9"); + + let leaf_node = new_smt_node( + x"1de0d92e4e770fa53ceaa12c83edb8c0e51c1d19499d769c572ffd9d38cef40f", + x"6493204f1b87055adb8937a385daa238b3c08c491026f2ac50ebe4dab9133030", + ); + let account_state = x"02000120ceaafd667b54252bba61993770d87bbb997b1a689b0e08899543e3c8f82adca7"; + let accountState: AccountState = bcs_deserialize_account_state(&account_state); + let expected_root = Option::borrow(Vector::borrow(&accountState.storage_roots, ACCOUNT_STORAGE_INDEX_RESOURCE)); +// let expected_root = x"0f30a41872208c6324fa842889315b14f9be6f3dd0d5050686317adfdd0cda60"; + let key = x"00000000000000000000000000000001074163636f756e740742616c616e636501078c109349c6bd91411d6bc962e080c4a30453544152045354415200"; + // Above key is this StructTag BCS serialized bytes: + let value = x"00000000000000000000000000000000"; + + let b = verify_smp(&sibling_nodes, &leaf_node, expected_root, &key, &value); + assert!(b, 1112) + } + + #[test] + fun test_verify_smp_2() { + let sibling_nodes: vector> = Vector::empty(); + let leaf_data: SMTNode = empty_smt_node(); + let expected_root: vector = placeholder(); + let key: vector = b"random key"; + let value: vector = Vector::empty(); //x"" + let b = verify_smp(&sibling_nodes, &leaf_data, &expected_root, &key, &value); + assert!(b, 1113); + + value = b"random value"; + b = verify_smp(&sibling_nodes, &leaf_data, &expected_root, &key, &value); + assert!(!b, 1114); + } + + public fun compute_smp_root_by_path_and_node_hash(sibling_nodes: &vector>, path: &vector, node_hash: &vector): vector { + let current_hash = *node_hash; + let i = 0; + let proof_length = Vector::length(sibling_nodes); + while (i < proof_length) { + let sibling = *Vector::borrow(sibling_nodes, i); + let bit = get_bit_at_from_msb(path, proof_length - i - 1); + let internal_node = if (bit) { + SMTNode{ hash1: sibling, hash2: current_hash } + } else { + SMTNode{ hash1: current_hash, hash2: sibling } + }; + current_hash = StructuredHash::hash(SPARSE_MERKLE_INTERNAL_NODE, &internal_node); + i = i + 1; + }; + current_hash + } + + public fun placeholder(): vector { + create_literal_hash(&SPARSE_MERKLE_PLACEHOLDER_HASH_LITERAL) + } + + public fun create_literal_hash(word: &vector): vector { + if (Vector::length(word) <= 32) { + let lenZero = 32 - Vector::length(word); + let i = 0; + let r = *word; + while (i < lenZero) { + Vector::push_back(&mut r, 0); + i = i + 1; + }; + return r + }; + abort ERROR_LITERAL_HASH_WRONG_LENGTH + } + + #[test] + fun test_create_literal_hash() { + let word = b"SPARSE_MERKLE_PLACEHOLDER_HASH"; + let r = create_literal_hash(&word); + assert!(r == x"5350415253455f4d45524b4c455f504c414345484f4c4445525f484153480000", 1115); + } + + fun hash_key(key: &vector): vector { + Hash::sha3_256(*key) + } + + fun hash_value(value: &vector): vector { + StructuredHash::hash(BLOB_HASH_PREFIX, value) + } + + fun count_common_prefix(data1: &vector, data2: &vector): u64 { + let count = 0; + let i = 0; + while ( i < Vector::length(data1) * 8) { + if (get_bit_at_from_msb(data1, i) == get_bit_at_from_msb(data2, i)) { + count = count + 1; + } else { + break + }; + i = i + 1; + }; + count + } + + fun get_bit_at_from_msb(data: &vector, index: u64): bool { + let pos = index / 8; + let bit = (7 - index % 8); + (*Vector::borrow(data, pos) >> (bit as u8)) & 1u8 != 0 + } + + spec get_bit_at_from_msb { + pragma verify = false; // Bitwise operator + pragma opaque; + } +} + +module StructuredHash { + use StarcoinFramework::Hash; + use StarcoinFramework::Vector; + use StarcoinFramework::BCS; + + const STARCOIN_HASH_PREFIX: vector = b"STARCOIN::"; + + public fun hash(structure: vector, data: &MoveValue): vector { + let prefix_hash = Hash::sha3_256(concat(&STARCOIN_HASH_PREFIX, structure)); + let bcs_bytes = BCS::to_bytes(data); + Hash::sha3_256(concat(&prefix_hash, bcs_bytes)) + } + + fun concat(v1: &vector, v2: vector): vector { + let data = *v1; + Vector::append(&mut data, v2); + data + } +} + +} diff --git a/release/v13/sources/StdlibUpgradeScripts.move b/release/v13/sources/StdlibUpgradeScripts.move new file mode 100644 index 00000000..7c534495 --- /dev/null +++ b/release/v13/sources/StdlibUpgradeScripts.move @@ -0,0 +1,133 @@ +address StarcoinFramework { +/// The module for StdlibUpgrade init scripts +module StdlibUpgradeScripts { + + use StarcoinFramework::Math::u64_max; + use StarcoinFramework::FlexiDagConfig; + use StarcoinFramework::EasyGas; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::STC::{Self, STC}; + use StarcoinFramework::Token::{Self, LinearTimeMintKey}; + use StarcoinFramework::TreasuryWithdrawDaoProposal; + use StarcoinFramework::Treasury::{Self, LinearWithdrawCapability}; + use StarcoinFramework::Offer; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Collection; + use StarcoinFramework::Oracle; + use StarcoinFramework::STCUSDOracle; + use StarcoinFramework::NFT; + use StarcoinFramework::GenesisNFT; + use StarcoinFramework::LanguageVersion; + use StarcoinFramework::OnChainConfigDao; + use StarcoinFramework::Config; + use StarcoinFramework::GenesisSignerCapability; + use StarcoinFramework::Account; + use StarcoinFramework::Block; + use StarcoinFramework::GasSchedule; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + + /// Stdlib upgrade script from v2 to v3 + public entry fun upgrade_from_v2_to_v3(account: signer, total_stc_amount: u128 ) { + CoreAddresses::assert_genesis_address(&account); + + let withdraw_cap = STC::upgrade_from_v1_to_v2(&account, total_stc_amount); + + let mint_keys = Collection::borrow_collection>(CoreAddresses::ASSOCIATION_ROOT_ADDRESS()); + let mint_key = Collection::borrow(&mint_keys, 0); + let (total, minted, start_time, period) = Token::read_linear_time_key(mint_key); + Collection::return_collection(mint_keys); + + let now = Timestamp::now_seconds(); + let linear_withdraw_cap = Treasury::issue_linear_withdraw_capability(&mut withdraw_cap, total-minted, period - (now - start_time)); + // Lock the TreasuryWithdrawCapability to Dao + TreasuryWithdrawDaoProposal::plugin(&account, withdraw_cap); + // Give a LinearWithdrawCapability Offer to association, association need to take the offer, and destroy old LinearTimeMintKey. + Offer::create(&account, linear_withdraw_cap, CoreAddresses::ASSOCIATION_ROOT_ADDRESS(), 0); + } + + /// association account should call this script after upgrade from v2 to v3. + public entry fun take_linear_withdraw_capability(signer: signer){ + let offered = Offer::redeem>(&signer, CoreAddresses::GENESIS_ADDRESS()); + Treasury::add_linear_withdraw_capability(&signer, offered); + let mint_key = Collection::take>(&signer); + Token::destroy_linear_time_key(mint_key); + } + + public fun do_upgrade_from_v5_to_v6(sender: &signer) { + CoreAddresses::assert_genesis_address(sender); + Oracle::initialize(sender); + //register oracle + STCUSDOracle::register(sender); + NFT::initialize(sender); + let merkle_root = x"5969f0e8e19f8769276fb638e6060d5c02e40088f5fde70a6778dd69d659ee6d"; + let image = b"ipfs://QmSPcvcXgdtHHiVTAAarzTeubk5X3iWymPAoKBfiRFjPMY"; + GenesisNFT::initialize(sender, merkle_root, 1639u64, image); + } + + public entry fun upgrade_from_v5_to_v6(sender: signer) { + Self::do_upgrade_from_v5_to_v6(&sender) + } + + public entry fun upgrade_from_v6_to_v7(sender: signer) { + Self::do_upgrade_from_v6_to_v7_with_language_version(&sender, 2); + } + + /// deprecated, use `do_upgrade_from_v6_to_v7_with_language_version`. + public fun do_upgrade_from_v6_to_v7(sender: &signer) { + do_upgrade_from_v6_to_v7_with_language_version(sender, 2); + } + + public fun do_upgrade_from_v6_to_v7_with_language_version(sender: &signer, language_version: u64) { + // initialize the language version config. + Config::publish_new_config(sender, LanguageVersion::new(language_version)); + // use STC Dao to upgrade onchain's move-language-version configuration. + OnChainConfigDao::plugin(sender); + // upgrade genesis NFT + GenesisNFT::upgrade_to_nft_type_info_v2(sender); + } + + public entry fun upgrade_from_v7_to_v8(sender: signer) { + do_upgrade_from_v7_to_v8(&sender); + } + public fun do_upgrade_from_v7_to_v8(sender: &signer) { + { + let cap = Oracle::extract_signer_cap(sender); + GenesisSignerCapability::initialize(sender, cap); + }; + + { + let cap = NFT::extract_signer_cap(sender); + Account::destroy_signer_cap(cap); + }; + } + + public entry fun upgrade_from_v11_to_v12(sender: signer) { + do_upgrade_from_v11_to_v12(&sender); + } + public fun do_upgrade_from_v11_to_v12(sender: &signer) { + { + GasSchedule::initialize(sender,GasSchedule::new_gas_schedule()); + let address = @0x8c109349c6bd91411d6bc962e080c4a3; + EasyGas::initialize(sender, + address, + b"STAR",b"STAR", + address); + Block::checkpoints_init(sender); + }; + } + + public entry fun upgrade_from_v12_to_v13(sender: signer) { + do_upgrade_from_v12_to_v13(&sender); + } + public fun do_upgrade_from_v12_to_v13(sender: &signer) { + { + FlexiDagConfig::initialize(sender, u64_max()); + Block::checkpoints_init(sender); + }; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/String.move b/release/v13/sources/String.move new file mode 100644 index 00000000..12c98456 --- /dev/null +++ b/release/v13/sources/String.move @@ -0,0 +1,128 @@ +/// The `string` module defines the `String` type which represents UTF8 encoded strings. +module StarcoinFramework::String { + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + use StarcoinFramework::Option::{Self, Option}; + + /// An invalid UTF8 encoding. + const EINVALID_UTF8: u64 = 1; + + /// Index out of range. + const EINVALID_INDEX: u64 = 2; + + /// A `String` holds a sequence of bytes which is guaranteed to be in utf8 format. + struct String has copy, drop, store { + bytes: vector, + } + + /// Creates a new string from a sequence of bytes. Aborts if the bytes do not represent valid utf8. + public fun utf8(bytes: vector): String { + assert!(internal_check_utf8(&bytes), Errors::invalid_state(EINVALID_UTF8)); + String{bytes} + } + + spec fun spec_utf8(bytes: vector): String { + String{bytes} + } + + /// Tries to create a new string from a sequence of bytes. + public fun try_utf8(bytes: vector): Option { + if (internal_check_utf8(&bytes)) { + Option::some(String{bytes}) + } else { + Option::none() + } + } + + /// Returns a reference to the underlying byte vector. + public fun bytes(s: &String): &vector { + &s.bytes + } + + /// Checks whether this string is empty. + public fun is_empty(s: &String): bool { + Vector::is_empty(&s.bytes) + } + + /// Returns the length of this string, in bytes. + public fun length(s: &String): u64 { + Vector::length(&s.bytes) + } + + /// Appends a string. + public fun append(s: &mut String, r: String) { + Vector::append(&mut s.bytes, *&r.bytes) + } + + /// Appends bytes which must be in valid utf8 format. + public fun append_utf8(s: &mut String, bytes: vector) { + append(s, utf8(bytes)) + } + + /// Insert the other string at the byte index in given string. The index must be at a valid utf8 char + /// boundary. + public fun insert(s: &mut String, at: u64, o: String) { + let bytes = &s.bytes; + assert!(at <= Vector::length(bytes) && internal_is_char_boundary(bytes, at), Errors::invalid_state(EINVALID_INDEX)); + let l = length(s); + let front = sub_string(s, 0, at); + let end = sub_string(s, at, l); + append(&mut front, o); + append(&mut front, end); + *s = front; + } + + /// Returns a sub-string using the given byte indices, where `i` is the first byte position and `j` is the start + /// of the first byte not included (or the length of the string). The indices must be at valid utf8 char boundaries, + /// guaranteeing that the result is valid utf8. + public fun sub_string(s: &String, i: u64, j: u64): String { + let bytes = &s.bytes; + let l = Vector::length(bytes); + assert!( + j <= l && i <= j && internal_is_char_boundary(bytes, i) && internal_is_char_boundary(bytes, j), + Errors::invalid_state(EINVALID_INDEX) + ); + String{bytes: internal_sub_string(bytes, i, j)} + } + + /// Computes the index of the first occurrence of a string. Returns `length(s)` if no occurrence found. + public fun index_of(s: &String, r: &String): u64 { + internal_index_of(&s.bytes, &r.bytes) + } + + + // Native API + native fun internal_check_utf8(v: &vector): bool; + native fun internal_is_char_boundary(v: &vector, i: u64): bool; + native fun internal_sub_string(v: &vector, i: u64, j: u64): vector; + native fun internal_index_of(v: &vector, r: &vector): u64; + + spec internal_check_utf8(v: &vector): bool { + pragma opaque; + aborts_if [abstract] false; + ensures [abstract] result == spec_internal_check_utf8(v); + } + + spec internal_is_char_boundary(v: &vector, i: u64): bool { + pragma opaque; + aborts_if [abstract] false; + ensures [abstract] result == spec_internal_is_char_boundary(v, i); + } + spec internal_sub_string(v: &vector, i: u64, j: u64): vector { + pragma opaque; + aborts_if [abstract] false; + ensures [abstract] result == spec_internal_sub_string(v, i, j); + } + spec internal_index_of(v: &vector, r: &vector): u64 { + pragma opaque; + aborts_if [abstract] false; + ensures [abstract] result == spec_internal_index_of(v, r); + } + + spec module { + fun spec_internal_check_utf8(v: vector): bool; + fun spec_internal_is_char_boundary(v: vector, i: u64): bool; + fun spec_internal_sub_string(v: vector, i: u64, j: u64): vector; + fun spec_internal_index_of(v: vector, r: vector): u64; + } +} \ No newline at end of file diff --git a/release/v13/sources/StructuredHash.move b/release/v13/sources/StructuredHash.move new file mode 100644 index 00000000..ea985cf1 --- /dev/null +++ b/release/v13/sources/StructuredHash.move @@ -0,0 +1,356 @@ +address StarcoinFramework { +module StarcoinVerifier { + use StarcoinFramework::Vector; + use StarcoinFramework::Option; + use StarcoinFramework::BCS; + use StarcoinFramework::StructuredHash; + use StarcoinFramework::Hash; + + const HASH_LEN_IN_BITS: u64 = 32 * 8; + const SPARSE_MERKLE_LEAF_NODE: vector = b"SparseMerkleLeafNode"; + const SPARSE_MERKLE_INTERNAL_NODE: vector = b"SparseMerkleInternalNode"; + const BLOB_HASH_PREFIX: vector = b"Blob"; + const DEFAULT_VALUE: vector = x""; + const ACCOUNT_STORAGE_INDEX_RESOURCE: u64 = 1; + const ERROR_ACCOUNT_STORAGE_ROOTS: u64 = 101; + const ERROR_LITERAL_HASH_WRONG_LENGTH: u64 = 102; + const SPARSE_MERKLE_PLACEHOLDER_HASH_LITERAL: vector = b"SPARSE_MERKLE_PLACEHOLDER_HASH"; + + + struct AccountState has store, drop, copy { + storage_roots: vector>>, + } + + public fun bcs_deserialize_account_state(data: &vector): AccountState { + let (vec, _) = BCS::deserialize_option_bytes_vector(data, 0); + AccountState{ + storage_roots: vec + } + } + + struct StateProof has store, drop, copy { + /** + * Account state's proof for global state root. + */ + account_proof: SparseMerkleProof, + /** + * Account state including storage roots. + */ + account_state: vector, + /** + * State's proof for account storage root. + */ + proof: SparseMerkleProof, + } + + public fun new_state_proof(account_proof: SparseMerkleProof, account_state: vector, proof: SparseMerkleProof): StateProof { + StateProof{ + account_proof, + account_state, + proof, + } + } + + struct SparseMerkleProof has store, drop, copy { + siblings: vector>, + leaf: SMTNode, + } + + public fun new_sparse_merkle_proof(siblings: vector>, leaf: SMTNode): SparseMerkleProof { + SparseMerkleProof{ + siblings, + leaf, + } + } + + struct SMTNode has store, drop, copy { + hash1: vector, + hash2: vector, + } + + public fun new_smt_node(hash1: vector, hash2: vector): SMTNode { + SMTNode{ + hash1, + hash2, + } + } + + public fun empty_smt_node(): SMTNode { + SMTNode{ + hash1: Vector::empty(), + hash2: Vector::empty(), + } + } + + public fun verify_state_proof(state_proof: &StateProof, state_root: &vector, + account_address: address, resource_struct_tag: &vector, + state: &vector): bool { + let accountState: AccountState = bcs_deserialize_account_state(&state_proof.account_state); + assert!(Vector::length(&accountState.storage_roots) > ACCOUNT_STORAGE_INDEX_RESOURCE, ERROR_ACCOUNT_STORAGE_ROOTS); + + // First, verify state for storage root. + let storageRoot = Option::borrow(Vector::borrow(&accountState.storage_roots, ACCOUNT_STORAGE_INDEX_RESOURCE)); + let ok: bool = verify_smp(&state_proof.proof.siblings, + &state_proof.proof.leaf, + storageRoot, + resource_struct_tag, // resource struct tag BCS serialized as key + state); + if (!ok) { + return false + }; + + // Then, verify account state for global state root. + ok = verify_smp(&state_proof.account_proof.siblings, + &state_proof.account_proof.leaf, + state_root, + &BCS::to_bytes
(&account_address), // account address as key + &state_proof.account_state, + ); + ok + } + + #[test] + fun test_verify_state_proof() { + // miannet, block number 6495396 + let state_root = x"d337896a5cd8bae3d0130e09409c0f5eede159d93af38a642528acb15c1204b8"; + let account_address = @0x47d36856884d7fb9e91a475ea3472341; +// let state = x""; + let state = x"00000000000000000000000000000000"; + // 0x00000000000000000000000000000001::Account::Balance<0x8c109349c6bd91411d6bc962e080c4a3::STAR::STAR> + let resource_struct_tag = x"00000000000000000000000000000001074163636f756e740742616c616e636501078c109349c6bd91411d6bc962e080c4a30453544152045354415200"; + + let account_proof_sibling_nodes = Vector::empty>(); + Vector::push_back(&mut account_proof_sibling_nodes, x"b81050a469dbe041f915cda6942143c691b1735599815142c895f77cf088a656"); + Vector::push_back(&mut account_proof_sibling_nodes, x"5350415253455f4d45524b4c455f504c414345484f4c4445525f484153480000"); + Vector::push_back(&mut account_proof_sibling_nodes, x"1c0cbf70e7474e739db9ca9958470f605f37a5a0f322c7c854b24866c4330577"); + Vector::push_back(&mut account_proof_sibling_nodes, x"68dde7ba4f4a9cf6329675e598a1ab7b545f8de36e5cb8151be8ff167e479c26"); + Vector::push_back(&mut account_proof_sibling_nodes, x"3c59423b2956d25cdacf638540e39dbc53238d36ca1420d31c4321580aeff633"); + Vector::push_back(&mut account_proof_sibling_nodes, x"5befec9a99ad40f1cb6d5b44c87ca6ad26841535cd7fac27f2f88205088b55e3"); + Vector::push_back(&mut account_proof_sibling_nodes, x"32f4d82b78b1339fb5d9c60ac2e49780c87b9e9c675bee9d1cb3ace3f34a63d6"); + Vector::push_back(&mut account_proof_sibling_nodes, x"a60429524592cac0170763196269c4997e08b6a09b2ad45647775486a81559af"); + Vector::push_back(&mut account_proof_sibling_nodes, x"6b6bc4e16bad1fbc6c6df21a923a9be06ae8508827cdd3dbdd4e0e6607abdb6d"); + Vector::push_back(&mut account_proof_sibling_nodes, x"5e6165bc60b30f46611d52f9779668e0fa79eeb60bf3a0d90346b33331156155"); + Vector::push_back(&mut account_proof_sibling_nodes, x"dfc42240b0d542457748e873e3ab0ee362c68dedd91df13532cd85a1a6ea6f00"); + Vector::push_back(&mut account_proof_sibling_nodes, x"610cba3b3c467b137ddbda0f5783ef269357ca4e30aaa2cfecb96e2ee8b2c5e7"); + Vector::push_back(&mut account_proof_sibling_nodes, x"179235bb93b8ece25921f7405a2f797f80630d90f71e763e8a700734d6945b99"); + Vector::push_back(&mut account_proof_sibling_nodes, x"85d80d435c4cb8b8034d32aff6b05230efc43b583154428a0990e1f752adcf3a"); + Vector::push_back(&mut account_proof_sibling_nodes, x"a2f4a3e6f11e6b42d700c920c06a89ffe6d086d5411aa578d56d8de000704669"); + Vector::push_back(&mut account_proof_sibling_nodes, x"ee57409d642877366ac26b2bf8948f7daae3c45a545b931b28a6d902e01bdc1f"); + + let state_proof_sibling_nodes = Vector::empty>(); + Vector::push_back(&mut state_proof_sibling_nodes, x"2a3c2096fbd5a1a2e81077e4b2156c7232b9291ad3d85ea7451eb8b7cda828fd"); + Vector::push_back(&mut state_proof_sibling_nodes, x"4cc4f038091aba95645a5b8153dc088ffdbfb7c7e82dd6b166f187b33eea7432"); + Vector::push_back(&mut state_proof_sibling_nodes, x"aa140a1627b5385e108f6580062110463d09768bce681bbb88c3d9c59680d75d"); + Vector::push_back(&mut state_proof_sibling_nodes, x"7c8f59d557168dd5667fcc950ed444cfa0cbce778e032c918a8b2a2084c48c03"); + Vector::push_back(&mut state_proof_sibling_nodes, x"a0718e77be611f67f880f5fc4d7c801940aae65890f02b38a663458ed924c2f9"); + + let proof = new_state_proof( + new_sparse_merkle_proof( + account_proof_sibling_nodes, + new_smt_node( + x"3fe0547cb3576cad025fb5cfa98b85a3545a41e5b14e844fd8cad5edaa619c05", + x"ed0e07d03371a130b84bea8245f84bf546955e5a190afc20ef34f310614c6d10", + ), + ), + x"02000120ceaafd667b54252bba61993770d87bbb997b1a689b0e08899543e3c8f82adca7", + new_sparse_merkle_proof( + state_proof_sibling_nodes, + new_smt_node( + x"1de0d92e4e770fa53ceaa12c83edb8c0e51c1d19499d769c572ffd9d38cef40f", + x"6493204f1b87055adb8937a385daa238b3c08c491026f2ac50ebe4dab9133030", + ), + ), + ); + + let b = verify_state_proof( + &proof, + &state_root, + account_address, + &resource_struct_tag, + &state, + ); + assert!(b, 1110); + } + + /// Verify sparse merkle proof by key and value. + public fun verify_smp(sibling_nodes: &vector>, leaf_data: &SMTNode, expected_root: &vector, key: &vector, value: &vector): bool { + let path = hash_key(key); + let current_hash: vector; + if (*value == DEFAULT_VALUE) { + // Non-membership proof. + if (empty_smt_node() == *leaf_data) { + current_hash = placeholder(); + } else { + if (*&leaf_data.hash1 == *&path) { + return false + }; + if (!(count_common_prefix(&leaf_data.hash1, &path) >= Vector::length(sibling_nodes))) { + return false + }; + current_hash = StructuredHash::hash(SPARSE_MERKLE_LEAF_NODE, leaf_data); + }; + } else { + // Membership proof. + if (empty_smt_node() == *leaf_data) { + return false + }; + if (*&leaf_data.hash1 != *&path) { + return false + }; + let value_hash = hash_value(value); + if (*&leaf_data.hash2 != value_hash) { + return false + }; + current_hash = StructuredHash::hash(SPARSE_MERKLE_LEAF_NODE, leaf_data); + }; + + current_hash = compute_smp_root_by_path_and_node_hash(sibling_nodes, &path, ¤t_hash); + current_hash == *expected_root + } + +// #[test] +// fun test_print_storage_root(){ +// let account_state = x"02000120ceaafd667b54252bba61993770d87bbb997b1a689b0e08899543e3c8f82adca7"; +// let accountState: AccountState = bcs_deserialize_account_state(&account_state); +// let storageRoot = Option::borrow(Vector::borrow(&accountState.storage_roots, ACCOUNT_STORAGE_INDEX_RESOURCE)); +// Debug::print(storageRoot); +// } + + #[test] + fun test_verify_smp() { + let sibling_nodes = Vector::empty>(); + Vector::push_back(&mut sibling_nodes, x"2a3c2096fbd5a1a2e81077e4b2156c7232b9291ad3d85ea7451eb8b7cda828fd"); + Vector::push_back(&mut sibling_nodes, x"4cc4f038091aba95645a5b8153dc088ffdbfb7c7e82dd6b166f187b33eea7432"); + Vector::push_back(&mut sibling_nodes, x"aa140a1627b5385e108f6580062110463d09768bce681bbb88c3d9c59680d75d"); + Vector::push_back(&mut sibling_nodes, x"7c8f59d557168dd5667fcc950ed444cfa0cbce778e032c918a8b2a2084c48c03"); + Vector::push_back(&mut sibling_nodes, x"a0718e77be611f67f880f5fc4d7c801940aae65890f02b38a663458ed924c2f9"); + + let leaf_node = new_smt_node( + x"1de0d92e4e770fa53ceaa12c83edb8c0e51c1d19499d769c572ffd9d38cef40f", + x"6493204f1b87055adb8937a385daa238b3c08c491026f2ac50ebe4dab9133030", + ); + let account_state = x"02000120ceaafd667b54252bba61993770d87bbb997b1a689b0e08899543e3c8f82adca7"; + let accountState: AccountState = bcs_deserialize_account_state(&account_state); + let expected_root = Option::borrow(Vector::borrow(&accountState.storage_roots, ACCOUNT_STORAGE_INDEX_RESOURCE)); +// let expected_root = x"0f30a41872208c6324fa842889315b14f9be6f3dd0d5050686317adfdd0cda60"; + let key = x"00000000000000000000000000000001074163636f756e740742616c616e636501078c109349c6bd91411d6bc962e080c4a30453544152045354415200"; + // Above key is this StructTag BCS serialized bytes: + let value = x"00000000000000000000000000000000"; + + let b = verify_smp(&sibling_nodes, &leaf_node, expected_root, &key, &value); + assert!(b, 1112) + } + + #[test] + fun test_verify_smp_2() { + let sibling_nodes: vector> = Vector::empty(); + let leaf_data: SMTNode = empty_smt_node(); + let expected_root: vector = placeholder(); + let key: vector = b"random key"; + let value: vector = Vector::empty(); //x"" + let b = verify_smp(&sibling_nodes, &leaf_data, &expected_root, &key, &value); + assert!(b, 1113); + + value = b"random value"; + b = verify_smp(&sibling_nodes, &leaf_data, &expected_root, &key, &value); + assert!(!b, 1114); + } + + public fun compute_smp_root_by_path_and_node_hash(sibling_nodes: &vector>, path: &vector, node_hash: &vector): vector { + let current_hash = *node_hash; + let i = 0; + let proof_length = Vector::length(sibling_nodes); + while (i < proof_length) { + let sibling = *Vector::borrow(sibling_nodes, i); + let bit = get_bit_at_from_msb(path, proof_length - i - 1); + let internal_node = if (bit) { + SMTNode{ hash1: sibling, hash2: current_hash } + } else { + SMTNode{ hash1: current_hash, hash2: sibling } + }; + current_hash = StructuredHash::hash(SPARSE_MERKLE_INTERNAL_NODE, &internal_node); + i = i + 1; + }; + current_hash + } + + public fun placeholder(): vector { + create_literal_hash(&SPARSE_MERKLE_PLACEHOLDER_HASH_LITERAL) + } + + public fun create_literal_hash(word: &vector): vector { + if (Vector::length(word) <= 32) { + let lenZero = 32 - Vector::length(word); + let i = 0; + let r = *word; + while (i < lenZero) { + Vector::push_back(&mut r, 0); + i = i + 1; + }; + return r + }; + abort ERROR_LITERAL_HASH_WRONG_LENGTH + } + + #[test] + fun test_create_literal_hash() { + let word = b"SPARSE_MERKLE_PLACEHOLDER_HASH"; + let r = create_literal_hash(&word); + assert!(r == x"5350415253455f4d45524b4c455f504c414345484f4c4445525f484153480000", 1115); + } + + fun hash_key(key: &vector): vector { + Hash::sha3_256(*key) + } + + fun hash_value(value: &vector): vector { + StructuredHash::hash(BLOB_HASH_PREFIX, value) + } + + fun count_common_prefix(data1: &vector, data2: &vector): u64 { + let count = 0; + let i = 0; + while ( i < Vector::length(data1) * 8) { + if (get_bit_at_from_msb(data1, i) == get_bit_at_from_msb(data2, i)) { + count = count + 1; + } else { + break + }; + i = i + 1; + }; + count + } + + fun get_bit_at_from_msb(data: &vector, index: u64): bool { + let pos = index / 8; + let bit = (7 - index % 8); + (*Vector::borrow(data, pos) >> (bit as u8)) & 1u8 != 0 + } + + spec get_bit_at_from_msb { + pragma verify = false; // Bitwise operator + pragma opaque; + } +} + +module StructuredHash { + use StarcoinFramework::Hash; + use StarcoinFramework::Vector; + use StarcoinFramework::BCS; + + const STARCOIN_HASH_PREFIX: vector = b"STARCOIN::"; + + public fun hash(structure: vector, data: &MoveValue): vector { + let prefix_hash = Hash::sha3_256(concat(&STARCOIN_HASH_PREFIX, structure)); + let bcs_bytes = BCS::to_bytes(data); + Hash::sha3_256(concat(&prefix_hash, bcs_bytes)) + } + + fun concat(v1: &vector, v2: vector): vector { + let data = *v1; + Vector::append(&mut data, v2); + data + } +} + +} diff --git a/release/v13/sources/Table.move b/release/v13/sources/Table.move new file mode 100644 index 00000000..8993f0c5 --- /dev/null +++ b/release/v13/sources/Table.move @@ -0,0 +1,235 @@ +address StarcoinFramework { +/// Type of large-scale storage tables. +module Table { + use StarcoinFramework::Errors; + + // native code raises this with Errors::invalid_arguments() + const EALREADY_EXISTS: u64 = 100; + // native code raises this with Errors::invalid_arguments() + const ENOT_FOUND: u64 = 101; + const ENOT_EMPTY: u64 = 102; + + /// Type of tables + struct Table has store { + handle: address, + length: u64, + } + + spec Table { + pragma intrinsic = map, + map_new = new, + map_destroy_empty = destroy_empty, + map_len = length, + map_is_empty = empty, + map_has_key = contains, + map_add_no_override = add, + map_del_must_exist = remove, + map_borrow = borrow, + map_borrow_mut = borrow_mut, + map_spec_get = spec_get, + map_spec_set = spec_set, + map_spec_del = spec_remove, + map_spec_len = spec_len, + map_spec_has_key = spec_contains; + } + + /// Create a new Table. + public fun new(): Table { + Table{ + handle: new_table_handle(), + length: 0, + } + } + + spec new { + pragma intrinsic; + } + + + /// Destroy a table. The table must be empty to succeed. + public fun destroy_empty(table: Table) { + assert!(table.length == 0, Errors::invalid_state(ENOT_EMPTY)); + destroy_empty_box>(&table); + drop_unchecked_box>(table) + } + + spec destroy_empty { + pragma intrinsic; + } + + /// Add a new entry to the table. Aborts if an entry for this + /// key already exists. The entry itself is not stored in the + /// table, and cannot be discovered from it. + public fun add(table: &mut Table, key: K, val: V) { + add_box>(table, key, Box{val}); + table.length = table.length + 1 + } + + spec add { + pragma intrinsic; + } + + /// Acquire an immutable reference to the value which `key` maps to. + /// Aborts if there is no entry for `key`. + public fun borrow(table: &Table, key: K): &V { + &borrow_box>(table, key).val + } + + spec borrow { + pragma intrinsic; + } + + /// Acquire an immutable reference to the value which `key` maps to. + /// Returns specified default value if there is no entry for `key`. + public fun borrow_with_default(table: &Table, key: K, default: &V): &V { + if (!contains(table, copy key)) { + default + } else { + borrow(table, copy key) + } + } + + /// Acquire a mutable reference to the value which `key` maps to. + /// Aborts if there is no entry for `key`. + public fun borrow_mut(table: &mut Table, key: K): &mut V { + &mut borrow_box_mut>(table, key).val + } + + spec borrow_mut { + pragma intrinsic; + } + + /// Returns the length of the table, i.e. the number of entries. + public fun length(table: &Table): u64 { + table.length + } + + spec length { + pragma intrinsic; + } + + /// Returns true if this table is empty. + public fun empty(table: &Table): bool { + table.length == 0 + } + + spec empty { + pragma intrinsic; + } + + /// Acquire a mutable reference to the value which `key` maps to. + /// Insert the pair (`key`, `default`) first if there is no entry for `key`. + public fun borrow_mut_with_default(table: &mut Table, key: K, default: V): &mut V { + if (!contains(table, copy key)) { + add(table, copy key, default) + }; + borrow_mut(table, key) + } + + spec borrow_mut_with_default { + pragma opaque, verify=false; + aborts_if false; + // TODO: Prover need to extend with supporting the `borrow_mut_with_default` pragma. + // `table.length` cannot be accessed because the struct is intrinsic. + // It seems not possible to write an abstract postcondition for this function. + } + + /// Insert the pair (`key`, `value`) if there is no entry for `key`. + /// update the value of the entry for `key` to `value` otherwise + public fun upsert(table: &mut Table, key: K, value: V) { + if (!contains(table, copy key)) { + add(table, copy key, value) + } else { + let ref = borrow_mut(table, key); + *ref = value; + }; + } + + /// Remove from `table` and return the value which `key` maps to. + /// Aborts if there is no entry for `key`. + public fun remove(table: &mut Table, key: K): V { + let Box{val} = remove_box>(table, key); + table.length = table.length - 1; + val + } + + spec remove { + pragma intrinsic; + } + + /// Returns true iff `table` contains an entry for `key`. + public fun contains(table: &Table, key: K): bool { + contains_box>(table, key) + } + + spec contains { + pragma intrinsic; + } + + #[test_only] + /// Testing only: allows to drop a table even if it is not empty. + public fun drop_unchecked(table: Table) { + drop_unchecked_box>(table) + } + + #[test_only] + struct TableHolder has key { + t: Table + } + + #[test(account = @0x1)] + fun test_upsert(account: signer) { + let t = new(); + let key: u64 = 111; + let error_code: u64 = 1; + assert!(!contains(&t, key), error_code); + upsert(&mut t, key, 12); + assert!(*borrow(&t, key) == 12, error_code); + upsert(&mut t, key, 23); + assert!(*borrow(&t, key) == 23, error_code); + + move_to(&account, TableHolder { t }); + } + + #[test(account = @0x1)] + fun test_borrow_with_default(account: signer) { + let t = new(); + let key: u64 = 100; + let error_code: u64 = 1; + assert!(!contains(&t, key), error_code); + assert!(*borrow_with_default(&t, key, &12) == 12, error_code); + add(&mut t, key, 1); + assert!(*borrow_with_default(&t, key, &12) == 1, error_code); + + move_to(&account, TableHolder{ t }); + } + + + // ====================================================================================================== + // Internal API + + /// Wrapper for values. Required for making values appear as resources in the implementation. + struct Box has key, drop, store { + val: V + } + + // Primitives which take as an additional type parameter `Box`, so the implementation + // can use this to determine serialization layout. + native fun new_table_handle(): address; + native fun add_box(table: &mut Table, key: K, val: Box); + native fun borrow_box(table: &Table, key: K): &Box; + native fun borrow_box_mut(table: &mut Table, key: K): &mut Box; + native fun contains_box(table: &Table, key: K): bool; + native fun remove_box(table: &mut Table, key: K): Box; + native fun destroy_empty_box(table: &Table); + native fun drop_unchecked_box(table: Table); + + // Specification functions for tables + + spec native fun spec_len(t: Table): num; + spec native fun spec_contains(t: Table, k: K): bool; + spec native fun spec_set(t: Table, k: K, v: V): Table; + spec native fun spec_remove(t: Table, k: K): Table; + spec native fun spec_get(t: Table, k: K): V; +} +} diff --git a/release/v13/sources/Timestamp.move b/release/v13/sources/Timestamp.move new file mode 100644 index 00000000..0dd5da96 --- /dev/null +++ b/release/v13/sources/Timestamp.move @@ -0,0 +1,131 @@ +address StarcoinFramework { +/// The module implements onchain timestamp oracle. +/// Timestamp is updated on each block. It always steps forward, and never come backward. +module Timestamp { + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + + // A singleton resource holding the current Unix time in milliseconds + struct CurrentTimeMilliseconds has key { + milliseconds: u64, + } + + /// A singleton resource used to determine whether time has started. This + /// is called at the end of genesis. + struct TimeHasStarted has key {} + + /// Conversion factor between seconds and milliseconds + const MILLI_CONVERSION_FACTOR: u64 = 1000; + + const ENOT_GENESIS: u64 = 12; + const EINVALID_TIMESTAMP: u64 = 14; + const ENOT_INITIALIZED: u64 = 101; + // Initialize the global wall clock time resource. + public fun initialize(account: &signer, genesis_timestamp: u64) { + // Only callable by the Genesis address + CoreAddresses::assert_genesis_address(account); + let milli_timer = CurrentTimeMilliseconds {milliseconds: genesis_timestamp}; + move_to(account, milli_timer); + } + spec initialize { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists(Signer::address_of(account)); + ensures exists(Signer::address_of(account)); + } + + // Update the wall clock time by consensus. Requires VM privilege and will be invoked during block prologue. + public fun update_global_time(account: &signer, timestamp: u64) acquires CurrentTimeMilliseconds { + CoreAddresses::assert_genesis_address(account); + //Do not update time before time start. + let global_milli_timer = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); + assert!(timestamp > global_milli_timer.milliseconds, Errors::invalid_argument(EINVALID_TIMESTAMP)); + global_milli_timer.milliseconds = timestamp; + } + spec update_global_time { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if timestamp <= global(CoreAddresses::GENESIS_ADDRESS()).milliseconds; + ensures global(CoreAddresses::GENESIS_ADDRESS()).milliseconds == timestamp; + } + + // Get the timestamp representing `now` in seconds. + public fun now_seconds(): u64 acquires CurrentTimeMilliseconds { + now_milliseconds() / MILLI_CONVERSION_FACTOR + } + spec now_seconds { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures result == now_milliseconds() / MILLI_CONVERSION_FACTOR; + } + spec fun spec_now_seconds(): u64 { + global(CoreAddresses::GENESIS_ADDRESS()).milliseconds / MILLI_CONVERSION_FACTOR + } + + // Get the timestamp representing `now` in milliseconds. + public fun now_milliseconds(): u64 acquires CurrentTimeMilliseconds { + borrow_global(CoreAddresses::GENESIS_ADDRESS()).milliseconds + } + + spec now_milliseconds { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + ensures result == global(CoreAddresses::GENESIS_ADDRESS()).milliseconds; + } + + spec fun spec_now_millseconds(): u64 { + global(CoreAddresses::GENESIS_ADDRESS()).milliseconds + } + + /// Marks that time has started and genesis has finished. This can only be called from genesis. + public fun set_time_has_started(account: &signer) { + CoreAddresses::assert_genesis_address(account); + + // Current time must have been initialized. + assert!( + exists(CoreAddresses::GENESIS_ADDRESS()), + Errors::invalid_state(ENOT_INITIALIZED) + ); + move_to(account, TimeHasStarted{}); + } + + spec set_time_has_started { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if !exists(Signer::address_of(account)); + aborts_if exists(Signer::address_of(account)); + ensures exists(Signer::address_of(account)); + } + + /// Helper function to determine if the blockchain is in genesis state. + public fun is_genesis(): bool { + !exists(CoreAddresses::GENESIS_ADDRESS()) + } + + spec is_genesis { + aborts_if false; + ensures result == !exists(CoreAddresses::GENESIS_ADDRESS()); + } + + /// Helper function to assert genesis state. + public fun assert_genesis() { + assert!(is_genesis(), Errors::invalid_state(ENOT_GENESIS)); + } + spec assert_genesis { + pragma opaque = true; + include AbortsIfNotGenesis; + } + + /// Helper schema to specify that a function aborts if not in genesis. + spec schema AbortsIfNotGenesis { + aborts_if !is_genesis(); + } + + spec schema AbortsIfTimestampNotExists { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } +} +} diff --git a/release/v13/sources/Token.move b/release/v13/sources/Token.move new file mode 100644 index 00000000..290b9843 --- /dev/null +++ b/release/v13/sources/Token.move @@ -0,0 +1,545 @@ +address StarcoinFramework { +/// Token implementation of Starcoin. +module Token { + use StarcoinFramework::Event; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::Math; + + friend StarcoinFramework::TypeInfo; + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// The token has a `TokenType` color that tells us what token the + /// `value` inside represents. + struct Token has store { + value: u128, + } + + /// Token Code which identify a unique Token. + struct TokenCode has copy, drop, store { + /// address who define the module contains the Token Type. + addr: address, + /// module which contains the Token Type. + module_name: vector, + /// name of the token. may nested if the token is an instantiated generic token type. + name: vector, + } + + /// A minting capability allows tokens of type `TokenType` to be minted + struct MintCapability has key, store {} + + /// A fixed time mint key which can mint token until global time > end_time + struct FixedTimeMintKey has key, store { + total: u128, + end_time: u64, + } + + /// A linear time mint key which can mint token in a period by time-based linear release. + struct LinearTimeMintKey has key, store { + total: u128, + minted: u128, + start_time: u64, + period: u64, + } + + /// A burn capability allows tokens of type `TokenType` to be burned. + struct BurnCapability has key, store {} + + + /// Event emitted when token minted. + struct MintEvent has drop, store { + /// funds added to the system + amount: u128, + /// full info of Token. + token_code: TokenCode, + } + + /// Event emitted when token burned. + struct BurnEvent has drop, store { + /// funds removed from the system + amount: u128, + /// full info of Token + token_code: TokenCode, + } + + /// Token information. + struct TokenInfo has key { + /// The total value for the token represented by + /// `TokenType`. Mutable. + total_value: u128, + /// The scaling factor for the coin (i.e. the amount to divide by + /// to get to the human-readable representation for this currency). + /// e.g. 10^6 for `Coin1` + scaling_factor: u128, + /// event stream for minting + mint_events: Event::EventHandle, + /// event stream for burning + burn_events: Event::EventHandle, + } + + const EDEPRECATED_FUNCTION: u64 = 19; + + const EDESTROY_TOKEN_NON_ZERO: u64 = 16; + const EINVALID_ARGUMENT: u64 = 18; + + /// Token register's address should same as TokenType's address. + const ETOKEN_REGISTER: u64 = 101; + + const EAMOUNT_EXCEEDS_COIN_VALUE: u64 = 102; + // Mint key time limit + const EMINT_KEY_TIME_LIMIT: u64 = 103; + + const EDESTROY_KEY_NOT_EMPTY: u64 = 104; + const EPRECISION_TOO_LARGE: u64 = 105; + const EEMPTY_KEY: u64 = 106; + const ESPLIT: u64 = 107; + const EPERIOD_NEW: u64 = 108; + const EMINT_AMOUNT_EQUAL_ZERO: u64 = 109; + + /// 2^128 < 10**39 + const MAX_PRECISION: u8 = 38; + + /// Register the type `TokenType` as a Token and got MintCapability and BurnCapability. + public fun register_token( + account: &signer, + precision: u8, + ) { + assert!(precision <= MAX_PRECISION, Errors::invalid_argument(EPRECISION_TOO_LARGE)); + let scaling_factor = Math::pow(10, (precision as u64)); + let token_address = token_address(); + assert!(Signer::address_of(account) == token_address, Errors::requires_address(ETOKEN_REGISTER)); + move_to(account, MintCapability {}); + move_to(account, BurnCapability {}); + move_to( + account, + TokenInfo { + total_value: 0, + scaling_factor, + mint_events: Event::new_event_handle(account), + burn_events: Event::new_event_handle(account), + }, + ); + } + + spec register_token { + include RegisterTokenAbortsIf; + include RegisterTokenEnsures; + } + + spec schema RegisterTokenAbortsIf { + precision: u8; + account: signer; + aborts_if precision > MAX_PRECISION; + aborts_if Signer::address_of(account) != SPEC_TOKEN_TEST_ADDRESS(); + aborts_if exists>(Signer::address_of(account)); + aborts_if exists>(Signer::address_of(account)); + aborts_if exists>(Signer::address_of(account)); + } + + spec schema RegisterTokenEnsures { + account: signer; + ensures exists>(Signer::address_of(account)); + ensures exists>(Signer::address_of(account)); + ensures exists>(Signer::address_of(account)); + } + + /// Remove mint capability from `signer`. + public fun remove_mint_capability(signer: &signer): MintCapability + acquires MintCapability { + move_from>(Signer::address_of(signer)) + } + + spec remove_mint_capability { + aborts_if !exists>(Signer::address_of(signer)); + ensures !exists>(Signer::address_of(signer)); + } + + /// Add mint capability to `signer`. + public fun add_mint_capability(signer: &signer, cap: MintCapability) { + move_to(signer, cap) + } + + spec add_mint_capability { + aborts_if exists>(Signer::address_of(signer)); + ensures exists>(Signer::address_of(signer)); + } + + /// Destroy the given mint capability. + public fun destroy_mint_capability(cap: MintCapability) { + let MintCapability {} = cap; + } + + spec destroy_mint_capability { + } + + /// remove the token burn capability from `signer`. + public fun remove_burn_capability(signer: &signer): BurnCapability + acquires BurnCapability { + move_from>(Signer::address_of(signer)) + } + + spec remove_burn_capability { + aborts_if !exists>(Signer::address_of(signer)); + ensures !exists>(Signer::address_of(signer)); + } + + /// Add token burn capability to `signer`. + public fun add_burn_capability(signer: &signer, cap: BurnCapability) { + move_to(signer, cap) + } + + spec add_burn_capability { + aborts_if exists>(Signer::address_of(signer)); + ensures exists>(Signer::address_of(signer)); + } + + /// Destroy the given burn capability. + public fun destroy_burn_capability(cap: BurnCapability) { + let BurnCapability {} = cap; + } + + spec destroy_burn_capability { + } + + /// Return `amount` tokens. + /// Fails if the sender does not have a published MintCapability. + public fun mint(account: &signer, amount: u128): Token + acquires TokenInfo, MintCapability { + mint_with_capability( + borrow_global>(Signer::address_of(account)), + amount, + ) + } + + spec mint { + aborts_if spec_abstract_total_value() + amount > MAX_U128; + aborts_if !exists>(Signer::address_of(account)); + } + + /// Mint a new Token::Token worth `amount`. + /// The caller must have a reference to a MintCapability. + /// Only the Association account can acquire such a reference, and it can do so only via + /// `borrow_sender_mint_capability` + public fun mint_with_capability( + _capability: &MintCapability, + amount: u128, + ): Token acquires TokenInfo { + do_mint(amount) + } + + spec mint_with_capability { + aborts_if spec_abstract_total_value() + amount > MAX_U128; + ensures spec_abstract_total_value() == + old(global>(SPEC_TOKEN_TEST_ADDRESS()).total_value) + amount; + } + + fun do_mint(amount: u128): Token acquires TokenInfo { + // update market cap resource to reflect minting + let (token_address, module_name, token_name) = name_of_token(); + let info = borrow_global_mut>(token_address); + info.total_value = info.total_value + amount; + Event::emit_event( + &mut info.mint_events, + MintEvent { + amount, + token_code: TokenCode { addr: token_address, module_name, name: token_name }, + }, + ); + Token { value: amount } + } + + spec do_mint { + aborts_if !exists>(SPEC_TOKEN_TEST_ADDRESS()); + aborts_if spec_abstract_total_value() + amount > MAX_U128; + } + + /// Deprecated since @v3 + /// Issue a `FixedTimeMintKey` with given `MintCapability`. + public fun issue_fixed_mint_key( + _capability: &MintCapability, + _amount: u128, + _period: u64, + ): FixedTimeMintKey { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + spec issue_fixed_mint_key { + aborts_if true; + } + + /// Deprecated since @v3 + /// Issue a `LinearTimeMintKey` with given `MintCapability`. + public fun issue_linear_mint_key( + _capability: &MintCapability, + _amount: u128, + _period: u64, + ): LinearTimeMintKey { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + spec issue_linear_mint_key { + aborts_if true; + } + + /// Destroy `LinearTimeMintKey`, for deprecated + public fun destroy_linear_time_key(key: LinearTimeMintKey): (u128, u128, u64, u64) { + let LinearTimeMintKey { total, minted, start_time, period } = key; + (total, minted, start_time, period) + } + + public fun read_linear_time_key(key: &LinearTimeMintKey): (u128, u128, u64, u64) { + (key.total, key.minted, key.start_time, key.period) + } + + /// Burn some tokens of `signer`. + public fun burn(account: &signer, tokens: Token) + acquires TokenInfo, BurnCapability { + burn_with_capability( + borrow_global>(Signer::address_of(account)), + tokens, + ) + } + + spec burn { + aborts_if spec_abstract_total_value() - tokens.value < 0; + aborts_if !exists>(Signer::address_of(account)); + } + + /// Burn tokens with the given `BurnCapability`. + public fun burn_with_capability( + _capability: &BurnCapability, + tokens: Token, + ) acquires TokenInfo { + let (token_address, module_name, token_name) = name_of_token(); + let info = borrow_global_mut>(token_address); + let Token { value } = tokens; + info.total_value = info.total_value - value; + Event::emit_event( + &mut info.burn_events, + BurnEvent { + amount: value, + token_code: TokenCode { addr: token_address, module_name, name: token_name }, + }, + ); + } + + spec burn_with_capability { + aborts_if spec_abstract_total_value() - tokens.value < 0; + ensures spec_abstract_total_value() == + old(global>(SPEC_TOKEN_TEST_ADDRESS()).total_value) - tokens.value; + } + + /// Create a new Token::Token with a value of 0 + public fun zero(): Token { + Token { value: 0 } + } + + spec zero { + ensures result.value == 0; + } + + + /// Public accessor for the value of a token + public fun value(token: &Token): u128 { + token.value + } + + spec value { + aborts_if false; + ensures result == token.value; + } + + /// Splits the given token into two and returns them both + public fun split( + token: Token, + value: u128, + ): (Token, Token) { + let rest = withdraw(&mut token, value); + (token, rest) + } + + spec split { + aborts_if token.value < value; + // N.B. spec translator regards `token` as a pure expression + ensures token.value == result_1.value + result_2.value; + } + + /// "Divides" the given token into two, where the original token is modified in place. + /// The original token will have value = original value - `value` + /// The new token will have a value = `value` + /// Fails if the tokens value is less than `value` + public fun withdraw( + token: &mut Token, + value: u128, + ): Token { + // Check that `value` is less than the token's value + assert!(token.value >= value, Errors::limit_exceeded(EAMOUNT_EXCEEDS_COIN_VALUE)); + token.value = token.value - value; + Token { value: value } + } + + spec withdraw { + aborts_if token.value < value; + ensures result.value == value; + ensures token.value == old(token).value - value; + } + + /// Merges two tokens of the same token and returns a new token whose + /// value is equal to the sum of the two inputs + public fun join( + token1: Token, + token2: Token, + ): Token { + deposit(&mut token1, token2); + token1 + } + + spec join { + aborts_if token1.value + token2.value > max_u128(); + ensures token1.value + token2.value == result.value; + } + + /// "Merges" the two tokens + /// The token passed in by reference will have a value equal to the sum of the two tokens + /// The `check` token is consumed in the process + public fun deposit(token: &mut Token, check: Token) { + let Token { value } = check; + token.value = token.value + value; + } + + spec deposit { + aborts_if token.value + check.value > max_u128(); + ensures old(token).value + check.value == token.value; + } + + /// Destroy a token + /// Fails if the value is non-zero + /// The amount of Token in the system is a tightly controlled property, + /// so you cannot "burn" any non-zero amount of Token + public fun destroy_zero(token: Token) { + let Token { value } = token; + assert!(value == 0, Errors::invalid_state(EDESTROY_TOKEN_NON_ZERO)) + } + + spec destroy_zero { + aborts_if token.value > 0; + } + + /// Returns the scaling_factor for the `TokenType` token. + public fun scaling_factor(): u128 acquires TokenInfo { + let token_address = token_address(); + borrow_global>(token_address).scaling_factor + } + + spec scaling_factor { + aborts_if false; + ensures result == global>(SPEC_TOKEN_TEST_ADDRESS()).scaling_factor; + } + + /// Return the total amount of token of type `TokenType`. + public fun market_cap(): u128 acquires TokenInfo { + let token_address = token_address(); + borrow_global>(token_address).total_value + } + + spec market_cap { + aborts_if false; + ensures result == global>(SPEC_TOKEN_TEST_ADDRESS()).total_value; + } + + /// Return true if the type `TokenType` is a registered in `token_address`. + public fun is_registered_in(token_address: address): bool { + exists>(token_address) + } + + spec is_registered_in { + aborts_if false; + ensures result == exists>(token_address); + } + + /// Return true if the type `TokenType1` is same with `TokenType2` + public fun is_same_token(): bool { + return token_code() == token_code() + } + + spec is_same_token { + aborts_if false; + } + + /// Return the TokenType's address + public fun token_address(): address { + let (addr, _, _) = name_of(); + addr + } + + // The specification of this function is abstracted to avoid the complexity to + // return a real address to caller + spec token_address { + pragma opaque = true; + aborts_if false; + ensures [abstract] exists>(result); + ensures [abstract] result == SPEC_TOKEN_TEST_ADDRESS(); + ensures [abstract] global>(result).total_value == 100000000u128; + } + + /// Return the token code for the registered token. + public fun token_code(): TokenCode { + let (addr, module_name, name) = name_of(); + TokenCode { + addr, + module_name, + name + } + } + + spec token_code { + pragma opaque = true; + aborts_if false; + // ensures [abstract] result == spec_token_code(); + } + + /// We use an uninterpreted function to represent the result of derived address. The actual value + /// does not matter for the verification of callers. + spec fun spec_token_code(): TokenCode; + + public (friend) fun type_of(): (address, vector, vector){ + name_of() + } + + /// Return Token's module address, module name, and type name of `TokenType`. + native fun name_of(): (address, vector, vector); + + spec name_of { + pragma opaque = true; + aborts_if false; + } + + fun name_of_token(): (address, vector, vector) { + name_of() + } + + // The specification of this function is abstracted to avoid the complexity to + // return a real address to caller + spec name_of_token { + pragma opaque = true; + aborts_if false; + ensures [abstract] exists>(result_1); + ensures [abstract] result_1 == SPEC_TOKEN_TEST_ADDRESS(); + ensures [abstract] global>(result_1).total_value == 100000000u128; + } + + + spec fun SPEC_TOKEN_TEST_ADDRESS(): address { + @0x2 + } + + spec fun spec_abstract_total_value(): num { + global>(SPEC_TOKEN_TEST_ADDRESS()).total_value + } + + +} +} \ No newline at end of file diff --git a/release/v13/sources/TransactionFee.move b/release/v13/sources/TransactionFee.move new file mode 100644 index 00000000..47a2fb5c --- /dev/null +++ b/release/v13/sources/TransactionFee.move @@ -0,0 +1,95 @@ +address StarcoinFramework { +/// `TransactionFee` collect gas fees used by transactions in blocks temporarily. +/// Then they are distributed in `TransactionManager`. +module TransactionFee { + use StarcoinFramework::Token::{Self, Token}; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Signer; + use StarcoinFramework::STC::{STC}; + use StarcoinFramework::Timestamp; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// The `TransactionFee` resource holds a preburn resource for each + /// fiat `TokenType` that can be collected as a transaction fee. + struct TransactionFee has key { + fee: Token, + } + + /// Called in genesis. Sets up the needed resources to collect transaction fees from the + /// `TransactionFee` resource with the TreasuryCompliance account. + public fun initialize( + account: &signer, + ) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + + // accept fees in all the currencies + add_txn_fee_token(account); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists>(Signer::address_of(account)); + } + + /// publishing a wrapper of the `Preburn` resource under `fee_account` + fun add_txn_fee_token( + account: &signer, + ) { + move_to( + account, + TransactionFee { + fee: Token::zero(), + } + ) + } + + spec add_txn_fee_token { + aborts_if exists>(Signer::address_of(account)); + } + + /// Deposit `token` into the transaction fees bucket + public fun pay_fee(token: Token) acquires TransactionFee { + let txn_fees = borrow_global_mut>( + CoreAddresses::GENESIS_ADDRESS() + ); + Token::deposit(&mut txn_fees.fee, token) + } + + spec pay_fee { + aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + aborts_if global>(CoreAddresses::GENESIS_ADDRESS()).fee.value + token.value > max_u128(); + } + + /// Distribute the transaction fees collected in the `TokenType` token. + /// If the `TokenType` is STC, it unpacks the token and preburns the + /// underlying fiat. + public fun distribute_transaction_fees( + account: &signer, + ): Token acquires TransactionFee { + let fee_address = CoreAddresses::GENESIS_ADDRESS(); + CoreAddresses::assert_genesis_address(account); + + // extract fees + let txn_fees = borrow_global_mut>(fee_address); + let value = Token::value(&txn_fees.fee); + if (value > 0) { + Token::withdraw(&mut txn_fees.fee, value) + }else { + Token::zero() + } + } + + spec distribute_transaction_fees { + pragma verify = false; +// aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); +// aborts_if !exists>(CoreAddresses::GENESIS_ADDRESS()); + + } + } +} diff --git a/release/v13/sources/TransactionManager.move b/release/v13/sources/TransactionManager.move new file mode 100644 index 00000000..a26498c4 --- /dev/null +++ b/release/v13/sources/TransactionManager.move @@ -0,0 +1,395 @@ +address StarcoinFramework { +/// `TransactionManager` manages: +/// 1. prologue and epilogue of transactions. +/// 2. prologue of blocks. +module TransactionManager { + use StarcoinFramework::Option; + 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; + use StarcoinFramework::Account; + use StarcoinFramework::PackageTxnManager; + use StarcoinFramework::BlockReward; + use StarcoinFramework::Block; + use StarcoinFramework::STC::{STC, is_stc}; + use StarcoinFramework::TransactionFee; + use StarcoinFramework::Timestamp; + use StarcoinFramework::ChainId; + use StarcoinFramework::Errors; + use StarcoinFramework::TransactionPublishOption; + 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; + } + + const TXN_PAYLOAD_TYPE_SCRIPT: u8 = 0; + const TXN_PAYLOAD_TYPE_PACKAGE: u8 = 1; + const TXN_PAYLOAD_TYPE_SCRIPT_FUNCTION: u8 = 2; + + const EPROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0; + const EPROLOGUE_TRANSACTION_EXPIRED: u64 = 5; + const EPROLOGUE_BAD_CHAIN_ID: u64 = 6; + const EPROLOGUE_MODULE_NOT_ALLOWED: u64 = 7; + const EPROLOGUE_SCRIPT_NOT_ALLOWED: u64 = 8; + + + /// The prologue is invoked at the beginning of every transaction + /// It verifies: + /// - The account's auth key matches the transaction's public key + /// - That the account has enough balance to pay for all of the gas + /// - That the sequence number matches the transaction's sequence key + public fun prologue( + account: signer, + txn_sender: address, + txn_sequence_number: u64, + txn_authentication_key_preimage: vector, + txn_gas_price: u64, + txn_max_gas_units: u64, + txn_expiration_time: u64, + chain_id: u8, + txn_payload_type: u8, + txn_script_or_package_hash: vector, + txn_package_address: address, + ) { + // Can only be invoked by genesis account + assert!( + Signer::address_of(&account) == CoreAddresses::GENESIS_ADDRESS(), + Errors::requires_address(EPROLOGUE_ACCOUNT_DOES_NOT_EXIST), + ); + // 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)); + 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), + Errors::invalid_argument(EPROLOGUE_TRANSACTION_EXPIRED), + ); + if (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE) { + // stdlib upgrade is not affected by PublishOption + if (txn_package_address != CoreAddresses::GENESIS_ADDRESS()) { + assert!( + TransactionPublishOption::is_module_allowed(Signer::address_of(&account)), + Errors::invalid_argument(EPROLOGUE_MODULE_NOT_ALLOWED), + ); + }; + PackageTxnManager::package_txn_prologue_v2( + &account, + txn_sender, + txn_package_address, + txn_script_or_package_hash, + ); + } else if (txn_payload_type == TXN_PAYLOAD_TYPE_SCRIPT) { + assert!( + TransactionPublishOption::is_script_allowed( + Signer::address_of(&account), + ), + Errors::invalid_argument(EPROLOGUE_SCRIPT_NOT_ALLOWED), + ); + }; + // do nothing for TXN_PAYLOAD_TYPE_SCRIPT_FUNCTION + } + + spec prologue { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if ChainId::get() != chain_id; + aborts_if !exists(txn_sender); + aborts_if Hash::sha3_256(txn_authentication_key_preimage) != global(txn_sender).authentication_key; + aborts_if txn_gas_price * txn_max_gas_units > max_u64(); + 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 && 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; + include TransactionTimeout::AbortsIfTimestampNotValid; + aborts_if !TransactionTimeout::spec_is_valid_transaction_timestamp(txn_expiration_time); + include TransactionPublishOption::AbortsIfTxnPublishOptionNotExistWithBool { + is_script_or_package: (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE || txn_payload_type == TXN_PAYLOAD_TYPE_SCRIPT), + }; + aborts_if txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE && txn_package_address != CoreAddresses::GENESIS_ADDRESS() && !TransactionPublishOption::spec_is_module_allowed(Signer::address_of(account)); + aborts_if txn_payload_type == TXN_PAYLOAD_TYPE_SCRIPT && !TransactionPublishOption::spec_is_script_allowed(Signer::address_of(account)); + include PackageTxnManager::CheckPackageTxnAbortsIfWithType{is_package: (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE), sender:txn_sender, package_address: txn_package_address, package_hash: txn_script_or_package_hash}; + } + + /// The epilogue is invoked at the end of transactions. + /// It collects gas and bumps the sequence number + public fun epilogue( + account: signer, + txn_sender: address, + txn_sequence_number: u64, + txn_gas_price: u64, + txn_max_gas_units: u64, + gas_units_remaining: u64, + txn_payload_type: u8, + _txn_script_or_package_hash: vector, + txn_package_address: address, + // txn execute success or fail. + success: bool, + ) { + epilogue_v2(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining, txn_payload_type, _txn_script_or_package_hash, txn_package_address, success) + } + + /// The epilogue is invoked at the end of transactions. + /// It collects gas and bumps the sequence number + public fun epilogue_v2( + 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, + txn_payload_type: u8, + _txn_script_or_package_hash: vector, + txn_package_address: address, + // txn execute success or fail. + success: bool, + ) { + CoreAddresses::assert_genesis_address(&account); + 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, + txn_authentication_key_preimage, + 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( + &account, + txn_sender, + txn_package_address, + success, + ); + } + } + + spec epilogue { + pragma verify = false;//fixme : timeout + include CoreAddresses::AbortsIfNotGenesisAddress; + 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; + aborts_if txn_sequence_number + 1 > max_u64(); + aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > max_u64(); + include PackageTxnManager::AbortsIfPackageTxnEpilogue { + is_package: (txn_payload_type == TXN_PAYLOAD_TYPE_PACKAGE), + package_address: txn_package_address, + success: success, + }; + } + + /// Set the metadata for the current block and distribute transaction fees and block rewards. + /// The runtime always runs this before executing the transactions in a block. + public fun block_prologue( + account: signer, + parent_hash: vector, + timestamp: u64, + author: address, + auth_key_vec: vector, + uncles: u64, + number: u64, + chain_id: u8, + parent_gas_used: u64, + parents_hash: Option::Option>, + ) { + // Can only be invoked by genesis account + CoreAddresses::assert_genesis_address(&account); + // 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)); + + // deal with previous block first. + let txn_fee = TransactionFee::distribute_transaction_fees(&account); + + // then deal with current block. + Timestamp::update_global_time(&account, timestamp); + Block::process_block_metadata( + &account, + parent_hash, + author, + timestamp, + uncles, + number, + parents_hash, + ); + let reward = Epoch::adjust_epoch(&account, number, timestamp, uncles, parent_gas_used); + // pass in previous block gas fees. + BlockReward::process_block_reward(&account, number, reward, author, auth_key_vec, txn_fee); + } + + 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 EDEPRECATED_FUNCTION: u64 = 19; + 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; + } +} +} diff --git a/release/v13/sources/TransactionPublishOption.move b/release/v13/sources/TransactionPublishOption.move new file mode 100644 index 00000000..285f55ec --- /dev/null +++ b/release/v13/sources/TransactionPublishOption.move @@ -0,0 +1,120 @@ +address StarcoinFramework { +/// `TransactionPublishOption` provide an option to limit: +/// - whether user can use script or publish custom modules on chain. +module TransactionPublishOption { + use StarcoinFramework::Config; + use StarcoinFramework::Timestamp; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Errors; + use StarcoinFramework::Signer; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_strict = true; + + } + spec fun spec_is_script_allowed(addr: address) : bool{ + let publish_option = Config::get_by_address(addr); + publish_option.script_allowed + } + + spec fun spec_is_module_allowed(addr: address) : bool{ + let publish_option = Config::get_by_address(addr); + publish_option.module_publishing_allowed + } + + const SCRIPT_HASH_LENGTH: u64 = 32; + + const EPROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0; + const EINVALID_ARGUMENT: u64 = 18; + /// The script hash has an invalid length + const EINVALID_SCRIPT_HASH: u64 = 1001; + /// The script hash already exists in the allowlist + const EALLOWLIST_ALREADY_CONTAINS_SCRIPT: u64 = 1002; + + /// Defines and holds the publishing policies for the VM. There are three possible configurations: + /// 1. !script_allowed && !module_publishing_allowed No module publishing, only script function in module are allowed. + /// 2. script_allowed && !module_publishing_allowed No module publishing, custom scripts are allowed. + /// 3. script_allowed && module_publishing_allowed Both module publishing and custom scripts are allowed. + /// We represent these as the following resource. + struct TransactionPublishOption has copy, drop, store { + // Anyone can use script if this flag is set to true. + script_allowed: bool, + // Anyone can publish new module if this flag is set to true. + module_publishing_allowed: bool, + } + + /// Module initialization. + public fun initialize( + account: &signer, + script_allowed: bool, + module_publishing_allowed: bool, + ) { + Timestamp::assert_genesis(); + assert!( + Signer::address_of(account) == CoreAddresses::GENESIS_ADDRESS(), + Errors::requires_address(EPROLOGUE_ACCOUNT_DOES_NOT_EXIST), + ); + let transaction_publish_option = Self::new_transaction_publish_option(script_allowed, module_publishing_allowed); + Config::publish_new_config( + account, + transaction_publish_option, + ); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + include Config::PublishNewConfigAbortsIf; + include Config::PublishNewConfigEnsures; + } + + /// Create a new option. Mainly used in DAO. + public fun new_transaction_publish_option( + script_allowed: bool, + module_publishing_allowed: bool, + ): TransactionPublishOption { + TransactionPublishOption { script_allowed, module_publishing_allowed } + } + + spec new_transaction_publish_option { + aborts_if false; + } + + /// Check if sender can execute script with + public fun is_script_allowed(account: address): bool { + let publish_option = Config::get_by_address(account); + publish_option.script_allowed + } + + spec is_script_allowed { + include Config::AbortsIfConfigNotExist{ + addr: account + }; + } + + /// Check if a sender can publish a module + public fun is_module_allowed(account: address): bool { + let publish_option = Config::get_by_address(account); + publish_option.module_publishing_allowed + } + + spec is_module_allowed { + include Config::AbortsIfConfigNotExist{ + addr: account + }; + } + + spec schema AbortsIfTxnPublishOptionNotExist { + include Config::AbortsIfConfigNotExist{ + addr: CoreAddresses::GENESIS_ADDRESS() + }; + } + + spec schema AbortsIfTxnPublishOptionNotExistWithBool { + is_script_or_package : bool; + aborts_if is_script_or_package && !exists>(CoreAddresses::GENESIS_ADDRESS()); + } + +} +} \ No newline at end of file diff --git a/release/v13/sources/TransactionTimeout.move b/release/v13/sources/TransactionTimeout.move new file mode 100644 index 00000000..0f8e55e5 --- /dev/null +++ b/release/v13/sources/TransactionTimeout.move @@ -0,0 +1,53 @@ +address StarcoinFramework { +/// A module used to check expiration time of transactions. +module TransactionTimeout { + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Block; + use StarcoinFramework::TransactionTimeoutConfig; + use StarcoinFramework::Config; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + + } + + spec fun spec_is_valid_transaction_timestamp(txn_timestamp: u64):bool { + if (Block::get_current_block_number() == 0) { + txn_timestamp > Timestamp::now_seconds() + } else { + Timestamp::now_seconds() < txn_timestamp && txn_timestamp < + (Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds()) + } + } + + /// Check whether the given timestamp is valid for transactions. + public fun is_valid_transaction_timestamp(txn_timestamp: u64): bool { + let current_block_time = Timestamp::now_seconds(); + let block_number = Block::get_current_block_number(); + // before first block, just require txn_timestamp > genesis timestamp. + if (block_number == 0) { + return txn_timestamp > current_block_time + }; + let timeout = TransactionTimeoutConfig::duration_seconds(); + let max_txn_time = current_block_time + timeout; + current_block_time < txn_timestamp && txn_timestamp < max_txn_time + } + spec is_valid_transaction_timestamp { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + include Timestamp::AbortsIfTimestampNotExists; + aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64(); + aborts_if Block::get_current_block_number() != 0 && !exists>(CoreAddresses::GENESIS_ADDRESS()); + } + + spec schema AbortsIfTimestampNotValid { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + include Timestamp::AbortsIfTimestampNotExists; + aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64(); + aborts_if Block::get_current_block_number() != 0 && !exists>(CoreAddresses::GENESIS_ADDRESS()); + } +} +} diff --git a/release/v13/sources/TransactionTimeoutConfig.move b/release/v13/sources/TransactionTimeoutConfig.move new file mode 100644 index 00000000..57ddf4b0 --- /dev/null +++ b/release/v13/sources/TransactionTimeoutConfig.move @@ -0,0 +1,76 @@ +address StarcoinFramework { +/// Onchain configuration for timeout setting of transaction. +module TransactionTimeoutConfig { + use StarcoinFramework::Timestamp; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Config; + use StarcoinFramework::Signer; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict = true; + } + + /// config structs. + struct TransactionTimeoutConfig has copy, drop, store { + /// timeout in second. + duration_seconds: u64, + } + + /// Initialize function. Should only be called in genesis. + public fun initialize(account: &signer, duration_seconds: u64) { + Timestamp::assert_genesis(); + CoreAddresses::assert_genesis_address(account); + + Config::publish_new_config( + account, + new_transaction_timeout_config(duration_seconds) + ); + } + + spec initialize { + aborts_if !Timestamp::is_genesis(); + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + include Config::PublishNewConfigAbortsIf; + include Config::PublishNewConfigEnsures; + } + + /// Create a new timeout config used in dao proposal. + public fun new_transaction_timeout_config(duration_seconds: u64) : TransactionTimeoutConfig { + TransactionTimeoutConfig {duration_seconds: duration_seconds} + } + + spec new_transaction_timeout_config { + aborts_if false; + } + + /// Get current timeout config. + public fun get_transaction_timeout_config(): TransactionTimeoutConfig { + Config::get_by_address(CoreAddresses::GENESIS_ADDRESS()) + } + + spec get_transaction_timeout_config { + include Config::AbortsIfConfigNotExist{ + addr: CoreAddresses::GENESIS_ADDRESS() + }; + } + + /// Get current txn timeout in seconds. + public fun duration_seconds() :u64 { + let config = get_transaction_timeout_config(); + config.duration_seconds + } + + spec duration_seconds { + include Config::AbortsIfConfigNotExist{ + addr: CoreAddresses::GENESIS_ADDRESS() + }; + } + + spec schema AbortsIfTxnTimeoutConfigNotExist { + include Config::AbortsIfConfigNotExist{ + addr: CoreAddresses::GENESIS_ADDRESS() + }; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/TransferScripts.move b/release/v13/sources/TransferScripts.move new file mode 100644 index 00000000..2c6c15ab --- /dev/null +++ b/release/v13/sources/TransferScripts.move @@ -0,0 +1,69 @@ +address StarcoinFramework { + +module TransferScripts { + use StarcoinFramework::Account; + use StarcoinFramework::Errors; + use StarcoinFramework::Vector; + const EADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 101; + const ELENGTH_MISMATCH: u64 = 102; + const EDEPRECATED_FUNCTION: u64 = 19; + + public entry fun peer_to_peer(account: signer, payee: address, _payee_auth_key: vector, amount: u128) { + peer_to_peer_v2(account, payee, amount) + } + + public entry fun peer_to_peer_v2(account: signer, payee: address, amount: u128) { + if (!Account::exists_at(payee)) { + Account::create_account_with_address(payee); + }; + Account::pay_from(&account, payee, amount) + } + + /// Batch transfer token to others. + public entry fun batch_peer_to_peer(account: signer, payeees: vector
, _payee_auth_keys: vector>, amounts: vector) { + batch_peer_to_peer_v2(account, payeees, amounts) + } + + /// Batch transfer token to others. + public entry fun batch_peer_to_peer_v2(account: signer, payeees: vector
, amounts: vector) { + let len = Vector::length(&payeees); + assert!(len == Vector::length(&amounts), ELENGTH_MISMATCH); + let i = 0; + while (i < len){ + let payee = *Vector::borrow(&payeees, i); + if (!Account::exists_at(payee)) { + Account::create_account_with_address(payee); + }; + let amount = *Vector::borrow(&amounts, i); + Account::pay_from(&account, payee, amount); + i = i + 1; + } + } + + public entry fun peer_to_peer_batch(_account: signer, _payeees: vector, _payee_auth_keys: vector, _amount: u128) { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + public entry fun peer_to_peer_with_metadata( + account: signer, + payee: address, + _payee_auth_key: vector, + amount: u128, + metadata: vector, + ) { + peer_to_peer_with_metadata_v2(account, payee, amount, metadata) + } + + public entry fun peer_to_peer_with_metadata_v2( + account: signer, + payee: address, + amount: u128, + metadata: vector, + ) { + if (!Account::exists_at(payee)) { + Account::create_account_with_address(payee); + }; + Account::pay_from_with_metadata(&account,payee, amount, metadata) + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Treasury.move b/release/v13/sources/Treasury.move new file mode 100644 index 00000000..f2ca3e3e --- /dev/null +++ b/release/v13/sources/Treasury.move @@ -0,0 +1,388 @@ +address StarcoinFramework { +/// The module for the Treasury of DAO, which can hold the token of DAO. +module Treasury { + use StarcoinFramework::Event; + use StarcoinFramework::Signer; + use StarcoinFramework::Errors; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Math; + use StarcoinFramework::Token::{Self, Token}; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + struct Treasury has store, key { + balance: Token, + /// event handle for treasury withdraw event + withdraw_events: Event::EventHandle, + /// event handle for treasury deposit event + deposit_events: Event::EventHandle, + } + + spec Treasury { + // invariant [abstract] balance.value <= Token::spec_abstract_total_value(); + } + + /// A withdraw capability allows tokens of type `TokenT` to be withdraw from Treasury. + struct WithdrawCapability has key, store {} + + /// A linear time withdraw capability which can withdraw token from Treasury in a period by time-based linear release. + struct LinearWithdrawCapability has key, store { + /// The total amount of tokens that can be withdrawn by this capability + total: u128, + /// The amount of tokens that have been withdrawn by this capability + withdraw: u128, + /// The time-based linear release start time, timestamp in seconds. + start_time: u64, + /// The time-based linear release period in seconds + period: u64, + } + + /// Message for treasury withdraw event. + struct WithdrawEvent has drop, store { + amount: u128, + } + /// Message for treasury deposit event. + struct DepositEvent has drop, store { + amount: u128, + } + + const ERR_INVALID_PERIOD: u64 = 101; + const ERR_ZERO_AMOUNT: u64 = 102; + const ERR_TOO_BIG_AMOUNT: u64 = 103; + const ERR_NOT_AUTHORIZED: u64 = 104; + const ERR_TREASURY_NOT_EXIST: u64 = 105; + + + /// Init a Treasury for TokenT. Can only be called by token issuer. + public fun initialize(signer: &signer, init_token: Token): WithdrawCapability { + let token_issuer = Token::token_address(); + assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + let treasure = Treasury { + balance: init_token, + withdraw_events: Event::new_event_handle(signer), + deposit_events: Event::new_event_handle(signer), + }; + move_to(signer, treasure); + WithdrawCapability{} + } + + spec initialize { + aborts_if Signer::address_of(signer) != Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + ensures exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + ensures result == WithdrawCapability{}; + } + + /// Check the Treasury of TokenT is exists. + public fun exists_at(): bool { + let token_issuer = Token::token_address(); + exists>(token_issuer) + } + + spec exists_at { + aborts_if false; + ensures result == exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + } + + /// Get the balance of TokenT's Treasury + /// if the Treasury do not exists, return 0. + public fun balance(): u128 acquires Treasury { + let token_issuer = Token::token_address(); + if (!exists>(token_issuer)) { + return 0 + }; + let treasury = borrow_global>(token_issuer); + Token::value(&treasury.balance) + } + + spec balance { + aborts_if false; + ensures if (exists>(Token::SPEC_TOKEN_TEST_ADDRESS())) + result == spec_balance() + else + result == 0; + } + + public fun deposit(token: Token) acquires Treasury { + assert!(exists_at(), Errors::not_published(ERR_TREASURY_NOT_EXIST)); + let token_address = Token::token_address(); + let treasury = borrow_global_mut>(token_address); + let amount = Token::value(&token); + Event::emit_event( + &mut treasury.deposit_events, + DepositEvent { amount }, + ); + Token::deposit(&mut treasury.balance, token); + } + + spec deposit { + aborts_if !exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + aborts_if spec_balance() + token.value > MAX_U128; + ensures spec_balance() == old(spec_balance()) + token.value; + } + + fun do_withdraw(amount: u128): Token acquires Treasury { + assert!(amount > 0, Errors::invalid_argument(ERR_ZERO_AMOUNT)); + assert!(exists_at(), Errors::not_published(ERR_TREASURY_NOT_EXIST)); + let token_address = Token::token_address(); + let treasury = borrow_global_mut>(token_address); + assert!(amount <= Token::value(&treasury.balance) , Errors::invalid_argument(ERR_TOO_BIG_AMOUNT)); + Event::emit_event( + &mut treasury.withdraw_events, + WithdrawEvent { amount }, + ); + Token::withdraw(&mut treasury.balance, amount) + } + + spec do_withdraw { + include WithdrawSchema; + } + + spec schema WithdrawSchema { + amount: u64; + + aborts_if amount <= 0; + aborts_if !exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + aborts_if spec_balance() < amount; + ensures spec_balance() == + old(spec_balance()) - amount; + } + + /// Withdraw tokens with given `LinearWithdrawCapability`. + public fun withdraw_with_capability( + _cap: &mut WithdrawCapability, + amount: u128, + ): Token acquires Treasury { + do_withdraw(amount) + } + + spec withdraw_with_capability { + include WithdrawSchema; + } + + /// Withdraw from TokenT's treasury, the signer must have WithdrawCapability + public fun withdraw( + signer: &signer, + amount: u128 + ): Token acquires Treasury, WithdrawCapability { + let cap = borrow_global_mut>(Signer::address_of(signer)); + Self::withdraw_with_capability(cap, amount) + } + + spec withdraw { + aborts_if !exists>(Signer::address_of(signer)); + include WithdrawSchema; + } + + /// Issue a `LinearWithdrawCapability` with given `WithdrawCapability`. + public fun issue_linear_withdraw_capability( + _capability: &mut WithdrawCapability, + amount: u128, + period: u64 + ): LinearWithdrawCapability { + assert!(period > 0, Errors::invalid_argument(ERR_INVALID_PERIOD)); + assert!(amount > 0, Errors::invalid_argument(ERR_ZERO_AMOUNT)); + let start_time = Timestamp::now_seconds(); + LinearWithdrawCapability { + total: amount, + withdraw: 0, + start_time, + period, + } + } + + spec issue_linear_withdraw_capability { + aborts_if period == 0; + aborts_if amount == 0; + aborts_if !exists(StarcoinFramework::CoreAddresses::GENESIS_ADDRESS()); + } + + /// Withdraw tokens with given `LinearWithdrawCapability`. + public fun withdraw_with_linear_capability( + cap: &mut LinearWithdrawCapability, + ): Token acquires Treasury { + let amount = withdraw_amount_of_linear_cap(cap); + let token = do_withdraw(amount); + cap.withdraw = cap.withdraw + amount; + token + } + + spec withdraw_with_linear_capability { + pragma aborts_if_is_partial; + // TODO: See [MUL_DIV] + // include WithdrawSchema {amount: ?}; + } + + /// Withdraw from TokenT's treasury, the signer must have LinearWithdrawCapability + public fun withdraw_by_linear( + signer: &signer, + ): Token acquires Treasury, LinearWithdrawCapability { + let cap = borrow_global_mut>(Signer::address_of(signer)); + Self::withdraw_with_linear_capability(cap) + } + + spec withdraw_by_linear { + pragma aborts_if_is_partial; + aborts_if !exists>(Signer::address_of(signer)); + // TODO: See [MUL_DIV] + // include WithdrawSchema {amount: ?}; + } + + /// Split the given `LinearWithdrawCapability`. + public fun split_linear_withdraw_cap( + cap: &mut LinearWithdrawCapability, + amount: u128, + ): (Token, LinearWithdrawCapability) acquires Treasury { + assert!(amount > 0, Errors::invalid_argument(ERR_ZERO_AMOUNT)); + let token = Self::withdraw_with_linear_capability(cap); + assert!((cap.withdraw + amount) <= cap.total, Errors::invalid_argument(ERR_TOO_BIG_AMOUNT)); + cap.total = cap.total - amount; + let start_time = Timestamp::now_seconds(); + let new_period = cap.start_time + cap.period - start_time; + let new_key = LinearWithdrawCapability { + total: amount, + withdraw: 0, + start_time, + period: new_period + }; + (token, new_key) + } + + spec split_linear_withdraw_cap { + pragma aborts_if_is_partial; + ensures old(cap.total - cap.withdraw) == + result_1.value + (result_2.total - result_2.withdraw) + (cap.total - cap.withdraw); + } + + + /// Returns the amount of the LinearWithdrawCapability can mint now. + public fun withdraw_amount_of_linear_cap(cap: &LinearWithdrawCapability): u128 { + let now = Timestamp::now_seconds(); + let elapsed_time = now - cap.start_time; + if (elapsed_time >= cap.period) { + cap.total - cap.withdraw + } else { + Math::mul_div(cap.total, (elapsed_time as u128), (cap.period as u128)) - cap.withdraw + } + } + + spec withdraw_amount_of_linear_cap { + // TODO: [MUL_DIV] The most important property is the amount of value. + // However, Math::mul_div remains to be uninterpreted + pragma aborts_if_is_partial; + aborts_if !exists(StarcoinFramework::CoreAddresses::GENESIS_ADDRESS()); + aborts_if Timestamp::spec_now_seconds() < cap.start_time; + aborts_if Timestamp::spec_now_seconds() - cap.start_time >= cap.period && cap.total < cap.withdraw; + aborts_if [abstract] + Timestamp::spec_now_seconds() - cap.start_time < cap.period && Math::spec_mul_div() < cap.withdraw; + ensures [abstract] result <= cap.total - cap.withdraw; + } + + /// Check if the given `LinearWithdrawCapability` is empty. + public fun is_empty_linear_withdraw_cap(key: &LinearWithdrawCapability) : bool { + key.total == key.withdraw + } + + spec is_empty_linear_withdraw_cap { + aborts_if false; + ensures result == (key.total == key.withdraw); + } + + // Improvement: Make move prover support the following definition. + // Following specs contains lots of duplication + //spec schema AddCapability { + // signer: signer; + + // aborts_if exists(Signer::address_of(signer)); + // ensures exists(Signer::address_of(signer)); + //} + + /// Remove mint capability from `signer`. + public fun remove_withdraw_capability(signer: &signer): WithdrawCapability + acquires WithdrawCapability { + move_from>(Signer::address_of(signer)) + } + + spec remove_withdraw_capability { + aborts_if !exists>(Signer::address_of(signer)); + ensures !exists>(Signer::address_of(signer)); + } + + /// Save mint capability to `signer`. + public fun add_withdraw_capability(signer: &signer, cap: WithdrawCapability) { + move_to(signer, cap) + } + + spec add_withdraw_capability { + aborts_if exists>(Signer::address_of(signer)); + ensures exists>(Signer::address_of(signer)); + } + + /// Destroy the given mint capability. + public fun destroy_withdraw_capability(cap: WithdrawCapability) { + let WithdrawCapability {} = cap; + } + + spec destroy_withdraw_capability { + } + + /// Add LinearWithdrawCapability to `signer`, a address only can have one LinearWithdrawCapability + public fun add_linear_withdraw_capability(signer: &signer, cap: LinearWithdrawCapability) { + move_to(signer, cap) + } + + spec add_linear_withdraw_capability { + aborts_if exists>(Signer::address_of(signer)); + ensures exists>(Signer::address_of(signer)); + } + + /// Remove LinearWithdrawCapability from `signer`. + public fun remove_linear_withdraw_capability(signer: &signer): LinearWithdrawCapability + acquires LinearWithdrawCapability { + move_from>(Signer::address_of(signer)) + } + + spec remove_linear_withdraw_capability { + aborts_if !exists>(Signer::address_of(signer)); + ensures !exists>(Signer::address_of(signer)); + } + + /// Destroy LinearWithdrawCapability. + public fun destroy_linear_withdraw_capability(cap: LinearWithdrawCapability) { + let LinearWithdrawCapability{ total: _, withdraw: _, start_time: _, period: _ } = cap; + } + + public fun is_empty_linear_withdraw_capability(cap: &LinearWithdrawCapability): bool { + cap.total == cap.withdraw + } + + /// Get LinearWithdrawCapability total amount + public fun get_linear_withdraw_capability_total(cap: &LinearWithdrawCapability): u128 { + cap.total + } + + /// Get LinearWithdrawCapability withdraw amount + public fun get_linear_withdraw_capability_withdraw(cap: &LinearWithdrawCapability): u128 { + cap.withdraw + } + + /// Get LinearWithdrawCapability period in seconds + public fun get_linear_withdraw_capability_period(cap: &LinearWithdrawCapability): u64 { + cap.period + } + + /// Get LinearWithdrawCapability start_time in seconds + public fun get_linear_withdraw_capability_start_time(cap: &LinearWithdrawCapability): u64 { + cap.start_time + } + + + spec fun spec_balance(): num { + global>(Token::SPEC_TOKEN_TEST_ADDRESS()).balance.value + } + +} +} \ No newline at end of file diff --git a/release/v13/sources/TreasuryScripts.move b/release/v13/sources/TreasuryScripts.move new file mode 100644 index 00000000..34747f89 --- /dev/null +++ b/release/v13/sources/TreasuryScripts.move @@ -0,0 +1,79 @@ +address StarcoinFramework { +module TreasuryScripts { + use StarcoinFramework::Treasury; + use StarcoinFramework::Account; + use StarcoinFramework::Offer; + use StarcoinFramework::TreasuryWithdrawDaoProposal; + + public entry fun withdraw_and_split_lt_withdraw_cap( + signer: signer, + for_address: address, + amount: u128, + lock_period: u64, + ) { + // 1. take cap: LinearWithdrawCapability + let cap = Treasury::remove_linear_withdraw_capability(&signer); + + // 2. withdraw token and split + let (tokens, new_cap) = Treasury::split_linear_withdraw_cap(&mut cap, amount); + + // 3. deposit + Account::deposit_to_self(&signer, tokens); + + // 4. put or destroy key + if (Treasury::is_empty_linear_withdraw_capability(&cap)) { + Treasury::destroy_linear_withdraw_capability(cap); + } else { + Treasury::add_linear_withdraw_capability(&signer, cap); + }; + + // 5. offer + Offer::create(&signer, new_cap, for_address, lock_period); + } + + spec withdraw_and_split_lt_withdraw_cap { + pragma verify = false; + } + + public entry fun withdraw_token_with_linear_withdraw_capability( + signer: signer, + ) { + // 1. take cap + let cap = Treasury::remove_linear_withdraw_capability(&signer); + + // 2. withdraw token + let tokens = Treasury::withdraw_with_linear_capability(&mut cap); + + // 3. deposit + Account::deposit_to_self(&signer, tokens); + + // 4. put or destroy key + if (Treasury::is_empty_linear_withdraw_capability(&cap)) { + Treasury::destroy_linear_withdraw_capability(cap); + } else { + Treasury::add_linear_withdraw_capability(&signer, cap); + }; + } + + spec withdraw_token_with_linear_withdraw_capability { + pragma verify = false; + } + + public entry fun propose_withdraw(signer: signer, receiver: address, amount: u128, period: u64, exec_delay: u64){ + TreasuryWithdrawDaoProposal::propose_withdraw(&signer, receiver, amount, period, exec_delay) + } + + spec propose_withdraw { + pragma verify = false; + } + + public entry fun execute_withdraw_proposal(signer: signer, proposer_address: address, + proposal_id: u64,){ + TreasuryWithdrawDaoProposal::execute_withdraw_proposal(&signer, proposer_address, proposal_id); + } + + spec execute_withdraw_proposal { + pragma verify = false; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/TreasuryWithdrawDaoProposal.move b/release/v13/sources/TreasuryWithdrawDaoProposal.move new file mode 100644 index 00000000..5b3668c1 --- /dev/null +++ b/release/v13/sources/TreasuryWithdrawDaoProposal.move @@ -0,0 +1,119 @@ +address StarcoinFramework { +/// TreasuryWithdrawDaoProposal is a dao proposal for withdraw Token from Treasury. +module TreasuryWithdrawDaoProposal { + use StarcoinFramework::Token::{Self,Token}; + use StarcoinFramework::Signer; + use StarcoinFramework::Dao; + use StarcoinFramework::Errors; + use StarcoinFramework::Treasury; + use StarcoinFramework::CoreAddresses; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_strict; + pragma aborts_if_is_partial; + } + + /// A wrapper of Token MintCapability. + struct WrappedWithdrawCapability has key { + cap: Treasury::WithdrawCapability, + } + + /// WithdrawToken request. + struct WithdrawToken has copy, drop, store { + /// the receiver of withdraw tokens. + receiver: address, + /// how many tokens to mint. + amount: u128, + /// How long in milliseconds does it take for the token to be released + period: u64, + } + + const ERR_NOT_AUTHORIZED: u64 = 101; + /// Only receiver can execute TreasuryWithdrawDaoProposal + const ERR_NEED_RECEIVER_TO_EXECUTE: u64 = 102; + /// The withdraw amount of propose is too many. + const ERR_TOO_MANY_WITHDRAW_AMOUNT: u64 = 103; + + /// Plugin method of the module. + /// Should be called by token issuer. + public fun plugin(signer: &signer, cap: Treasury::WithdrawCapability) { + let token_issuer = Token::token_address(); + assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + move_to(signer, WrappedWithdrawCapability { cap: cap }); + } + + spec plugin { + pragma aborts_if_is_partial = false; + let sender = Signer::address_of(signer); + aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if !exists>(sender); + aborts_if exists>(sender); + + ensures !exists>(sender); + ensures exists>(sender); + } + + + /// Entrypoint for the proposal. + public fun propose_withdraw(signer: &signer, receiver: address, amount: u128, period: u64, exec_delay: u64) { + let quorum_votes = Dao::quorum_votes(); + assert!(amount <= quorum_votes, Errors::invalid_argument(ERR_TOO_MANY_WITHDRAW_AMOUNT)); + Dao::propose( + signer, + WithdrawToken { receiver, amount, period }, + exec_delay, + ); + } + spec propose_withdraw { + use StarcoinFramework::Timestamp; + use StarcoinFramework::CoreAddresses; + pragma aborts_if_is_partial = false; + let quorum_votes = Dao::spec_quorum_votes(); + aborts_if amount > quorum_votes; + // copy from Dao::propose spec. + include Dao::AbortIfDaoConfigNotExist; + include Dao::AbortIfDaoInfoNotExist; + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + aborts_if exec_delay > 0 && exec_delay < Dao::spec_dao_config().min_action_delay; + include Dao::CheckQuorumVotes; + let sender = Signer::address_of(signer); + aborts_if exists>(sender); + } + + /// Once the proposal is agreed, anyone can call the method to make the proposal happen. + public fun execute_withdraw_proposal( + signer: &signer, + proposer_address: address, + proposal_id: u64, + ) acquires WrappedWithdrawCapability { + let WithdrawToken { receiver, amount, period } = Dao::extract_proposal_action( + proposer_address, + proposal_id, + ); + assert!(receiver == Signer::address_of(signer), Errors::requires_address(ERR_NEED_RECEIVER_TO_EXECUTE)); + let cap = borrow_global_mut>(Token::token_address()); + let linear_cap = Treasury::issue_linear_withdraw_capability(&mut cap.cap, amount, period); + Treasury::add_linear_withdraw_capability(signer, linear_cap); + } + + spec execute_withdraw_proposal { + use StarcoinFramework::Option; + pragma aborts_if_is_partial = true; + let expected_states = vec(6); + include Dao::CheckProposalStates{expected_states}; + let proposal = global>(proposer_address); + aborts_if Option::is_none(proposal.action); + aborts_if !exists>(Token::SPEC_TOKEN_TEST_ADDRESS()); + } + + /// Provider a port for get block reward STC from Treasury, only genesis account can invoke this function. + /// The TreasuryWithdrawCapability is locked in TreasuryWithdrawDaoProposal, and only can withdraw by DAO proposal. + /// This approach is not graceful, but restricts the operation to genesis accounts only, so there are no security issues either. + public fun withdraw_for_block_reward(signer: &signer, reward: u128):Token acquires WrappedWithdrawCapability { + CoreAddresses::assert_genesis_address(signer); + let cap = borrow_global_mut>(Signer::address_of(signer)); + Treasury::withdraw_with_capability(&mut cap.cap, reward) + } +} +} \ No newline at end of file diff --git a/release/v13/sources/TypeInfo.move b/release/v13/sources/TypeInfo.move new file mode 100644 index 00000000..fa755c72 --- /dev/null +++ b/release/v13/sources/TypeInfo.move @@ -0,0 +1,44 @@ +module StarcoinFramework::TypeInfo { + use StarcoinFramework::BCS; + use StarcoinFramework::Token; + use StarcoinFramework::Vector; + + struct TypeInfo has copy, drop, store { + account_address: address, + module_name: vector, + struct_name: vector + } + + public fun account_address(type_info: &TypeInfo): address { + type_info.account_address + } + + public fun module_name(type_info: &TypeInfo): vector { + *&type_info.module_name + } + + public fun struct_name(type_info: &TypeInfo): vector { + *&type_info.struct_name + } + + public fun type_of(): TypeInfo { + let (account_address, module_name, struct_name) = Token::type_of(); + TypeInfo { + account_address, + module_name, + struct_name + } + } + + /// Return the BCS size, in bytes, of value at `val_ref`. + /// + /// See the [BCS spec](https://github.com/diem/bcs) + /// + /// See `test_size_of_val()` for an analysis of common types and + /// nesting patterns, as well as `test_size_of_val_vectors()` for an + /// analysis of vector size dynamism. + public fun size_of_val(val_ref: &T): u64 { + // Return vector length of vectorized BCS representation. + Vector::length(&BCS::to_bytes(val_ref)) + } +} \ No newline at end of file diff --git a/release/v13/sources/U256.move b/release/v13/sources/U256.move new file mode 100644 index 00000000..83cbdc27 --- /dev/null +++ b/release/v13/sources/U256.move @@ -0,0 +1,442 @@ +address StarcoinFramework { +/// Helper module to do u64 arith. +module Arith { + use StarcoinFramework::Errors; + const ERR_INVALID_CARRY: u64 = 301; + const ERR_INVALID_BORROW: u64 = 302; + + const P32: u64 = 0x100000000; + const P64: u128 = 0x10000000000000000; + + spec module { + pragma verify = true; + pragma aborts_if_is_strict; + } + + /// split u64 to (high, low) + public fun split_u64(i: u64): (u64, u64) { + (i >> 32, i & 0xFFFFFFFF) + } + + spec split_u64 { + pragma verify = false; + pragma opaque; // MVP cannot reason about bitwise operation + ensures [abstract] result_1 == i / P32; + ensures [abstract] result_2 == i % P32; + } + + /// combine (high, low) to u64, + /// any lower bits of `high` will be erased, any higher bits of `low` will be erased. + public fun combine_u64(hi: u64, lo: u64): u64 { + (hi << 32) | (lo & 0xFFFFFFFF) + } + + spec combine_u64 { + pragma verify = false; + pragma opaque = true; // MVP cannot reason about bitwise operation + let hi_32 = hi % P32; + let lo_32 = lo % P32; + ensures [abstract] result == hi_32 * P32 + lo_32; + } + + /// a + b, with carry + public fun adc(a: u64, b: u64, carry: &mut u64) : u64 { + assert!(*carry <= 1, Errors::invalid_argument(ERR_INVALID_CARRY)); + let (a1, a0) = split_u64(a); + let (b1, b0) = split_u64(b); + let (c, r0) = split_u64(a0 + b0 + *carry); + let (c, r1) = split_u64(a1 + b1 + c); + *carry = c; + combine_u64(r1, r0) + } + + spec adc { + // Carry has either to be 0 or 1 + aborts_if !(carry == 0 || carry == 1); + ensures carry == 0 || carry == 1; + // Result with or without carry + ensures carry == 0 ==> result == a + b + old(carry); + ensures carry == 1 ==> P64 + result == a + b + old(carry); + } + + /// a - b, with borrow + public fun sbb(a: u64, b: u64, borrow: &mut u64): u64 { + assert!(*borrow <= 1, Errors::invalid_argument(ERR_INVALID_BORROW)); + let (a1, a0) = split_u64(a); + let (b1, b0) = split_u64(b); + let (b, r0) = split_u64(P32 + a0 - b0 - *borrow); + let borrowed = 1 - b; + let (b, r1) = split_u64(P32 + a1 - b1 - borrowed); + *borrow = 1 - b; + + combine_u64(r1, r0) + } + + spec sbb { + // Borrow has either to be 0 or 1 + aborts_if !(borrow == 0 || borrow == 1); + ensures borrow == 0 || borrow == 1; + // Result with or without borrow + ensures borrow == 0 ==> result == a - b - old(borrow); + ensures borrow == 1 ==> result == P64 + a - b - old(borrow); + } +} + +/// Implementation u256. +module U256 { + + spec module { + pragma verify = true; + } + + use StarcoinFramework::Vector; + use StarcoinFramework::Errors; + + const WORD: u8 = 4; + const P32: u64 = 0x100000000; + const P64: u128 = 0x10000000000000000; + + const ERR_INVALID_LENGTH: u64 = 100; + const ERR_OVERFLOW: u64 = 200; + /// use vector to represent data. + /// so that we can use buildin vector ops later to construct U256. + /// vector should always has two elements. + struct U256 has copy, drop, store { + /// little endian representation + bits: vector, + } + + spec U256 { + invariant len(bits) == 4; + } + + spec fun value_of_U256(a: U256): num { + a.bits[0] + + a.bits[1] * P64 + + a.bits[2] * P64 * P64 + + a.bits[3] * P64 * P64 * P64 + } + + public fun zero(): U256 { + from_u128(0u128) + } + + public fun one(): U256 { + from_u128(1u128) + } + + public fun from_u64(v: u64): U256 { + from_u128((v as u128)) + } + + public fun from_u128(v: u128): U256 { + let low = ((v & 0xffffffffffffffff) as u64); + let high = ((v >> 64) as u64); + let bits = Vector::singleton(low); + Vector::push_back(&mut bits, high); + Vector::push_back(&mut bits, 0u64); + Vector::push_back(&mut bits, 0u64); + U256 { bits } + } + + spec from_u128 { + pragma verify = false; + pragma opaque; // Original function has bitwise operator + ensures value_of_U256(result) == v; + } + + #[test] + fun test_from_u128() { + // 2^64 + 1 + let v = from_u128(18446744073709551617u128); + assert!(*Vector::borrow(&v.bits, 0) == 1, 0); + assert!(*Vector::borrow(&v.bits, 1) == 1, 1); + assert!(*Vector::borrow(&v.bits, 2) == 0, 2); + assert!(*Vector::borrow(&v.bits, 3) == 0, 3); + } + + public fun from_big_endian(data: vector): U256 { + // TODO: define error code. + assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH)); + from_bytes(&data, true) + } + + spec from_big_endian { + pragma verify = false; // TODO: How to interpret the value of vector data of bytes + } + + public fun from_little_endian(data: vector): U256 { + // TODO: define error code. + assert!(Vector::length(&data) <= 32, Errors::invalid_argument(ERR_INVALID_LENGTH)); + from_bytes(&data, false) + } + + spec from_little_endian { + pragma verify = false; // TODO: How to interpret the value of vector data of bytes + } + + public fun to_u128(v: &U256): u128 { + assert!(*Vector::borrow(&v.bits, 3) == 0, Errors::invalid_state(ERR_OVERFLOW)); + assert!(*Vector::borrow(&v.bits, 2) == 0, Errors::invalid_state(ERR_OVERFLOW)); + ((*Vector::borrow(&v.bits, 1) as u128) << 64) | (*Vector::borrow(&v.bits, 0) as u128) + } + + spec to_u128 { + pragma verify = false; + pragma opaque; // Original function has bitwise operator + aborts_if value_of_U256(v) >= P64 * P64; + ensures value_of_U256(v) == result; + } + + #[test] + fun test_to_u128() { + // 2^^128 - 1 + let i = 340282366920938463463374607431768211455u128; + let v = from_u128(i); + assert!(to_u128(&v) == i, 128); + } + #[test] + #[expected_failure] + fun test_to_u128_overflow() { + // 2^^128 - 1 + let i = 340282366920938463463374607431768211455u128; + let v = from_u128(i); + let v = add(v, one()); + to_u128(&v); + } + + const EQUAL: u8 = 0; + const LESS_THAN: u8 = 1; + const GREATER_THAN: u8 = 2; + + public fun compare(a: &U256, b: &U256): u8 { + let i = (WORD as u64); + while (i > 0) { + i = i - 1; + let a_bits = *Vector::borrow(&a.bits, i); + let b_bits = *Vector::borrow(&b.bits, i); + if (a_bits != b_bits) { + if (a_bits < b_bits) { + return LESS_THAN + } else { + return GREATER_THAN + } + } + }; + return EQUAL + } + + // TODO: MVP interprets it wrong + // spec compare { + // let va = value_of_U256(a); + // let vb = value_of_U256(b); + // ensures (va > vb) ==> (result == GREATER_THAN); + // ensures (va < vb) ==> (result == LESS_THAN); + // ensures (va == vb) ==> (result == EQUAL); + // } + + #[test] + fun test_compare() { + let a = from_u64(111); + let b = from_u64(111); + let c = from_u64(112); + let d = from_u64(110); + assert!(compare(&a, &b) == EQUAL, 0); + assert!(compare(&a, &c) == LESS_THAN, 1); + assert!(compare(&a, &d) == GREATER_THAN, 2); + } + + + public fun add(a: U256, b: U256): U256 { + native_add(&mut a, &b); + a + } + + spec add { + aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(result) == value_of_U256(a) + value_of_U256(b); + } + + #[test] + fun test_add() { + let a = Self::one(); + let b = Self::from_u128(10); + let ret = Self::add(a, b); + assert!(compare(&ret, &from_u64(11)) == EQUAL, 0); + } + + public fun sub(a: U256, b: U256): U256 { + native_sub(&mut a, &b); + a + } + + spec sub { + aborts_if value_of_U256(a) < value_of_U256(b); + ensures value_of_U256(result) == value_of_U256(a) - value_of_U256(b); + } + + #[test] + #[expected_failure] + fun test_sub_overflow() { + let a = Self::one(); + let b = Self::from_u128(10); + let _ = Self::sub(a, b); + } + + #[test] + fun test_sub_ok() { + let a = Self::from_u128(10); + let b = Self::one(); + let ret = Self::sub(a, b); + assert!(compare(&ret, &from_u64(9)) == EQUAL, 0); + } + + public fun mul(a: U256, b: U256): U256 { + native_mul(&mut a, &b); + a + } + + spec mul { + pragma verify = false; + pragma timeout = 200; // Take longer time + aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(result) == value_of_U256(a) * value_of_U256(b); + } + + #[test] + fun test_mul() { + let a = Self::from_u128(10); + let b = Self::from_u64(10); + let ret = Self::mul(a, b); + assert!(compare(&ret, &from_u64(100)) == EQUAL, 0); + } + + public fun div(a: U256, b: U256): U256 { + native_div(&mut a, &b); + a + } + + spec div { + pragma verify = false; + pragma timeout = 160; // Might take longer time + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(result) == value_of_U256(a) / value_of_U256(b); + } + + #[test] + fun test_div() { + let a = Self::from_u128(10); + let b = Self::from_u64(2); + let c = Self::from_u64(3); + // as U256 cannot be implicitly copied, we need to add copy keyword. + assert!(compare(&Self::div(copy a, b), &from_u64(5)) == EQUAL, 0); + assert!(compare(&Self::div(copy a, c), &from_u64(3)) == EQUAL, 0); + } + + public fun rem(a: U256, b: U256): U256 { + native_rem(&mut a, &b); + a + } + + spec rem { + pragma verify = false; + pragma timeout = 160; // Might take longer time + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(result) == value_of_U256(a) % value_of_U256(b); + } + + #[test] + fun test_rem() { + let a = Self::from_u128(10); + let b = Self::from_u64(2); + let c = Self::from_u64(3); + assert!(compare(&Self::rem(copy a, b), &from_u64(0)) == EQUAL, 0); + assert!(compare(&Self::rem(copy a, c), &from_u64(1)) == EQUAL, 0); + } + + public fun pow(a: U256, b: U256): U256 { + native_pow(&mut a, &b); + a + } + + spec pow { + // Verfication of Pow takes enormous amount of time + // Don't verify it, and make it opaque so that the caller + // can make use of the properties listed here. + pragma verify = false; + pragma opaque; + pragma timeout = 600; + let p = pow_spec(value_of_U256(a), value_of_U256(b)); + aborts_if p >= P64 * P64 * P64 * P64; + ensures value_of_U256(result) == p; + } + + #[test] + fun test_pow() { + let a = Self::from_u128(10); + let b = Self::from_u64(1); + let c = Self::from_u64(2); + let d = Self::zero(); + assert!(compare(&Self::pow(copy a, b), &from_u64(10)) == EQUAL, 0); + assert!(compare(&Self::pow(copy a, c), &from_u64(100)) == EQUAL, 0); + assert!(compare(&Self::pow(copy a, d), &from_u64(1)) == EQUAL, 0); + } + + native fun from_bytes(data: &vector, be: bool): U256; + native fun native_add(a: &mut U256, b: &U256); + native fun native_sub(a: &mut U256, b: &U256); + native fun native_mul(a: &mut U256, b: &U256); + native fun native_div(a: &mut U256, b: &U256); + native fun native_rem(a: &mut U256, b: &U256); + native fun native_pow(a: &mut U256, b: &U256); + + spec native_add { + pragma opaque; + aborts_if value_of_U256(a) + value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(a) == value_of_U256(old(a)) + value_of_U256(b); + } + + spec native_sub { + pragma opaque; + aborts_if value_of_U256(a) - value_of_U256(b) < 0; + ensures value_of_U256(a) == value_of_U256(old(a)) - value_of_U256(b); + } + + spec native_mul { + pragma opaque; + aborts_if value_of_U256(a) * value_of_U256(b) >= P64 * P64 * P64 * P64; + ensures value_of_U256(a) == value_of_U256(old(a)) * value_of_U256(b); + } + + spec native_div { + pragma opaque; + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(a) == value_of_U256(old(a)) / value_of_U256(b); + } + + spec native_rem { + pragma opaque; + aborts_if value_of_U256(b) == 0; + ensures value_of_U256(a) == value_of_U256(old(a)) % value_of_U256(b); + } + + spec native_pow { + pragma opaque; + aborts_if pow_spec(value_of_U256(a), value_of_U256(b)) >= P64 * P64 * P64 * P64; + ensures value_of_U256(a) == pow_spec(value_of_U256(old(a)), value_of_U256(b)); + } + + spec fun pow_spec(base: num, expon: num): num { + // This actually doesn't follow a strict definition as 0^0 is undefined + // mathematically. But the U256::pow of Rust is defined to be like this: + // Link: https://docs.rs/uint/0.9.3/src/uint/uint.rs.html#1000-1003 + if (expon > 0) { + let x = pow_spec(base, expon / 2); + if (expon % 2 == 0) { x * x } else { x * x * base } + } else { + 1 + } + } + +} +} diff --git a/release/v13/sources/UpgradeModuleDaoProposal.move b/release/v13/sources/UpgradeModuleDaoProposal.move new file mode 100644 index 00000000..d4cb99c8 --- /dev/null +++ b/release/v13/sources/UpgradeModuleDaoProposal.move @@ -0,0 +1,117 @@ +address StarcoinFramework { +/// UpgradeModuleDaoProposal is a proposal moudle used to upgrade contract codes under a token. +module UpgradeModuleDaoProposal { + use StarcoinFramework::PackageTxnManager; + use StarcoinFramework::Token; + use StarcoinFramework::Signer; + use StarcoinFramework::Option; + use StarcoinFramework::Dao; + use StarcoinFramework::Errors; + + spec module { + pragma verify = false; // break after enabling v2 compilation scheme + pragma aborts_if_is_strict; + pragma aborts_if_is_partial; + } + + const ERR_UNABLE_TO_UPGRADE: u64 = 400; + const ERR_NOT_AUTHORIZED: u64 = 401; + const ERR_ADDRESS_MISSMATCH: u64 = 402; + + /// A wrapper of `PackageTxnManager::UpgradePlanCapability`. + struct UpgradeModuleCapability has key { + cap: PackageTxnManager::UpgradePlanCapability, + } + + /// request of upgrading module contract code. + struct UpgradeModule has copy, drop, store { + module_address: address, + package_hash: vector, + version: u64, + } + + struct UpgradeModuleV2 has copy, drop, store { + module_address: address, + package_hash: vector, + version: u64, + enforced: bool, + } + + /// If this goverment can upgrade module, call this to register capability. + public fun plugin( + signer: &signer, + cap: PackageTxnManager::UpgradePlanCapability, + ) { + let token_issuer = Token::token_address(); + assert!(Signer::address_of(signer) == token_issuer, Errors::requires_address(ERR_NOT_AUTHORIZED)); + move_to(signer, UpgradeModuleCapability { cap }) + } + + spec plugin { + pragma aborts_if_is_partial = false; + + let sender = Signer::address_of(signer); + aborts_if sender != Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if exists>(sender); + } + + spec schema AbortIfUnableUpgrade { + module_address: address; + let token_issuer = Token::SPEC_TOKEN_TEST_ADDRESS(); + aborts_if !exists>(token_issuer); + let cap = global>(token_issuer).cap; + aborts_if PackageTxnManager::account_address(cap) != module_address; + } + + public fun propose_module_upgrade_v2( + signer: &signer, + module_address: address, + package_hash: vector, + version: u64, + exec_delay: u64, + enforced: bool, + ) acquires UpgradeModuleCapability { + let cap = borrow_global>(Token::token_address()); + let account_address = PackageTxnManager::account_address(&cap.cap); + assert!(account_address == module_address, Errors::requires_capability(ERR_ADDRESS_MISSMATCH)); + Dao::propose( + signer, + UpgradeModuleV2 { module_address, package_hash, version, enforced }, + exec_delay, + ); + } + + spec propose_module_upgrade_v2 { + pragma aborts_if_is_partial = true; + include AbortIfUnableUpgrade; + } + + /// Once the proposal is agreed, anyone can call this method to generate the upgrading plan. + public fun submit_module_upgrade_plan( + proposer_address: address, + proposal_id: u64, + ) acquires UpgradeModuleCapability { + let UpgradeModuleV2 { module_address, package_hash, version, enforced } = Dao::extract_proposal_action< + TokenT, + UpgradeModuleV2, + >(proposer_address, proposal_id); + let cap = borrow_global>(Token::token_address()); + let account_address = PackageTxnManager::account_address(&cap.cap); + assert!(account_address == module_address, Errors::requires_capability(ERR_ADDRESS_MISSMATCH)); + PackageTxnManager::submit_upgrade_plan_with_cap_v2( + &cap.cap, + package_hash, + version, + enforced, + ); + } + spec submit_module_upgrade_plan { + let expected_states = vec(6); + include Dao::CheckProposalStates{expected_states}; + let proposal = global>(proposer_address); + aborts_if Option::is_none(proposal.action); + let action = proposal.action.vec[0]; + include AbortIfUnableUpgrade{module_address: action.module_address}; + } +} +} \ No newline at end of file diff --git a/release/v13/sources/VMConfig.move b/release/v13/sources/VMConfig.move new file mode 100644 index 00000000..3f962e83 --- /dev/null +++ b/release/v13/sources/VMConfig.move @@ -0,0 +1,442 @@ +address StarcoinFramework { +/// `VMConfig` keep track of VM related configuration, like gas schedule. +module VMConfig { + use StarcoinFramework::Config; + use StarcoinFramework::Signer; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Vector; + use StarcoinFramework::ChainId; + spec module { + pragma verify = false; + pragma aborts_if_is_strict; + } + + /// The struct to hold all config data needed to operate the VM. + /// * gas_schedule: Cost of running the VM. + struct VMConfig has copy, drop, store { + gas_schedule: GasSchedule, + } + + /// The gas schedule keeps two separate schedules for the gas: + /// * The instruction_schedule: This holds the gas for each bytecode instruction. + /// * The native_schedule: This holds the gas for used (per-byte operated over) for each native + /// function. + /// A couple notes: + /// 1. In the case that an instruction is deleted from the bytecode, that part of the cost schedule + /// still needs to remain the same; once a slot in the table is taken by an instruction, that is its + /// slot for the rest of time (since that instruction could already exist in a module on-chain). + /// 2. The initialization of the module will publish the instruction table to the genesis + /// address, and will preload the vector with the gas schedule for instructions. The VM will then + /// load this into memory at the startup of each block. + struct GasSchedule has copy, drop, store { + instruction_schedule: vector, + native_schedule: vector, + gas_constants: GasConstants, + } + + /// The gas constants contains all kind of constants used in gas calculation. + struct GasConstants has copy, drop, store { + /// The cost per-byte written to global storage. + global_memory_per_byte_cost: u64, + /// The cost per-byte written to storage. + global_memory_per_byte_write_cost: u64, + /// We charge one unit of gas per-byte for the first 600 bytes + min_transaction_gas_units: u64, + /// Any transaction over this size will be charged `INTRINSIC_GAS_PER_BYTE` per byte + large_transaction_cutoff: u64, + /// The units of gas that should be charged per byte for every transaction. + instrinsic_gas_per_byte: u64, + /// 1 nanosecond should equal one unit of computational gas. We bound the maximum + /// computational time of any given transaction at 10 milliseconds. We want this number and + /// `MAX_PRICE_PER_GAS_UNIT` to always satisfy the inequality that + /// MAXIMUM_NUMBER_OF_GAS_UNITS * MAX_PRICE_PER_GAS_UNIT < min(u64::MAX, GasUnits::MAX) + maximum_number_of_gas_units: u64, + /// The minimum gas price that a transaction can be submitted with. + min_price_per_gas_unit: u64, + /// The maximum gas unit price that a transaction can be submitted with. + max_price_per_gas_unit: u64, + /// The max transaction size in bytes that a transaction can have. + max_transaction_size_in_bytes: u64, + /// gas unit scaling factor. + gas_unit_scaling_factor: u64, + /// default account size. + default_account_size: u64, + } + + /// The `GasCost` tracks: + /// - instruction cost: how much time/computational power is needed to perform the instruction + /// - memory cost: how much memory is required for the instruction, and storage overhead + struct GasCost has copy, drop, store { + instruction_gas: u64, + memory_gas: u64, + } + + public fun instruction_schedule(): vector { + let table = Vector::empty(); + + // POP + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // RET + Vector::push_back(&mut table, new_gas_cost(638, 1)); + // BR_TRUE + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // BR_FALSE + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // BRANCH + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LD_U64 + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LD_CONST + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LD_TRUE + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LD_FALSE + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // COPY_LOC + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // MOVE_LOC + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // ST_LOC + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // MUT_BORROW_LOC + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // IMM_BORROW_LOC + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // MUT_BORROW_FIELD + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // IMM_BORROW_FIELD + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // CALL + Vector::push_back(&mut table, new_gas_cost(1132, 1)); + // PACK + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // UNPACK + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // READ_REF + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // WRITE_REF + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // ADD + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // SUB + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // MUL + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // MOD + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // DIV + Vector::push_back(&mut table, new_gas_cost(3, 1)); + // BIT_OR + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // BIT_AND + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // XOR + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // OR + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // AND + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // NOT + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // EQ + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // NEQ + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LT + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // GT + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LE + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // GE + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // ABORT + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // NOP + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // EXISTS + Vector::push_back(&mut table, new_gas_cost(41, 1)); + // MUT_BORROW_GLOBAL + Vector::push_back(&mut table, new_gas_cost(21, 1)); + // IML_BORROW_GLOBAL + Vector::push_back(&mut table, new_gas_cost(23, 1)); + // MOVE_FROM + Vector::push_back(&mut table, new_gas_cost(459, 1)); + // MOVE_TO + Vector::push_back(&mut table, new_gas_cost(13, 1)); + // FREEZE_REF + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // SHL + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // SHR + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LD_U8 + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // LD_U128 + Vector::push_back(&mut table, new_gas_cost(1, 1)); + + // CAST_U8 + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // CAST_U64 + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // CAST_U128 + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // MUT_BORORW_FIELD_GENERIC + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // IMM_BORORW_FIELD_GENERIC + Vector::push_back(&mut table, new_gas_cost(1, 1)); + // CALL_GENERIC + Vector::push_back(&mut table, new_gas_cost(582, 1)); + // PACK_GENERIC + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // UNPACK_GENERIC + Vector::push_back(&mut table, new_gas_cost(2, 1)); + // EXISTS_GENERIC + Vector::push_back(&mut table, new_gas_cost(34, 1)); + // MUT_BORROW_GLOBAL_GENERIC + Vector::push_back(&mut table, new_gas_cost(15, 1)); + // IMM_BORROW_GLOBAL_GENERIC + Vector::push_back(&mut table, new_gas_cost(14, 1)); + // MOVE_FROM_GENERIC + Vector::push_back(&mut table, new_gas_cost(13, 1)); + // MOVE_TO_GENERIC + Vector::push_back(&mut table, new_gas_cost(27, 1)); + + // VEC_PACK + Vector::push_back(&mut table, new_gas_cost(84, 1)); + // VEC_LEN + Vector::push_back(&mut table, new_gas_cost(98, 1)); + // VEC_IMM_BORROW + Vector::push_back(&mut table, new_gas_cost(1334, 1)); + // VEC_MUT_BORROW + Vector::push_back(&mut table, new_gas_cost(1902, 1)); + // VEC_PUSH_BACK + Vector::push_back(&mut table, new_gas_cost(53, 1)); + // VEC_POP_BACK + Vector::push_back(&mut table, new_gas_cost(227, 1)); + // VEC_UNPACK + Vector::push_back(&mut table, new_gas_cost(572, 1)); + // VEC_SWAP + Vector::push_back(&mut table, new_gas_cost(1436, 1)); + table + } + + public fun native_schedule(): vector { + let table = Vector::empty(); + //Hash::sha2_256 0 + Vector::push_back(&mut table, new_gas_cost(21, 1)); + //Hash::sha3_256 1 + Vector::push_back(&mut table, new_gas_cost(64, 1)); + //Signature::ed25519_verify 2 + Vector::push_back(&mut table, new_gas_cost(61, 1)); + //ED25519_THRESHOLD_VERIFY 3 this native funciton is deprecated + Vector::push_back(&mut table, new_gas_cost(3351, 1)); + //BSC::to_bytes 4 + Vector::push_back(&mut table, new_gas_cost(181, 1)); + //Vector::length 5 + Vector::push_back(&mut table, new_gas_cost(98, 1)); + //Vector::empty 6 + Vector::push_back(&mut table, new_gas_cost(84, 1)); + //Vector::borrow 7 + Vector::push_back(&mut table, new_gas_cost(1334, 1)); + //Vector::borrow_mut 8 + Vector::push_back(&mut table, new_gas_cost(1902, 1)); + //Vector::push_back 9 + Vector::push_back(&mut table, new_gas_cost(53, 1)); + //Vector::pop_back 10 + Vector::push_back(&mut table, new_gas_cost(227, 1)); + //Vector::destory_empty 11 + Vector::push_back(&mut table, new_gas_cost(572, 1)); + //Vector::swap 12 + Vector::push_back(&mut table, new_gas_cost(1436, 1)); + //Signature::ed25519_validate_pubkey 13 + Vector::push_back(&mut table, new_gas_cost(26, 1)); + //Signer::borrow_address 14 + Vector::push_back(&mut table, new_gas_cost(353, 1)); + //Account::creator_signer 15 + Vector::push_back(&mut table, new_gas_cost(24, 1)); + //Account::destroy_signer 16 + Vector::push_back(&mut table, new_gas_cost(212, 1)); + //Event::emit_event 17 + Vector::push_back(&mut table, new_gas_cost(52, 1)); + //BCS::to_address 18 + Vector::push_back(&mut table, new_gas_cost(26, 1)); + //Token::name_of 19 + Vector::push_back(&mut table, new_gas_cost(2002, 1)); + //Hash::keccak_256 20 + Vector::push_back(&mut table, new_gas_cost(64, 1)); + //Hash::ripemd160 21 + Vector::push_back(&mut table, new_gas_cost(64, 1)); + //Signature::native_ecrecover 22 + Vector::push_back(&mut table, new_gas_cost(128, 1)); + //U256::from_bytes 23 + Vector::push_back(&mut table, new_gas_cost(2, 1)); + //U256::add 24 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + //U256::sub 25 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + //U256::mul 26 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + //U256::div 27 + Vector::push_back(&mut table, new_gas_cost(10, 1)); + // U256::rem 28 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // U256::pow 29 + Vector::push_back(&mut table, new_gas_cost(8, 1)); + // TODO: settle down the gas cost + // Vector::append 30 + Vector::push_back(&mut table, new_gas_cost(40, 1)); + // Vector::remove 31 + Vector::push_back(&mut table, new_gas_cost(20, 1)); + // Vector::reverse 32 + Vector::push_back(&mut table, new_gas_cost(10, 1)); + + // Table::new_table_handle 33 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // Table::add_box 34 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // Table::borrow_box 35 + Vector::push_back(&mut table, new_gas_cost(10, 1)); + // Table::remove_box 36 + Vector::push_back(&mut table, new_gas_cost(8, 1)); + // Table::contains_box 37 + Vector::push_back(&mut table, new_gas_cost(40, 1)); + // Table::destroy_empty_box 38 + Vector::push_back(&mut table, new_gas_cost(20, 1)); + // Table::drop_unchecked_box 39 + Vector::push_back(&mut table, new_gas_cost(73, 1)); + // string.check_utf8 40 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // string.sub_str 41 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // string.is_char_boundary 42 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // Table::string.index_of 43 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // FromBCS::from_bytes 44 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // Secp256k1::ecdsa_recover_internal 45 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + // Vector::spawn_from 46 + Vector::push_back(&mut table, new_gas_cost(4, 1)); + + table + } + + public fun gas_constants(): GasConstants { + let min_price_per_gas_unit: u64 = if (ChainId::is_test()) { 0 } else { 1 }; + let maximum_number_of_gas_units: u64 = 40000000;//must less than base_block_gas_limit + + if (ChainId::is_test() || ChainId::is_dev() || ChainId::is_halley()) { + maximum_number_of_gas_units = maximum_number_of_gas_units * 10 + }; + GasConstants { + global_memory_per_byte_cost: 4, + global_memory_per_byte_write_cost: 9, + min_transaction_gas_units: 600, + large_transaction_cutoff: 600, + instrinsic_gas_per_byte: 8, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit: 10000, + max_transaction_size_in_bytes: 1024 * 128, + gas_unit_scaling_factor: 1, + default_account_size: 800, + } + } + + fun new_gas_cost(instr_gas: u64, mem_gas: u64): GasCost { + GasCost { + instruction_gas: instr_gas, + memory_gas: mem_gas, + } + } + + + /// Create a new vm config, mainly used in DAO. + public fun new_vm_config( + instruction_schedule: vector, + native_schedule: vector, + global_memory_per_byte_cost: u64, + global_memory_per_byte_write_cost: u64, + min_transaction_gas_units: u64, + large_transaction_cutoff: u64, + instrinsic_gas_per_byte: u64, + maximum_number_of_gas_units: u64, + min_price_per_gas_unit: u64, + max_price_per_gas_unit: u64, + max_transaction_size_in_bytes: u64, + gas_unit_scaling_factor: u64, + default_account_size: u64, + ): VMConfig { + let gas_constants = GasConstants { + global_memory_per_byte_cost, + global_memory_per_byte_write_cost, + min_transaction_gas_units, + large_transaction_cutoff, + instrinsic_gas_per_byte, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit, + max_transaction_size_in_bytes, + gas_unit_scaling_factor, + default_account_size, + }; + VMConfig { + gas_schedule: GasSchedule { instruction_schedule, native_schedule, gas_constants }, + } + } + + /// Initialize the table under the genesis account + public fun initialize( + account: &signer, + instruction_schedule: vector, + native_schedule: vector, + global_memory_per_byte_cost: u64, + global_memory_per_byte_write_cost: u64, + min_transaction_gas_units: u64, + large_transaction_cutoff: u64, + instrinsic_gas_per_byte: u64, + maximum_number_of_gas_units: u64, + min_price_per_gas_unit: u64, + max_price_per_gas_unit: u64, + max_transaction_size_in_bytes: u64, + gas_unit_scaling_factor: u64, + default_account_size: u64, + ) { + CoreAddresses::assert_genesis_address(account); + Config::publish_new_config( + account, + new_vm_config( + instruction_schedule, + native_schedule, + global_memory_per_byte_cost, + global_memory_per_byte_write_cost, + min_transaction_gas_units, + large_transaction_cutoff, + instrinsic_gas_per_byte, + maximum_number_of_gas_units, + min_price_per_gas_unit, + max_price_per_gas_unit, + max_transaction_size_in_bytes, + gas_unit_scaling_factor, + default_account_size, + ), + ); + } + + spec initialize { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists>(Signer::address_of(account)); + aborts_if + exists>( + Signer::address_of(account), + ); + ensures exists>(Signer::address_of(account)); + ensures + exists>( + Signer::address_of(account), + ); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/Vector.move b/release/v13/sources/Vector.move new file mode 100644 index 00000000..59db7ae5 --- /dev/null +++ b/release/v13/sources/Vector.move @@ -0,0 +1,250 @@ +address StarcoinFramework { + +/// A variable-sized container that can hold any type. Indexing is 0-based, and +/// vectors are growable. This module has many native functions. +/// Verification of modules that use this one uses model functions that are implemented +/// directly in Boogie. The specification language has built-in functions operations such +/// as `vec`. There are some helper functions defined here for specifications in other +/// modules as well. +/// +/// >Note: We did not verify most of the +/// Move functions here because many have loops, requiring loop invariants to prove, and +/// the return on investment didn't seem worth it for these simple functions. +module Vector { + + /// The index into the vector is out of bounds + const EINDEX_OUT_OF_BOUNDS: u64 = 0; + + /// Create an empty vector. + native public fun empty(): vector; + + /// Return the length of the vector. + native public fun length(v: &vector): u64; + + /// Acquire an immutable reference to the `i`th element of the vector `v`. + /// Aborts if `i` is out of bounds. + native public fun borrow(v: &vector, i: u64): ∈ + + /// Add element `e` to the end of the vector `v`. + native public fun push_back(v: &mut vector, e: Element); + + /// Return a mutable reference to the `i`th element in the vector `v`. + /// Aborts if `i` is out of bounds. + native public fun borrow_mut(v: &mut vector, i: u64): &mut Element; + + /// Pop an element from the end of vector `v`. + /// Aborts if `v` is empty. + native public fun pop_back(v: &mut vector): Element; + + /// Destroy the vector `v`. + /// Aborts if `v` is not empty. + native public fun destroy_empty(v: vector); + + /// Spawn a sub vector from a vector + native fun spawn_from(v: &vector, offset: u64, size: u64): vector; + + spec spawn_from { + pragma opaque; + ensures [abstract] result == v[offset..offset+size]; + } + + public fun spawn_from_vec(v: &vector, offset: u64, size: u64): vector { + let len = length(v); + let end_idx = (offset + size); + assert!(end_idx <= len, EINDEX_OUT_OF_BOUNDS); + assert!(size > 0, EINDEX_OUT_OF_BOUNDS); + if (offset == 0 && end_idx == len) { + return *v + }; + spawn_from(v, offset, size) + } + + /// Swaps the elements at the `i`th and `j`th indices in the vector `v`. + /// Aborts if `i`or `j` is out of bounds. + native public fun swap(v: &mut vector, i: u64, j: u64); + + /// Return an vector of size one containing element `e`. + public fun singleton(e: Element): vector { + let v = empty(); + push_back(&mut v, e); + v + } + spec singleton { + // TODO: when using opaque here, we get verification errors. + // pragma opaque; + aborts_if false; + ensures result == vec(e); + } + spec fun spec_singleton(e: Element): vector { + vec(e) + } + + + /// Reverses the order of the elements in the vector `v` in place. + public fun reverse(v: &mut vector) { + native_reverse(v) + } + spec reverse { + pragma intrinsic = true; + } + native fun native_reverse(this: &mut vector); + + /// Pushes all of the elements of the `other` vector into the `lhs` vector. + public fun append(lhs: &mut vector, other: vector) { + native_append(lhs, other); + } + native fun native_append(lhs: &mut vector, other: vector); + + spec append { + pragma intrinsic = true; + } + spec is_empty { + pragma intrinsic = true; + } + + + /// Return `true` if the vector `v` has no elements and `false` otherwise. + public fun is_empty(v: &vector): bool { + length(v) == 0 + } + + /// Return true if `e` is in the vector `v`. + public fun contains(v: &vector, e: &Element): bool { + let i = 0; + let len = length(v); + while (i < len) { + if (borrow(v, i) == e) return true; + i = i + 1; + }; + false + } + spec contains { + pragma intrinsic = true; + } + + /// Return `(true, i)` if `e` is in the vector `v` at index `i`. + /// Otherwise, returns `(false, 0)`. + public fun index_of(v: &vector, e: &Element): (bool, u64) { + let i = 0; + let len = length(v); + while (i < len) { + if (borrow(v, i) == e) return (true, i); + i = i + 1; + }; + (false, 0) + } + spec index_of { + pragma intrinsic = true; + } + + /// Remove the `i`th element of the vector `v`, shifting all subsequent elements. + /// This is O(n) and preserves ordering of elements in the vector. + /// Aborts if `i` is out of bounds. + public fun remove(v: &mut vector, i: u64): Element { + let len = length(v); + // i out of bounds; abort + if (i >= len) abort EINDEX_OUT_OF_BOUNDS; + + native_remove(v, i) + } + spec remove { + pragma intrinsic = true; + } + native fun native_remove(this: &mut vector, i: u64): Element; + + /// Swap the `i`th element of the vector `v` with the last element and then pop the vector. + /// This is O(1), but does not preserve ordering of elements in the vector. + /// Aborts if `i` is out of bounds. + public fun swap_remove(v: &mut vector, i: u64): Element { + let last_idx = length(v) - 1; + swap(v, i, last_idx); + pop_back(v) + } + spec swap_remove { + pragma intrinsic = true; + } + + /// Split a vector into sub-vectors of size sub_len, + public fun split(v: &vector, sub_len: u64): vector> { + let result = empty>(); + let len = length(v) / sub_len; + + let rem = 0; + if (len * sub_len < length(v)) { + rem = length(v) - len * sub_len; + }; + + let i = 0; + while (i < len) { + let sub = empty(); + let j = 0; + while (j < sub_len) { + let index = sub_len * i + j; + push_back(&mut sub, *borrow(v, index)); + j = j + 1; + }; + push_back>(&mut result, sub); + i = i + 1; + }; + + if (rem > 0) { + let sub = empty(); + let index = length(v) - rem; + while (index < length(v)) { + push_back(&mut sub, *borrow(v, index)); + index = index + 1; + }; + push_back>(&mut result, sub); + }; + result + } + + spec split { + pragma verify = false; // timeout, skip + aborts_if sub_len == 0; + } + + + // ================================================================= + // Module Specification + + spec module {} // Switch to module documentation context + + /// # Helper Functions + + + /// Check whether a vector contains an element. + spec fun spec_contains(v: vector, e: Element): bool { + exists x in v: x == e + } + + /// Check if `v1` is equal to the result of adding `e` at the end of `v2` + spec fun eq_push_back(v1: vector, v2: vector, e: Element): bool { + len(v1) == len(v2) + 1 && + v1[len(v1)-1] == e && + v1[0..len(v1)-1] == v2[0..len(v2)] + } + + /// Check if `v` is equal to the result of concatenating `v1` and `v2` + spec fun eq_append(v: vector, v1: vector, v2: vector): bool { + len(v) == len(v1) + len(v2) && + v[0..len(v1)] == v1 && + v[len(v1)..len(v)] == v2 + } + + /// Check `v1` is equal to the result of removing the first element of `v2` + spec fun eq_pop_front(v1: vector, v2: vector): bool { + len(v1) + 1 == len(v2) && + v1 == v2[1..len(v2)] + } + + /// Check that `v1` is equal to the result of removing the element at index `i` from `v2`. + spec fun eq_remove_elem_at_index(i: u64, v1: vector, v2: vector): bool { + len(v1) + 1 == len(v2) && + v1[0..i] == v2[0..i] && + v1[i..len(v1)] == v2[i + 1..len(v2)] + } + +} + +} diff --git a/release/v13/sources/Version.move b/release/v13/sources/Version.move new file mode 100644 index 00000000..86330627 --- /dev/null +++ b/release/v13/sources/Version.move @@ -0,0 +1,38 @@ +address StarcoinFramework { +/// `Version` tracks version of something, like current VM version. +module Version { + use StarcoinFramework::Config; + + const EMAJOR_TO_OLD: u64 = 101; + + spec module { + pragma verify; + pragma aborts_if_is_strict; + } + + /// Version. + struct Version has copy, drop, store { + /// major number. + major: u64, + } + + /// Create a new version. + public fun new_version(major: u64): Version { + Version { major } + } + + spec new_version { + aborts_if false; + } + + /// Get version under `addr`. + public fun get(addr: address): u64 { + let version = Config::get_by_address(addr); + version.major + } + + spec get { + aborts_if !exists>(addr); + } +} +} \ No newline at end of file diff --git a/release/v13/sources/YieldFarming.move b/release/v13/sources/YieldFarming.move new file mode 100644 index 00000000..7ca65bb5 --- /dev/null +++ b/release/v13/sources/YieldFarming.move @@ -0,0 +1,204 @@ +// Copyright (c) The Starcoin Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +address StarcoinFramework { +module YieldFarming { + use StarcoinFramework::Token; + use StarcoinFramework::Errors; + + const EDEPRECATED_FUNCTION: u64 = 19; + const ERR_FARMING_INIT_REPEATE: u64 = 101; + const ERR_FARMING_NOT_STILL_FREEZE: u64 = 102; + const ERR_FARMING_STAKE_EXISTS: u64 = 103; + const ERR_FARMING_STAKE_NOT_EXISTS: u64 = 104; + const ERR_FARMING_HAVERST_NO_GAIN: u64 = 105; + const ERR_FARMING_TOTAL_WEIGHT_IS_ZERO: u64 = 106; + const ERR_EXP_DIVIDE_BY_ZERO: u64 = 107; + const ERR_FARMING_BALANCE_EXCEEDED: u64 = 108; + const ERR_FARMING_NOT_ENOUGH_ASSET: u64 = 109; + const ERR_FARMING_TIMESTAMP_INVALID: u64 = 110; + + spec module { + pragma verify = false; + } + + /// The object of yield farming + /// RewardTokenT meaning token of yield farming + struct Farming has key, store { + treasury_token: Token::Token, + } + + struct FarmingAsset has key, store { + asset_total_weight: u128, + harvest_index: u128, + last_update_timestamp: u64, + // Release count per seconds + release_per_second: u128, + // Start time, by seconds, user can operate stake only after this timestamp + start_time: u64, + } + + /// Capability to modify parameter such as period and release amount + struct ParameterModifyCapability has key, store {} + + /// To store user's asset token + struct Stake has key, store { + asset: AssetT, + asset_weight: u128, + last_harvest_index: u128, + gain: u128, + } + + ////////////////////////////////////////////////////////////////////// + // Exponential functions + + const EXP_SCALE: u128 = 1000000000000000000;// e18 + + struct Exp has copy, store, drop { + mantissa: u128 + } + + fun exp(num: u128, denom: u128): Exp { + // if overflow move will abort + let scaledNumerator = mul_u128(num, EXP_SCALE); + let rational = div_u128(scaledNumerator, denom); + Exp { + mantissa: rational + } + } + + fun mul_u128(a: u128, b: u128): u128 { + if (a == 0 || b == 0) { + return 0 + }; + + a * b + } + + fun div_u128(a: u128, b: u128): u128 { + if ( b == 0) { + abort Errors::invalid_argument(ERR_EXP_DIVIDE_BY_ZERO) + }; + if (a == 0) { + return 0 + }; + a / b + } + + fun truncate(exp: Exp): u128 { + return exp.mantissa / EXP_SCALE + } + + /// Called by token issuer + /// this will declare a yield farming pool + public fun initialize< + PoolType: store, + RewardTokenT: store>(_account: &signer, + _treasury_token: Token::Token) { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + // Initialize asset pools + public fun initialize_asset( + _account: &signer, + _release_per_second: u128, + _delay: u64): ParameterModifyCapability { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + public fun modify_parameter( + _cap: &ParameterModifyCapability, + _broker: address, + _release_per_second: u128) { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + /// Call by stake user, staking amount of asset in order to get yield farming token + public fun stake( + _account: &signer, + _broker: address, + _asset: AssetT, + _asset_weight: u128) { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + /// Unstake asset from farming pool + public fun unstake(_account: &signer, _broker: address) + : (AssetT, Token::Token) { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + /// Harvest yield farming token from stake + public fun harvest( + _account: &signer, + _broker: address, + _amount: u128): Token::Token { + abort Errors::deprecated(EDEPRECATED_FUNCTION) + } + + /// The user can quering all yield farming amount in any time and scene + public fun query_gov_token_amount(_account: &signer, _broker: address): u128 { + 0 + } + + /// Query total stake count from yield farming resource + public fun query_total_stake(_broker: address): u128 { + 0 + } + + /// Query stake weight from user staking objects. + public fun query_stake(_account: &signer): u128 { + 0 + } + + /// Update farming asset + fun calculate_harvest_index_with_asset(_farming_asset: &FarmingAsset, _now_seconds: u64): u128 { + 0 + } + + /// There is calculating from harvest index and global parameters without asset_total_weight + public fun calculate_harvest_index_weight_zero(_harvest_index: u128, + _last_update_timestamp: u64, + _now_seconds: u64, + _release_per_second: u128): u128 { + 0 + } + + /// There is calculating from harvest index and global parameters + public fun calculate_harvest_index(_harvest_index: u128, + _asset_total_weight: u128, + _last_update_timestamp: u64, + _now_seconds: u64, + _release_per_second: u128): u128 { + 0 + } + + /// This function will return a gain index + public fun calculate_withdraw_amount(_harvest_index: u128, + _last_harvest_index: u128, + _asset_weight: u128): u128 { + 0 + } + + /// Check the Farming of TokenT is exists. + public fun exists_at(broker: address): bool { + exists>(broker) + } + + /// Check the Farming of AsssetT is exists. + public fun exists_asset_at(broker: address): bool { + exists>(broker) + } + + /// Check stake at address exists. + public fun exists_stake_at_address(account: address): bool { + exists>(account) + } +} +} \ No newline at end of file diff --git a/release/v13/sources/YieldFarmingV2.move b/release/v13/sources/YieldFarmingV2.move new file mode 100644 index 00000000..db8845bc --- /dev/null +++ b/release/v13/sources/YieldFarmingV2.move @@ -0,0 +1,492 @@ +// Copyright (c) The Starcoin Core Contributors +// SPDX-License-Identifier: Apache-2.0 + +address StarcoinFramework { +module YieldFarmingV2 { + use StarcoinFramework::Token; + use StarcoinFramework::Signer; + use StarcoinFramework::Timestamp; + use StarcoinFramework::Errors; + use StarcoinFramework::Math; + + const ERR_FARMING_INIT_REPEATE: u64 = 101; + const ERR_FARMING_NOT_STILL_FREEZE: u64 = 102; + const ERR_FARMING_STAKE_EXISTS: u64 = 103; + const ERR_FARMING_STAKE_NOT_EXISTS: u64 = 104; + const ERR_FARMING_HAVERST_NO_GAIN: u64 = 105; + const ERR_FARMING_TOTAL_WEIGHT_IS_ZERO: u64 = 106; + const ERR_EXP_DIVIDE_BY_ZERO: u64 = 107; + const ERR_FARMING_BALANCE_EXCEEDED: u64 = 108; + const ERR_FARMING_NOT_ENOUGH_ASSET: u64 = 109; + const ERR_FARMING_TIMESTAMP_INVALID: u64 = 110; + const ERR_FARMING_TOKEN_SCALE_OVERFLOW: u64 = 111; + const ERR_FARMING_CALC_LAST_IDX_BIGGER_THAN_NOW: u64 = 112; + const ERR_FARMING_NOT_ALIVE: u64 = 113; + const ERR_FARMING_ALIVE_STATE_INVALID: u64 = 114; + + const EXP_MAX_SCALE: u128 = 9; + + spec module { + pragma verify = false; + } + + ////////////////////////////////////////////////////////////////////// + // Exponential functions + + const EXP_SCALE: u128 = 1000000000000000000;// e18 + + struct Exp has copy, store, drop { + mantissa: u128 + } + + fun exp_direct(num: u128): Exp { + Exp { + mantissa: num + } + } + + fun exp_direct_expand(num: u128): Exp { + Exp { + mantissa: mul_u128(num, EXP_SCALE) + } + } + + + fun mantissa(a: Exp): u128 { + a.mantissa + } + + fun add_exp(a: Exp, b: Exp): Exp { + Exp { + mantissa: add_u128(a.mantissa, b.mantissa) + } + } + + fun exp(num: u128, denom: u128): Exp { + // if overflow move will abort + let scaledNumerator = mul_u128(num, EXP_SCALE); + let rational = div_u128(scaledNumerator, denom); + Exp { + mantissa: rational + } + } + + fun add_u128(a: u128, b: u128): u128 { + a + b + } + + fun sub_u128(a: u128, b: u128): u128 { + a - b + } + + fun mul_u128(a: u128, b: u128): u128 { + if (a == 0 || b == 0) { + return 0 + }; + a * b + } + + fun div_u128(a: u128, b: u128): u128 { + if (b == 0) { + abort Errors::invalid_argument(ERR_EXP_DIVIDE_BY_ZERO) + }; + if (a == 0) { + return 0 + }; + a / b + } + + fun truncate(exp: Exp): u128 { + return exp.mantissa / EXP_SCALE + } + + /// The object of yield farming + /// RewardTokenT meaning token of yield farming + struct Farming has key, store { + treasury_token: Token::Token, + } + + struct FarmingAsset has key, store { + asset_total_weight: u128, + harvest_index: u128, + last_update_timestamp: u64, + // Release count per seconds + release_per_second: u128, + // Start time, by seconds, user can operate stake only after this timestamp + start_time: u64, + // Representing the pool is alive, false: not alive, true: alive. + alive: bool, + } + + /// To store user's asset token + struct Stake has key, store { + asset: AssetT, + asset_weight: u128, + last_harvest_index: u128, + gain: u128, + } + + /// Capability to modify parameter such as period and release amount + struct ParameterModifyCapability has key, store {} + + /// Harvest ability to harvest + struct HarvestCapability has key, store { + trigger: address, + } + + /// Called by token issuer + /// this will declare a yield farming pool + public fun initialize< + PoolType: store, + RewardTokenT: store>(signer: &signer, treasury_token: Token::Token) { + let scaling_factor = Math::pow(10, (EXP_MAX_SCALE as u64)); + let token_scale = Token::scaling_factor(); + assert!(token_scale <= scaling_factor, Errors::limit_exceeded(ERR_FARMING_TOKEN_SCALE_OVERFLOW)); + assert!(!exists_at( + Signer::address_of(signer)), Errors::invalid_state(ERR_FARMING_INIT_REPEATE)); + + move_to(signer, Farming { + treasury_token, + }); + } + + /// Add asset pools + public fun add_asset( + signer: &signer, + release_per_second: u128, + delay: u64): ParameterModifyCapability { + assert!(!exists_asset_at( + Signer::address_of(signer)), + Errors::invalid_state(ERR_FARMING_INIT_REPEATE)); + + let now_seconds = Timestamp::now_seconds(); + + move_to(signer, FarmingAsset { + asset_total_weight: 0, + harvest_index: 0, + last_update_timestamp: now_seconds, + release_per_second, + start_time: now_seconds + delay, + alive: true + }); + ParameterModifyCapability {} + } + + /// Remove asset for make this pool to the state of not alive + /// Please make sure all user unstaking from this pool +// public fun remove_asset( +// broker: address, +// cap: ParameterModifyCapability) acquires FarmingAsset { +// let ParameterModifyCapability {} = cap; +// let FarmingAsset { +// asset_total_weight: _, +// harvest_index: _, +// last_update_timestamp: _, +// release_per_second: _, +// start_time: _, +// alive: _, +// } = move_from>(broker); +// } + + public fun modify_parameter( + _cap: &ParameterModifyCapability, + broker: address, + release_per_second: u128, + alive: bool) acquires FarmingAsset { + + // Not support to shuttingdown alive state. + assert!(alive, Errors::invalid_state(ERR_FARMING_ALIVE_STATE_INVALID)); + + let farming_asset = borrow_global_mut>(broker); + // assert!(farming_asset.alive != alive, Errors::invalid_state(ERR_FARMING_ALIVE_STATE_INVALID)); + + let now_seconds = Timestamp::now_seconds(); + + farming_asset.release_per_second = release_per_second; + farming_asset.last_update_timestamp = now_seconds; + + // if the pool is alive, then update index + if (farming_asset.alive) { + farming_asset.harvest_index = calculate_harvest_index_with_asset(farming_asset, now_seconds); + }; + farming_asset.alive = alive; + } + + /// Call by stake user, staking amount of asset in order to get yield farming token + public fun stake( + signer: &signer, + broker: address, + asset: AssetT, + asset_weight: u128, + _cap: &ParameterModifyCapability) acquires FarmingAsset { + let harvest_cap = stake_for_cap< + PoolType, + RewardTokenT, + AssetT>(signer, broker, asset, asset_weight, _cap); + + move_to(signer, harvest_cap); + } + + public fun stake_for_cap( + signer: &signer, + broker: address, + asset: AssetT, + asset_weight: u128, + _cap: &ParameterModifyCapability) + : HarvestCapability acquires FarmingAsset { + let account = Signer::address_of(signer); + assert!(!exists_stake_at_address(account), + Errors::invalid_state(ERR_FARMING_STAKE_EXISTS)); + + let farming_asset = borrow_global_mut>(broker); + assert!(farming_asset.alive, Errors::invalid_state(ERR_FARMING_NOT_ALIVE)); + + // Check locking time + let now_seconds = Timestamp::now_seconds(); + assert!(farming_asset.start_time <= now_seconds, Errors::invalid_state(ERR_FARMING_NOT_STILL_FREEZE)); + + let time_period = now_seconds - farming_asset.last_update_timestamp; + + if (farming_asset.asset_total_weight <= 0) { + // Stake as first user + let gain = farming_asset.release_per_second * (time_period as u128); + move_to(signer, Stake { + asset, + asset_weight, + last_harvest_index: 0, + gain, + }); + farming_asset.harvest_index = 0; + farming_asset.asset_total_weight = asset_weight; + } else { + let new_harvest_index = calculate_harvest_index_with_asset(farming_asset, now_seconds); + move_to(signer, Stake { + asset, + asset_weight, + last_harvest_index: new_harvest_index, + gain: 0, + }); + farming_asset.asset_total_weight = farming_asset.asset_total_weight + asset_weight; + farming_asset.harvest_index = new_harvest_index; + }; + farming_asset.last_update_timestamp = now_seconds; + HarvestCapability { trigger: account } + } + + /// Unstake asset from farming pool + public fun unstake( + signer: &signer, + broker: address) + : (AssetT, Token::Token) acquires HarvestCapability, Farming, FarmingAsset, Stake { + let account = Signer::address_of(signer); + let cap = move_from>(account); + unstake_with_cap(broker, cap) + } + + public fun unstake_with_cap( + broker: address, + cap: HarvestCapability) + : (AssetT, Token::Token) acquires Farming, FarmingAsset, Stake { + // Destroy capability + let HarvestCapability { trigger } = cap; + + let farming = borrow_global_mut>(broker); + let farming_asset = borrow_global_mut>(broker); + + let Stake { last_harvest_index, asset_weight, asset, gain } = + move_from>(trigger); + + let now_seconds = Timestamp::now_seconds(); + let new_harvest_index = calculate_harvest_index_with_asset(farming_asset, now_seconds); + + let period_gain = calculate_withdraw_amount(new_harvest_index, last_harvest_index, asset_weight); + let total_gain = gain + period_gain; + let withdraw_token = Token::withdraw(&mut farming.treasury_token, total_gain); + + // Dont update harvest index that because the `Stake` object has droped. + // let new_index = calculate_harvest_index_with_asset(farming_asset, now_seconds); + assert!(farming_asset.asset_total_weight >= asset_weight, Errors::invalid_state(ERR_FARMING_NOT_ENOUGH_ASSET)); + + // Update farm asset + farming_asset.asset_total_weight = farming_asset.asset_total_weight - asset_weight; + farming_asset.last_update_timestamp = now_seconds; + + if (farming_asset.alive) { + farming_asset.harvest_index = new_harvest_index; + }; + + (asset, withdraw_token) + } + + /// Harvest yield farming token from stake + public fun harvest( + signer: &signer, + broker: address, + amount: u128) : Token::Token acquires HarvestCapability, Farming, FarmingAsset, Stake { + let account = Signer::address_of(signer); + let cap = borrow_global_mut>(account); + harvest_with_cap(broker, amount, cap) + } + + public fun harvest_with_cap( + broker: address, + amount: u128, + _cap: &HarvestCapability): Token::Token acquires Farming, FarmingAsset, Stake { + let farming = borrow_global_mut>(broker); + let farming_asset = borrow_global_mut>(broker); + let stake = borrow_global_mut>(_cap.trigger); + + let now_seconds = Timestamp::now_seconds(); + let new_harvest_index = calculate_harvest_index_with_asset(farming_asset, now_seconds); + + let period_gain = calculate_withdraw_amount( + new_harvest_index, + stake.last_harvest_index, + stake.asset_weight + ); + + let total_gain = stake.gain + period_gain; + //assert!(total_gain > 0, Errors::limit_exceeded(ERR_FARMING_HAVERST_NO_GAIN)); + assert!(total_gain >= amount, Errors::limit_exceeded(ERR_FARMING_BALANCE_EXCEEDED)); + + let withdraw_amount = if (amount <= 0) { + total_gain + } else { + amount + }; + + let withdraw_token = Token::withdraw(&mut farming.treasury_token, withdraw_amount); + stake.gain = total_gain - withdraw_amount; + stake.last_harvest_index = new_harvest_index; + + if (farming_asset.alive) { + farming_asset.harvest_index = new_harvest_index; + }; + farming_asset.last_update_timestamp = now_seconds; + + withdraw_token + } + + /// The user can quering all yield farming amount in any time and scene + public fun query_gov_token_amount(account: address, broker: address): u128 acquires FarmingAsset, Stake { + let farming_asset = borrow_global_mut>(broker); + let stake = borrow_global_mut>(account); + let now_seconds = Timestamp::now_seconds(); + + let new_harvest_index = calculate_harvest_index_with_asset( + farming_asset, + now_seconds + ); + + let new_gain = calculate_withdraw_amount( + new_harvest_index, + stake.last_harvest_index, + stake.asset_weight + ); + stake.gain + new_gain + } + + /// Query total stake count from yield farming resource + public fun query_total_stake(broker: address): u128 acquires FarmingAsset { + let farming_asset = borrow_global_mut>(broker); + farming_asset.asset_total_weight + } + + /// Query stake weight from user staking objects. + public fun query_stake(account: address): u128 acquires Stake { + let stake = borrow_global_mut>(account); + stake.asset_weight + } + + /// Queyry pool info from pool type + /// return value: (alive, release_per_second, asset_total_weight, harvest_index) + public fun query_info(broker: address): (bool, u128, u128, u128) acquires FarmingAsset { + let asset = borrow_global_mut>(broker); + ( + asset.alive, + asset.release_per_second, + asset.asset_total_weight, + asset.harvest_index + ) + } + + /// Update farming asset + fun calculate_harvest_index_with_asset(farming_asset: &FarmingAsset, now_seconds: u64): u128 { + // Recalculate harvest index + if (farming_asset.asset_total_weight <= 0) { + calculate_harvest_index_weight_zero( + farming_asset.harvest_index, + farming_asset.last_update_timestamp, + now_seconds, + farming_asset.release_per_second + ) + } else { + calculate_harvest_index( + farming_asset.harvest_index, + farming_asset.asset_total_weight, + farming_asset.last_update_timestamp, + now_seconds, + farming_asset.release_per_second + ) + } + } + + /// There is calculating from harvest index and global parameters without asset_total_weight + public fun calculate_harvest_index_weight_zero(harvest_index: u128, + last_update_timestamp: u64, + now_seconds: u64, + release_per_second: u128): u128 { + assert!(last_update_timestamp <= now_seconds, Errors::invalid_argument(ERR_FARMING_TIMESTAMP_INVALID)); + let time_period = now_seconds - last_update_timestamp; + let addtion_index = release_per_second * ((time_period as u128)); + harvest_index + mantissa(exp_direct_expand(addtion_index)) + } + + /// There is calculating from harvest index and global parameters + public fun calculate_harvest_index(harvest_index: u128, + asset_total_weight: u128, + last_update_timestamp: u64, + now_seconds: u64, + release_per_second: u128): u128 { + assert!(asset_total_weight > 0, Errors::invalid_argument(ERR_FARMING_TOTAL_WEIGHT_IS_ZERO)); + assert!(last_update_timestamp <= now_seconds, Errors::invalid_argument(ERR_FARMING_TIMESTAMP_INVALID)); + + let time_period = now_seconds - last_update_timestamp; + let numr = (release_per_second * (time_period as u128)); + let denom = asset_total_weight; + harvest_index + mantissa(exp(numr, denom)) + } + + /// This function will return a gain index + public fun calculate_withdraw_amount(harvest_index: u128, + last_harvest_index: u128, + asset_weight: u128): u128 { + assert!(harvest_index >= last_harvest_index, Errors::invalid_argument(ERR_FARMING_CALC_LAST_IDX_BIGGER_THAN_NOW)); + let amount = asset_weight * (harvest_index - last_harvest_index); + truncate(exp_direct(amount)) + } + + /// Check the Farming of TokenT is exists. + public fun exists_at(broker: address): bool { + exists>(broker) + } + + /// Check the Farming of AsssetT is exists. + public fun exists_asset_at(broker: address): bool { + exists>(broker) + } + + /// Check stake at address exists. + public fun exists_stake_at_address(account: address): bool { + exists>(account) + } +} +} \ No newline at end of file diff --git a/sources/Block.move b/sources/Block.move index 87b08948..b90033d9 100644 --- a/sources/Block.move +++ b/sources/Block.move @@ -1,6 +1,7 @@ address StarcoinFramework { /// Block module provide metadata for generated blocks. module Block { + use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::Event; use StarcoinFramework::Timestamp; use StarcoinFramework::Signer; @@ -27,6 +28,8 @@ module Block { author: address, /// number of uncles. uncles: u64, + /// Hash of the parents hash for a Dag block. + parents_hash: Option::Option>, /// Handle of events when new blocks are emitted new_block_events: Event::EventHandle, } @@ -37,6 +40,7 @@ module Block { author: address, timestamp: u64, uncles: u64, + parents_hash: Option::Option>, } // @@ -75,9 +79,10 @@ module Block { account, BlockMetadata { number: 0, - parent_hash: parent_hash, + parent_hash, author: CoreAddresses::GENESIS_ADDRESS(), uncles: 0, + parents_hash: Option::none>(), new_block_events: Event::new_event_handle(account), }); } @@ -106,6 +111,14 @@ module Block { aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); } + public fun get_parents_hash(): Option::Option> acquires BlockMetadata { + *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parents_hash + } + + spec get_parents_hash { + aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); + } + /// Gets the address of the author of the current block public fun get_current_author(): address acquires BlockMetadata { borrow_global(CoreAddresses::GENESIS_ADDRESS()).author @@ -116,23 +129,26 @@ module Block { } /// Call at block prologue - public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64) acquires BlockMetadata{ + public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option>) acquires BlockMetadata{ CoreAddresses::assert_genesis_address(account); let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH)); + assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH)); block_metadata_ref.number = number; block_metadata_ref.author= author; block_metadata_ref.parent_hash = parent_hash; block_metadata_ref.uncles = uncles; + block_metadata_ref.parents_hash = parents_hash; Event::emit_event( &mut block_metadata_ref.new_block_events, NewBlockEvent { - number: number, - author: author, - timestamp: timestamp, - uncles: uncles, + number, + author, + timestamp, + uncles, + parents_hash, } ); } diff --git a/sources/FlexiDagConfig.move b/sources/FlexiDagConfig.move new file mode 100644 index 00000000..98b93b0d --- /dev/null +++ b/sources/FlexiDagConfig.move @@ -0,0 +1,52 @@ +address StarcoinFramework { + module FlexiDagConfig { + + use StarcoinFramework::Config; + use StarcoinFramework::CoreAddresses; + use StarcoinFramework::Signer; + + spec module { + pragma verify = false; + pragma aborts_if_is_strict; + } + + /// The struct to hold all config data needed for Flexidag. + struct FlexiDagConfig has copy, drop, store { + // todo: double check, epoch might be better? + // the height of dag genesis block + effective_height: u64, + } + + /// Create a new configuration for flexidag, mainly used in DAO. + public fun new_flexidag_config(effective_height: u64): FlexiDagConfig { + FlexiDagConfig { + effective_height, + } + } + + public fun initialize(account: &signer, effective_height: u64) { + CoreAddresses::assert_genesis_address(account); + if (!Config::config_exist_by_address(Signer::address_of(account))) { + Config::publish_new_config(account, new_flexidag_config(effective_height)) + } + } + + spec initialize { + aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + ensures exists>(Signer::address_of(account)); + ensures + exists>( + Signer::address_of(account), + ); + } + + public fun effective_height(account: address): u64 { + let flexi_dag_config = Config::get_by_address(account); + flexi_dag_config.effective_height + } + + spec effective_height { + include Config::AbortsIfConfigNotExist { addr: account }; + } + } +} diff --git a/sources/Genesis.move b/sources/Genesis.move index ddf9f365..b53099c0 100644 --- a/sources/Genesis.move +++ b/sources/Genesis.move @@ -2,6 +2,8 @@ address StarcoinFramework { /// The module for init Genesis module Genesis { + use StarcoinFramework::Math::u64_max; + use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::CoreAddresses; use StarcoinFramework::Account; use StarcoinFramework::Signer; @@ -402,6 +404,7 @@ module Genesis { Option::some(0u64), ); BlockReward::initialize(&genesis_account, reward_delay); + FlexiDagConfig::initialize(&genesis_account, u64_max()); // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init. let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay); @@ -447,6 +450,7 @@ module Genesis { }; StdlibUpgradeScripts::do_upgrade_from_v6_to_v7_with_language_version(&genesis_account, 6); StdlibUpgradeScripts::do_upgrade_from_v11_to_v12(&genesis_account); + StdlibUpgradeScripts::do_upgrade_from_v12_to_v13(&genesis_account); //Start time, Timestamp::is_genesis() will return false. this call should at the end of genesis init. Timestamp::set_time_has_started(&genesis_account); Account::release_genesis_signer(genesis_account); diff --git a/sources/OnChainConfigScripts.move b/sources/OnChainConfigScripts.move index 4ce105e9..7bc0bc29 100644 --- a/sources/OnChainConfigScripts.move +++ b/sources/OnChainConfigScripts.move @@ -1,5 +1,6 @@ address StarcoinFramework { module OnChainConfigScripts { + use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::ConsensusConfig; use StarcoinFramework::OnChainConfigDao; use StarcoinFramework::STC; @@ -119,6 +120,15 @@ module OnChainConfigScripts { pragma verify = false; } + public entry fun propose_update_flexi_dag_effective_height(account: signer, new_height: u64, exec_delay: u64) { + let config = FlexiDagConfig::new_flexidag_config(new_height); + OnChainConfigDao::propose_update(&account, config, exec_delay); + } + + spec propose_update_flexi_dag_effective_height { + pragma verify = false; + } + public entry fun execute_on_chain_config_proposal(account: signer, proposal_id: u64) { OnChainConfigDao::execute(Signer::address_of(&account), proposal_id); } diff --git a/sources/STC.move b/sources/STC.move index 92fc837d..15ab8e8f 100644 --- a/sources/STC.move +++ b/sources/STC.move @@ -2,6 +2,7 @@ address StarcoinFramework { /// STC is the token of Starcoin blockchain. /// It uses apis defined in the `Token` module. module STC { + use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::Token::{Self, Token}; use StarcoinFramework::Dao; use StarcoinFramework::ModifyDaoConfigProposal; @@ -122,6 +123,7 @@ module STC { OnChainConfigDao::plugin(account); OnChainConfigDao::plugin(account); OnChainConfigDao::plugin(account); + OnChainConfigDao::plugin(account); withdraw_cap } diff --git a/sources/StdlibUpgradeScripts.move b/sources/StdlibUpgradeScripts.move index 2218b334..2e34de74 100644 --- a/sources/StdlibUpgradeScripts.move +++ b/sources/StdlibUpgradeScripts.move @@ -2,6 +2,8 @@ address StarcoinFramework { /// The module for StdlibUpgrade init scripts module StdlibUpgradeScripts { + use StarcoinFramework::Math::u64_max; + use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::EasyGas; use StarcoinFramework::CoreAddresses; use StarcoinFramework::STC::{Self, STC}; @@ -117,5 +119,14 @@ module StdlibUpgradeScripts { Block::checkpoints_init(sender); }; } + + public entry fun upgrade_from_v12_to_v13(sender: signer) { + do_upgrade_from_v12_to_v13(&sender); + } + public fun do_upgrade_from_v12_to_v13(sender: &signer) { + { + FlexiDagConfig::initialize(sender, u64_max()); + }; + } } } \ No newline at end of file diff --git a/sources/TransactionManager.move b/sources/TransactionManager.move index f0426453..a26498c4 100644 --- a/sources/TransactionManager.move +++ b/sources/TransactionManager.move @@ -3,6 +3,7 @@ address StarcoinFramework { /// 1. prologue and epilogue of transactions. /// 2. prologue of blocks. module TransactionManager { + use StarcoinFramework::Option; use StarcoinFramework::Authenticator; use StarcoinFramework::Account::{exists_at, is_signer_delegated, transaction_fee_simulate, balance, Account, Balance @@ -225,6 +226,7 @@ module TransactionManager { number: u64, chain_id: u8, parent_gas_used: u64, + parents_hash: Option::Option>, ) { // Can only be invoked by genesis account CoreAddresses::assert_genesis_address(&account); @@ -244,6 +246,7 @@ module TransactionManager { timestamp, uncles, number, + parents_hash, ); let reward = Epoch::adjust_epoch(&account, number, timestamp, uncles, parent_gas_used); // pass in previous block gas fees. From 3daa0ec69e4ae13c29a9f54b465196e395cb8adc Mon Sep 17 00:00:00 2001 From: simonjiao Date: Thu, 25 Jan 2024 17:31:52 +0800 Subject: [PATCH 2/9] rebuild new release --- build/StarcoinFramework/BuildInfo.yaml | 2 +- .../bytecode_modules/StdlibUpgradeScripts.mv | Bin 2199 -> 2195 bytes .../docs/StdlibUpgradeScripts.md | 1 - .../source_maps/FlexiDagConfig.mvsm | Bin 1368 -> 1368 bytes .../source_maps/StdlibUpgradeScripts.mvsm | Bin 7177 -> 7093 bytes release/StarcoinFramework.v0.1.0.blob | Bin 114284 -> 114280 bytes release/v13/BuildInfo.yaml | 2 +- .../v13/bytecode_modules/FlexiDagConfig.mv | Bin 326 -> 399 bytes release/v13/bytecode_modules/Genesis.mv | Bin 3391 -> 3439 bytes .../bytecode_modules/StdlibUpgradeScripts.mv | Bin 2199 -> 2195 bytes release/v13/docs/FlexiDagConfig.md | 10 ++++------ release/v13/docs/Genesis.md | 3 +++ release/v13/docs/StdlibUpgradeScripts.md | 1 - release/v13/source_maps/FlexiDagConfig.mvsm | Bin 1116 -> 1368 bytes release/v13/source_maps/Genesis.mvsm | Bin 25235 -> 25361 bytes .../v13/source_maps/StdlibUpgradeScripts.mvsm | Bin 7177 -> 7093 bytes release/v13/sources/FlexiDagConfig.move | 9 +++------ release/v13/sources/Genesis.move | 3 +++ release/v13/sources/StdlibUpgradeScripts.move | 1 - 19 files changed, 15 insertions(+), 17 deletions(-) diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index 19cd449d..c0d3580a 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: D44931F7D1A422F556EC2F1A0AC206D39AB15F0F8669C202ED2BFCBD020CB302 + source_digest: E203083CDEA5D40EEA2400D1D89CE602FF1778668B8DC34A0672D1EFCB44A57E build_flags: dev_mode: false test_mode: false diff --git a/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv b/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv index 86dbbec48c8d76bb2d444b2814bf40508a906a82..c98c9deabd1956ad445e3cf0cca5bfe4c4e6d79c 100644 GIT binary patch delta 25 gcmbO(I9YIl4&&{Ox(4j*EZhu&f`USuGuZVR0a!8xrvLx| delta 29 kcmbO%I9+gp4&(iex(4jrY+MY2f`UTa41xliQ`q$x0c%wS*Z=?k diff --git a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md index 358ba2c9..fbfd1432 100644 --- a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md +++ b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md @@ -402,7 +402,6 @@ deprecated, use do_upgrade_from_v6_to_v7_with_language_version.
public fun do_upgrade_from_v12_to_v13(sender: &signer) {
     {
         FlexiDagConfig::initialize(sender, u64_max());
-        Block::checkpoints_init(sender);
     };
 }
 
diff --git a/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm b/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm index 54039ad5cf8f753a09ca27ac5390e28f5bf33bfe..ccefaa8ff24ae7b25d0b4454af09088c53fa63db 100644 GIT binary patch literal 1368 zcmb8vu}cDB7{~GVJoQQ=Y>bEqho+hoT3S*Z4k8Gu@s#WCyeNe_MWW4rAh)7LD6p+1 z3<`?2{(_*fwf=(!>H7vk+j9xO$0ooMI6gM>VhOhIbPos<$!+o zBpFM-B4ccHmFrk1DiL?oCA3X)p6`2Z6t+F5?u9{JyrXT3JiU~fl1JSK4v0MJ6Vwfn zM?FHNlKKTokKzlNM#`gpL|Vv{*z*CYby}1|RF|HXC@ZK9G9gMAbxbBjxrvHMMwD}? r7Ricoe4-eabjDxA72&7+-v@S0*_|$B8F5SBm<)rKAJ{u`7OB(^`3Cur literal 1368 zcmb8vKS%;$7{~GVPR}ciurX?B3fhCnO~oOIrsm@~?;nW{ofS=ia}YGSL{M2nqXZRg zjnNhq(biUr5Dg8{_YH)$=MsLCpXYhs_jz9(>^7?Vmp9L!=h4T`T`97=?)}>9pgZmM z9-WuM`>axGo*3ls#~80Q{H?g^hLu(`h(o>~2(8+fj_zYfa>7(ad0 zd98Lck(!s#WnvTqeFCTMhK~1p2C1@6Rif9j!HaQOfL diff --git a/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm b/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm index 60eb9a5c2b2c54d96f13b5be183ab965c24e1b41..b412aa7e9a5aef97b3d73ab2ebc95c03a6159aa4 100644 GIT binary patch literal 7093 zcmb7}TWpj?7=~wiKA&i-2t@%EC>jy1M!^Fqm5Px{s+^y7bvdv!_ATU zN7|ZVp|Drm5R0_=ag%GzDN%7wu`v~30%>tC8unspz-`DYA&?#lhhttmt_B=K{?tAp zPtT?kugeyf^X|qv3`x>#!Ww{NX%1uk0x8l=yi=+)^Gl2=fi!6@#aa&O(yYd+fedLr zg!L$7O0xyahb(E%utM#a+0yLAIt)3|?7Y-5gq^D?}S{FWWy(y`|er$8^m=U9J&UWU>f zW9EWhhGeWV&>g!0s}Xd^-jCG;x?{Vr_JZ!%cC3A%JGPNMyBT!HzCpcTL3ivH>g@vE zv6)z_KzD2n)*jFuYpuQD@NpLA8?ywQqgsx<%noqr*bc;PprhJ}wF7iitFd;1j;ghG zfkRgN(2iR*$?;778u=s?G>4*1?V%>omM_QxmY(B%F-|dsgo80m03XFLi^!l}9 zb%9>L4Orcv*Y7T@9?-2`UPvfFxB5Bi-HfSQeGk@t(5+sN^&IF{x7Go0nCQ|XV=BS9 zF;*k5g+Ovcs7<9{GvZcTJxhn+MZ8yRVHuZBtUk~oNIYMM;1u<~108}Nu*N`#;9ab< zphHkG%a|3QLr{jb5_AaGVMRgj_uH_xgTq9V_#o$ljZ35{s=w4PKwb=i^w!2kFXn|+ zWGa!@+9zj?6gL1n9`TgEa{{GRs-X zJ3vP!6YEaUk*UUNgFLzN)_M{gCfZL12W<{rZ;V68AKL+ZT5=*&h%=zW@-5ay&|$IG z-{7#eqg*X6T)tj79=(4c|78cbyxa|ZW4{IT%N1hX3i{=&RRIohC{H!!9xzGip@xRm z_NcE~_g?HZP~f-vq2^%RZwQ83Tn4UZPzW++HAkXeC>HF9_#4BqP)E?=JUWohy%927 zB2hp1gtuA##!!@I%p6FwBlPZd67@7BM_W7864Wyh57OGaSfo{MjOQr(8)U`(P|Oed zkrq!q;d}I-A@%YiEBiR+H<0sxR&e?V{7iMQ9=^}{UeHqhJkJgn`Yx9dbU^>+Ox^*#iBqZ`B;0)3-<3F{c>8{HJv zY=W+Dbcu}XV0<_YSJ zL#Z@>#F~IBq&bOo0j`v$t!M4o(wxGYhO4A`2`iAno-EB2tUQ=2%_OX3D3j(4PrnHB zq!kS@)^507 znq64kut=IWV)ejcX`zUuUrmRRN9+L3FgcMV{(+GR`d~au$t+BV z{rM)e)mC+#auxCeb^u4Dobo}$UeHtS!+I6;S>Axv5Be;()*)~>d_LfJkP-V^i0d+Z eg?z#eaQWVy!u38I^fF9PG6z#HgSB$On12B==3pEE literal 7177 zcmb7}eN2^A9LLY){Z-xs^94<_RH#)JZKW-nvdEU?sKxrD>y`Tecfp13eTXy>-++d- z5&Y9~ix4HvP=h)_>m<+vmT}InQ~1&-eMA zdmaW(9d0~SpFdL8yI}7}yEgBh^K##w^1@Z;k8P^xKR9=B$9iLo2Lbr+Utng9A8v|l ze4@1>77BYcb+JgRA2+$i42T)$&NQY1Odu`pMZ;c94Y&t+B?Qt#;c(20$JKzN$e-CO z%+Rap#Otz?%XN2S?S~|3HeiiFvNXrAeufljChjR!nt8>>6hoRc%dwV2x-_e>sv$#~ zk6}FtnbK^=@*zu_SEx`MX0|j3vGzlbG<&c{AXl1)vEB!Vh}4uA(+tkhjw1VZ08dLU zWEAmZ&{6#q>r2p49mE<39o0Xvra?#b4Axc9QO%jf0|1AG_GKG$0GvyE5czF8z@-aZ zLYx9!+Rw560A1RW9AoBzE^RVaDd^H}z^Vsb+J~_kKzD&ItlglyKpWOepu0dl`#=-u zF7Ouf{Q|lRyuf@rKzD&mtOr4NfoiN?&|SbMtZvZtyC16u^s8Q0Kqx@J>KB;rPE7r(_hR*de$_W( zy#o4Gw^lzmEVR7PnAPC?Vyr=43xVXiP^(J8Cd4gv_ADKO*YMu36U(@CVhw=~LE`#4 z1gDtqd(a{H0qZR25WI(V4s-}Aii}wSIs~OyD?x`~9aa={zwf}>3JwcR;z2G18<$8! zR38);AuokMdP{x17xTg@GOLl-+AFZ3D|a*Ac00K=cVZ2Lj?AN2`#?t~u~HqG)691k zbYv#5CP7E$U95|sBeR@J-U~W1nOOIMj!YF+E6k9Ux7M@Zu+U*LIBIj~dI~*){D~dF z(~=9BLc9VxEZ<^HgAR+eu7X2tPjg(keErDcxb^;y{Ffcza&x!x+x{-lH&=jlH|U$Q zRs}f3p)A#y2f!qyhwAED+M>RCbys0O1o?i8A8HE5{kmYN*=68*28AG_s3{WlLa|_b z#BU78LhV6^{ir{kvnXUXN1}f48E=#PZc)e~a4w|T5xRSwMEwquqb=>K1RGh12WhQd zEYczy;{~Su6|&-fDCP(KNVBJ|a0dN6q+TzwvX5ha13CYvqN6;DF)+*Y8~8fj2hE%I+0D?t`9NahoDb% zqgY2kpXl~r9R+=&o5Gq+(DjKfk#W7PB%+-s`+nk;%$H{31t^eaC3mw93Z=OOs~U== z*@(3bW=b>BIEtltg83$(M4CTgO~Nc`Uc|Z#H%QaYXYJY2oWlAW=1B7zRv?3(EX@?G z88AD}7c7)!H&#C^l4dQ|0NfddSIzEt@R=}w8eM$%yi6tYI6N)I)*%M2e609 zg(UG$kxbAV<2k0x!gT1*x1+7Gs_T*~ksq-G*dpbUUqu`Qz2qURy`cB&Pd%3mt rfy3tW0pCH!?Y9uuGJJ)6!VYlx-JQbmJ{xoyCYdq^QN4Km?%>O4z|PLX%^)Z!D73vggz;l00501MxBvhE delta 44 zcmaFyhwaTDwuUW?g1(H?rwjQq>N4Kn?%>O4z|PIa#ULmsD8$VmD6qXegz;l009d;W A?EnA( diff --git a/release/v13/BuildInfo.yaml b/release/v13/BuildInfo.yaml index f8c5d3a0..c0d3580a 100644 --- a/release/v13/BuildInfo.yaml +++ b/release/v13/BuildInfo.yaml @@ -5,7 +5,7 @@ compiled_package_info: StarcoinAssociation: "0x0000000000000000000000000a550c18" StarcoinFramework: "0x00000000000000000000000000000001" VMReserved: "0x00000000000000000000000000000000" - source_digest: DAD01288B0F425AF6BF3F9B3EB48FD863E6736AC99B2C8B99B0C73C848ACE126 + source_digest: E203083CDEA5D40EEA2400D1D89CE602FF1778668B8DC34A0672D1EFCB44A57E build_flags: dev_mode: false test_mode: false diff --git a/release/v13/bytecode_modules/FlexiDagConfig.mv b/release/v13/bytecode_modules/FlexiDagConfig.mv index 50363aad2d38813b79e3db9110a7ffe10a62642e..4845bb9b88b05bde7823d7d610c46fb572c844bc 100644 GIT binary patch delta 245 zcmWlTy-EX75QWc~xqrF$8WRyjw6L=fY~98*K7x>TG07%uvw^IIRz88q7M2$J625`Y zAz1nnUW)_g4ByP0FL}|Y_tW3x07N24Fq$vSm9y8!e*VeuER*;qHh;)$?^~o`gg^lg znBrlj1jph%EWHG$&{4U^2v5%xlwOT9-q2FTWd#E`0$nD>4c)nSx9z5DcEjuZB;Ku7 zyQc5!?fPiB?bhw4ZXVkHzFs^IKbJSAY?seIp+e@E6C4W5ME4`6rpQ)2GdUq~DwWuA N0!97-O*kmkfj^|H9ccgn delta 177 zcmWlSI}QP16ot>Z_kWlNL4jfl)f5U*>ODHGUV%&^v^pygCR3;_z&0$v5;O{%@N3R1 zUve(`l+!)?CJsPMIB`bfz8M%h?E2Z6wHKT5n>PJ$RKJM?j0oxh4GBgRur#0x=Eb`( z*SylJv4)l^F8xnn6qq!$2#xt}eJrM{?c}iE6y>#3K9*I^oLVi|%Y2NMNszE5V~T_q J)dcPTEq-Sz6e<7! diff --git a/release/v13/bytecode_modules/Genesis.mv b/release/v13/bytecode_modules/Genesis.mv index 97508566d043a0348306b8dcb0f25bbf29d2f4f0..78659547354e59fd73b0d53c4a14b6e126b99573 100644 GIT binary patch delta 788 zcmY*X%Wl(95S_8FAMtf=ebdHn-f`Y>Y$s{c5*~#>OL>WJKv_VkL}62;u88;o1W^|( zSaeAx7AWeP4`9aHqbLQ%P$p6U4C&jN^2Y?j9M461#!xM!a zt3~a-`b#n1>EBZ3Ysb;wI?vHQmB%mRtr?V|f(-`PWKd|?2$;zj;CYO)LObD=iUE#e zAb_`%aPNA8P^AE0A*dliov7QPEY(Gt7BCH5Uq@g*b(#q%zKM|Y$y&*`5c0`iW9D-N z?$g9nkNPTMT7VucAsRA92b{jlAjrWof|}GX4KWRNl4a^ES->?Lky%N5VclCrwlcCw zd?QC+3!C`@;khE^#c_#nHK{9~FIUL^1)Ka|^l=7wsY-myu7U9D2+NnLDD5{8vR6nZ zJ0Y6AO5k22z-^7PU93RHZy|U$+9c}Tv^#{ix&h(s9w}*eXaklJE9tyjbjxnVt-8Kj zch=l>cjRukn_-};j4{<(e8!)+Bz7O&Kic1!?rlGL{9u1?{!y)K?C$jN;o`e071MaS zIl6Z+JzD(M&J;YEpP8?!(vzzq;tFr_7H{*8%-KT`jTO`fSnQvH!Seu_( zL24*M+99MJzF1AI#QS5GY%?$NPPbvxsJ~VsvJ#NBuIO@|taXWpBodNHAp460{t5p8 Dj;UW5 delta 728 zcmY*XJCD;q5T3Euuk2>yy~MtA9=CZXc5ElPJ0QRv?^nTZphF-k3Ob5FMR_`0Pys^x zgov77fP^S%u0^7_9wEV4qG6=@^nLcselzx-H9t4=5AC1a1^^G?&^SCWpT05JE3<8V zG=Ce;d;6>Bp4EK&Pwgd&7wY&VKU!m-0S*{MLxF(4??4bRV$rD7osI)iItUP4FLiLE zMA)SSZ4h*kphvPXCgx3$PMb0d8rnu+nmXMQ4DBLpYZ|MiD+oK~TSs$*HP>{a7gJv+ zsYn z>oG!bYeJ^MZ80Uh6DNdsXXIqvqq*6ZY*cr`X4nop;clqIp1%l};a<2O9&AqW7ZyLv z!NzCG*u?fH1K$;=?&~Hu_=u1BgiqDBSjuc=$Qfm(qT<90CJ(AhZmvwRkTccdixsP| zJ^I7{#gIKIzIf5PE8UgbWzVU(FLIf4R}FZshSb^@iA=adIw75@kw|66Q#B?&k(mSb zqw?ZVIH;yFv;QejF;yg#Gs=`_D&sSi8MG~oj#1^zv@H5;WfTu9&#+s3uO!}FrnEy! vJ5>3|YVrAsmD?2e`84i}jI7I1G8!eJ(P9~Mn{-S%C6km)5|wS<@^APTJhxGn diff --git a/release/v13/bytecode_modules/StdlibUpgradeScripts.mv b/release/v13/bytecode_modules/StdlibUpgradeScripts.mv index 86dbbec48c8d76bb2d444b2814bf40508a906a82..c98c9deabd1956ad445e3cf0cca5bfe4c4e6d79c 100644 GIT binary patch delta 25 gcmbO(I9YIl4&&{Ox(4j*EZhu&f`USuGuZVR0a!8xrvLx| delta 29 kcmbO%I9+gp4&(iex(4jrY+MY2f`UTa41xliQ`q$x0c%wS*Z=?k diff --git a/release/v13/docs/FlexiDagConfig.md b/release/v13/docs/FlexiDagConfig.md index 0e7f2888..81441e26 100644 --- a/release/v13/docs/FlexiDagConfig.md +++ b/release/v13/docs/FlexiDagConfig.md @@ -14,6 +14,7 @@
use 0x1::Config;
 use 0x1::CoreAddresses;
+use 0x1::Signer;
 
@@ -90,7 +91,9 @@ Create a new configuration for flexidag, mainly used in DAO.
public fun initialize(account: &signer, effective_height: u64) {
     CoreAddresses::assert_genesis_address(account);
-    Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height))
+    if (!Config::config_exist_by_address<FlexiDagConfig>(Signer::address_of(account))) {
+        Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height))
+    }
 }
 
@@ -104,11 +107,6 @@ Create a new configuration for flexidag, mainly used in DAO.
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-aborts_if exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
-aborts_if
-    exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(
-        Signer::address_of(account),
-    );
 ensures exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
 ensures
     exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(
diff --git a/release/v13/docs/Genesis.md b/release/v13/docs/Genesis.md
index 6d449dab..1f9b39c3 100644
--- a/release/v13/docs/Genesis.md
+++ b/release/v13/docs/Genesis.md
@@ -24,8 +24,10 @@ The module for init Genesis
 use 0x1::CoreAddresses;
 use 0x1::DummyToken;
 use 0x1::Epoch;
+use 0x1::FlexiDagConfig;
 use 0x1::GenesisNFT;
 use 0x1::GenesisSignerCapability;
+use 0x1::Math;
 use 0x1::Option;
 use 0x1::PackageTxnManager;
 use 0x1::STC;
@@ -464,6 +466,7 @@ The module for init Genesis
         Option::some(0u64),
     );
     BlockReward::initialize(&genesis_account, reward_delay);
+    FlexiDagConfig::initialize(&genesis_account, u64_max());
 
     // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init.
     let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay);
diff --git a/release/v13/docs/StdlibUpgradeScripts.md b/release/v13/docs/StdlibUpgradeScripts.md
index 358ba2c9..fbfd1432 100644
--- a/release/v13/docs/StdlibUpgradeScripts.md
+++ b/release/v13/docs/StdlibUpgradeScripts.md
@@ -402,7 +402,6 @@ deprecated, use do_upgrade_from_v6_to_v7_with_language_version.
 
public fun do_upgrade_from_v12_to_v13(sender: &signer) {
     {
         FlexiDagConfig::initialize(sender, u64_max());
-        Block::checkpoints_init(sender);
     };
 }
 
diff --git a/release/v13/source_maps/FlexiDagConfig.mvsm b/release/v13/source_maps/FlexiDagConfig.mvsm index 16fe85326ce572e177b817932374391cb3afc167..ccefaa8ff24ae7b25d0b4454af09088c53fa63db 100644 GIT binary patch literal 1368 zcmb8vu}cDB7{~GVJoQQ=Y>bEqho+hoT3S*Z4k8Gu@s#WCyeNe_MWW4rAh)7LD6p+1 z3<`?2{(_*fwf=(!>H7vk+j9xO$0ooMI6gM>VhOhIbPos<$!+o zBpFM-B4ccHmFrk1DiL?oCA3X)p6`2Z6t+F5?u9{JyrXT3JiU~fl1JSK4v0MJ6Vwfn zM?FHNlKKTokKzlNM#`gpL|Vv{*z*CYby}1|RF|HXC@ZK9G9gMAbxbBjxrvHMMwD}? r7Ricoe4-eabjDxA72&7+-v@S0*_|$B8F5SBm<)rKAJ{u`7OB(^`3Cur literal 1116 zcmea?(Y=Vd;#o<^HB)~pHZ!g}4R?%q!YT_tx}Mu35~J&+&cMK63dD>+j0_n0+;UPY zGF=kWo%8e3GSh+b-UN&)1*&NVnZrm(r63angCYPfSkEFU>0< zWcWUy>Z3r+D3Av7L3~PLdVDh24}^3+2kQC`vWu0lyA;_O7&L&Gkzla=0-C4^RLMk8 zCCq+if-22{=D7ng3sEW~fGUY_s0A=OoPd~tiP)fa2CDV~Vu94OwAAF1%(B$@jMU8Z z41#eK3e=PevWfv1IE12Q0Z`#`ASN8tRX|lMfS7PlKLo0J0mOuZ`X5jg9}6)-{R*g( zAE=U*ppUizRSE!A65-GZz-+P@h=IwO)IeSW)V2kr6=)4XC;bAd;Q~5~a3J3Vs+0t( HWMBXQ$1!}b diff --git a/release/v13/source_maps/Genesis.mvsm b/release/v13/source_maps/Genesis.mvsm index 41d1e279bdb026d066772bdf372151237ece8bbc..666697f9d8888c8e4b77e2cbc80520446aca0537 100644 GIT binary patch literal 25361 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 literal 7177 zcmb7}eN2^A9LLY){Z-xs^94<_RH#)JZKW-nvdEU?sKxrD>y`Tecfp13eTXy>-++d- z5&Y9~ix4HvP=h)_>m<+vmT}InQ~1&-eMA zdmaW(9d0~SpFdL8yI}7}yEgBh^K##w^1@Z;k8P^xKR9=B$9iLo2Lbr+Utng9A8v|l ze4@1>77BYcb+JgRA2+$i42T)$&NQY1Odu`pMZ;c94Y&t+B?Qt#;c(20$JKzN$e-CO z%+Rap#Otz?%XN2S?S~|3HeiiFvNXrAeufljChjR!nt8>>6hoRc%dwV2x-_e>sv$#~ zk6}FtnbK^=@*zu_SEx`MX0|j3vGzlbG<&c{AXl1)vEB!Vh}4uA(+tkhjw1VZ08dLU zWEAmZ&{6#q>r2p49mE<39o0Xvra?#b4Axc9QO%jf0|1AG_GKG$0GvyE5czF8z@-aZ zLYx9!+Rw560A1RW9AoBzE^RVaDd^H}z^Vsb+J~_kKzD&ItlglyKpWOepu0dl`#=-u zF7Ouf{Q|lRyuf@rKzD&mtOr4NfoiN?&|SbMtZvZtyC16u^s8Q0Kqx@J>KB;rPE7r(_hR*de$_W( zy#o4Gw^lzmEVR7PnAPC?Vyr=43xVXiP^(J8Cd4gv_ADKO*YMu36U(@CVhw=~LE`#4 z1gDtqd(a{H0qZR25WI(V4s-}Aii}wSIs~OyD?x`~9aa={zwf}>3JwcR;z2G18<$8! zR38);AuokMdP{x17xTg@GOLl-+AFZ3D|a*Ac00K=cVZ2Lj?AN2`#?t~u~HqG)691k zbYv#5CP7E$U95|sBeR@J-U~W1nOOIMj!YF+E6k9Ux7M@Zu+U*LIBIj~dI~*){D~dF z(~=9BLc9VxEZ<^HgAR+eu7X2tPjg(keErDcxb^;y{Ffcza&x!x+x{-lH&=jlH|U$Q zRs}f3p)A#y2f!qyhwAED+M>RCbys0O1o?i8A8HE5{kmYN*=68*28AG_s3{WlLa|_b z#BU78LhV6^{ir{kvnXUXN1}f48E=#PZc)e~a4w|T5xRSwMEwquqb=>K1RGh12WhQd zEYczy;{~Su6|&-fDCP(KNVBJ|a0dN6q+TzwvX5ha13CYvqN6;DF)+*Y8~8fj2hE%I+0D?t`9NahoDb% zqgY2kpXl~r9R+=&o5Gq+(DjKfk#W7PB%+-s`+nk;%$H{31t^eaC3mw93Z=OOs~U== z*@(3bW=b>BIEtltg83$(M4CTgO~Nc`Uc|Z#H%QaYXYJY2oWlAW=1B7zRv?3(EX@?G z88AD}7c7)!H&#C^l4dQ|0NfddSIzEt@R=}w8eM$%yi6tYI6N)I)*%M2e609 zg(UG$kxbAV<2k0x!gT1*x1+7Gs_T*~ksq-G*dpbUUqu`Qz2qURy`cB&Pd%3mt rfy3tW0pCH!?Y9uuGJJ)6!VYlx-JQbmJ{xoyCYdq^Q(account, new_flexidag_config(effective_height)) + if (!Config::config_exist_by_address(Signer::address_of(account))) { + Config::publish_new_config(account, new_flexidag_config(effective_height)) + } } spec initialize { aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); - aborts_if exists>(Signer::address_of(account)); - aborts_if - exists>( - Signer::address_of(account), - ); ensures exists>(Signer::address_of(account)); ensures exists>( diff --git a/release/v13/sources/Genesis.move b/release/v13/sources/Genesis.move index 368c8699..b53099c0 100644 --- a/release/v13/sources/Genesis.move +++ b/release/v13/sources/Genesis.move @@ -2,6 +2,8 @@ address StarcoinFramework { /// The module for init Genesis module Genesis { + use StarcoinFramework::Math::u64_max; + use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::CoreAddresses; use StarcoinFramework::Account; use StarcoinFramework::Signer; @@ -402,6 +404,7 @@ module Genesis { Option::some(0u64), ); BlockReward::initialize(&genesis_account, reward_delay); + FlexiDagConfig::initialize(&genesis_account, u64_max()); // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init. let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay); diff --git a/release/v13/sources/StdlibUpgradeScripts.move b/release/v13/sources/StdlibUpgradeScripts.move index 7c534495..2e34de74 100644 --- a/release/v13/sources/StdlibUpgradeScripts.move +++ b/release/v13/sources/StdlibUpgradeScripts.move @@ -126,7 +126,6 @@ module StdlibUpgradeScripts { public fun do_upgrade_from_v12_to_v13(sender: &signer) { { FlexiDagConfig::initialize(sender, u64_max()); - Block::checkpoints_init(sender); }; } } From 61ef8769e707e506df0541d9f4364844afda4f77 Mon Sep 17 00:00:00 2001 From: simonjiao Date: Thu, 25 Jan 2024 18:08:53 +0800 Subject: [PATCH 3/9] refactor flexidag upgrade function --- build/StarcoinFramework/BuildInfo.yaml | 2 +- .../bytecode_modules/FlexiDagConfig.mv | Bin 399 -> 326 bytes .../bytecode_modules/Genesis.mv | Bin 3439 -> 3391 bytes .../StarcoinFramework/bytecode_modules/STC.mv | Bin 1371 -> 1339 bytes .../bytecode_modules/StdlibUpgradeScripts.mv | Bin 2195 -> 2210 bytes .../StarcoinFramework/docs/FlexiDagConfig.md | 7 +++---- build/StarcoinFramework/docs/Genesis.md | 3 --- build/StarcoinFramework/docs/STC.md | 2 -- .../docs/StdlibUpgradeScripts.md | 1 + .../source_maps/FlexiDagConfig.mvsm | Bin 1368 -> 1158 bytes .../source_maps/Genesis.mvsm | Bin 25361 -> 25235 bytes build/StarcoinFramework/source_maps/STC.mvsm | Bin 6236 -> 6152 bytes .../source_maps/StdlibUpgradeScripts.mvsm | Bin 7093 -> 7177 bytes release/StarcoinFramework.v0.1.0.blob | Bin 114280 -> 114142 bytes sources/FlexiDagConfig.move | 6 +++--- sources/Genesis.move | 3 --- sources/STC.move | 2 -- sources/StdlibUpgradeScripts.move | 1 + 18 files changed, 9 insertions(+), 18 deletions(-) diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index c0d3580a..d470b2aa 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: E203083CDEA5D40EEA2400D1D89CE602FF1778668B8DC34A0672D1EFCB44A57E + source_digest: 5590F14E900DBA21E25A1E21CB250F424A36635942AF60F7709E95B3A1B6DA44 build_flags: dev_mode: false test_mode: false diff --git a/build/StarcoinFramework/bytecode_modules/FlexiDagConfig.mv b/build/StarcoinFramework/bytecode_modules/FlexiDagConfig.mv index 4845bb9b88b05bde7823d7d610c46fb572c844bc..50363aad2d38813b79e3db9110a7ffe10a62642e 100644 GIT binary patch delta 177 zcmWlSI}QP16ot>Z_kWlNL4jfl)f5U*>ODHGUV%&^v^pygCR3;_z&0$v5;O{%@N3R1 zUve(`l+!)?CJsPMIB`bfz8M%h?E2Z6wHKT5n>PJ$RKJM?j0oxh4GBgRur#0x=Eb`( z*SylJv4)l^F8xnn6qq!$2#xt}eJrM{?c}iE6y>#3K9*I^oLVi|%Y2NMNszE5V~T_q J)dcPTEq-Sz6e<7! delta 245 zcmWlTy-EX75QWc~xqrF$8WRyjw6L=fY~98*K7x>TG07%uvw^IIRz88q7M2$J625`Y zAz1nnUW)_g4ByP0FL}|Y_tW3x07N24Fq$vSm9y8!e*VeuER*;qHh;)$?^~o`gg^lg znBrlj1jph%EWHG$&{4U^2v5%xlwOT9-q2FTWd#E`0$nD>4c)nSx9z5DcEjuZB;Ku7 zyQc5!?fPiB?bhw4ZXVkHzFs^IKbJSAY?seIp+e@E6C4W5ME4`6rpQ)2GdUq~DwWuA N0!97-O*kmkfj^|H9ccgn diff --git a/build/StarcoinFramework/bytecode_modules/Genesis.mv b/build/StarcoinFramework/bytecode_modules/Genesis.mv index 78659547354e59fd73b0d53c4a14b6e126b99573..97508566d043a0348306b8dcb0f25bbf29d2f4f0 100644 GIT binary patch delta 728 zcmY*XJCD;q5T3Euuk2>yy~MtA9=CZXc5ElPJ0QRv?^nTZphF-k3Ob5FMR_`0Pys^x zgov77fP^S%u0^7_9wEV4qG6=@^nLcselzx-H9t4=5AC1a1^^G?&^SCWpT05JE3<8V zG=Ce;d;6>Bp4EK&Pwgd&7wY&VKU!m-0S*{MLxF(4??4bRV$rD7osI)iItUP4FLiLE zMA)SSZ4h*kphvPXCgx3$PMb0d8rnu+nmXMQ4DBLpYZ|MiD+oK~TSs$*HP>{a7gJv+ zsYn z>oG!bYeJ^MZ80Uh6DNdsXXIqvqq*6ZY*cr`X4nop;clqIp1%l};a<2O9&AqW7ZyLv z!NzCG*u?fH1K$;=?&~Hu_=u1BgiqDBSjuc=$Qfm(qT<90CJ(AhZmvwRkTccdixsP| zJ^I7{#gIKIzIf5PE8UgbWzVU(FLIf4R}FZshSb^@iA=adIw75@kw|66Q#B?&k(mSb zqw?ZVIH;yFv;QejF;yg#Gs=`_D&sSi8MG~oj#1^zv@H5;WfTu9&#+s3uO!}FrnEy! vJ5>3|YVrAsmD?2e`84i}jI7I1G8!eJ(P9~Mn{-S%C6km)5|wS<@^APTJhxGn delta 788 zcmY*X%Wl(95S_8FAMtf=ebdHn-f`Y>Y$s{c5*~#>OL>WJKv_VkL}62;u88;o1W^|( zSaeAx7AWeP4`9aHqbLQ%P$p6U4C&jN^2Y?j9M461#!xM!a zt3~a-`b#n1>EBZ3Ysb;wI?vHQmB%mRtr?V|f(-`PWKd|?2$;zj;CYO)LObD=iUE#e zAb_`%aPNA8P^AE0A*dliov7QPEY(Gt7BCH5Uq@g*b(#q%zKM|Y$y&*`5c0`iW9D-N z?$g9nkNPTMT7VucAsRA92b{jlAjrWof|}GX4KWRNl4a^ES->?Lky%N5VclCrwlcCw zd?QC+3!C`@;khE^#c_#nHK{9~FIUL^1)Ka|^l=7wsY-myu7U9D2+NnLDD5{8vR6nZ zJ0Y6AO5k22z-^7PU93RHZy|U$+9c}Tv^#{ix&h(s9w}*eXaklJE9tyjbjxnVt-8Kj zch=l>cjRukn_-};j4{<(e8!)+Bz7O&Kic1!?rlGL{9u1?{!y)K?C$jN;o`e071MaS zIl6Z+JzD(M&J;YEpP8?!(vzzq;tFr_7H{*8%-KT`jTO`fSnQvH!Seu_( zL24*M+99MJzF1AI#QS5GY%?$NPPbvxsJ~VsvJ#NBuIO@|taXWpBodNHAp460{t5p8 Dj;UW5 diff --git a/build/StarcoinFramework/bytecode_modules/STC.mv b/build/StarcoinFramework/bytecode_modules/STC.mv index 213831b4eadcf00d73097aba35795e5f129f2575..b462ed908f1f2910168bbd9515060d11ca25c6e4 100644 GIT binary patch delta 373 zcmWlVJx&BM427Q^&m@y%W@ncD-&t5-si8qiLB$ym9D!qOK}k6+LZadTloVWm22pYY zH~R^DloebXb^d-E#p)7JT~HU7_5@z(uN zdE;5@2@C^4h8z|S1v~;GN@$2G!Z{&OXrj{1dghCWqOd4S3nB|^EwM$JHYQ=W(Wl)JwOyn&4;S4D-F0tt`ZVS<&L>1n)9y;H>9~85%kzNbL%~L8 kBu)d?6?;*0refK6G$Z{6O3gHd$SOI-Xw+4vDwuw?e;JV>Jpcdz delta 404 zcmWlVJxT;Y5QSe=*Gy0U%%=r7P zh|k$C$p ziRECZ^P6#`+#0psZAw_g6`D-KJNmrarPU^-b;*}|E6pA~a2A^nsyoHx^899Yd^SD0 zzPgxA-+t(j(*Y6FusM(^?Ke+yGV!Q=K-~$BjV@1IcUkXmMahYZap_Sm>Mv2<8`L4P PO0Hux>dNaPnD*v>@kA$* diff --git a/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv b/build/StarcoinFramework/bytecode_modules/StdlibUpgradeScripts.mv index c98c9deabd1956ad445e3cf0cca5bfe4c4e6d79c..cebf13e904604b7e5038b49384f43660e0802cae 100644 GIT binary patch delta 636 zcmYLGyKYlK5S`ig-ralcwXd&}*bv9T!A@+0aD6mqpSZQX@o^$3*v32+oW}o|OrvShr%-MX(pZ-DdgZ1Ta_8s+C z@zaG@L1KA(0%7pobCYBpM_rX~QKVhM-gQO5K7Gf^)MmI(;b+!G)usG)f@} zA&Hc(HWx=_p@(V{z%>~tho^1H;+?s8!p@miuV21dy?9lx#qwezkJ&b2f|wml)KOmrA|8xErOyx{+00iuc4E3duq#_^biBQJC7j1yg_oOHU|jm|Tgx6xB) M;o$#lUa!pbFI>ntegFUf delta 621 zcmYLG&2AGh5T5bB*Ip;iW|K52G!3LAZIU7ysQHJNK;po;0wKf&IH5}1IF>!49^lBe zPrx0CD-utDcmj}+m`#vaX~v)D`?2i(7^^t{u=&#|0I&!PwwUk-zfgQ-effiZM*T^A zGv-a+RPXXv{%!bvGCxqxX^8RU$?Ib|0fgq5T5C!zuaO;R2yWLp5PKd`H)eoLYdf!{ z`w$=-H%M9|yc`hZ6_gMTVhcsNY$FPO4G6anJ6#m<`bHn*4N~x%azNaz&2tFt+vkbn zcdiadUfe|s<-M&Tiq34C2I2mQ`iAT0+s#pNp}bgJDktT%*ez$pyjV1=Qyd)&NxQmR5JGTnRzj!N1P!=wdTkK6LP#W~tJT6$ zQHUac#{$W?_o>iN?bM~|PKE#;E!3rFuATZ|z9h74js)ut+` zIu0~bNA(}1PxIKV-s@rPCCDHlIR{LVFH~Q2uhVPAn9bh^4be;98Wgxd6`>BFVJ;#Bd5FFlzB#en;dl(cm8{Q_0r7# E0!(x_$p8QV diff --git a/build/StarcoinFramework/docs/FlexiDagConfig.md b/build/StarcoinFramework/docs/FlexiDagConfig.md index 81441e26..bda75c0e 100644 --- a/build/StarcoinFramework/docs/FlexiDagConfig.md +++ b/build/StarcoinFramework/docs/FlexiDagConfig.md @@ -14,7 +14,6 @@
use 0x1::Config;
 use 0x1::CoreAddresses;
-use 0x1::Signer;
 
@@ -91,9 +90,7 @@ Create a new configuration for flexidag, mainly used in DAO.
public fun initialize(account: &signer, effective_height: u64) {
     CoreAddresses::assert_genesis_address(account);
-    if (!Config::config_exist_by_address<FlexiDagConfig>(Signer::address_of(account))) {
-        Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height))
-    }
+    Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height));
 }
 
@@ -107,6 +104,8 @@ Create a new configuration for flexidag, mainly used in DAO.
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
+aborts_if exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(Signer::address_of(account));
 ensures exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
 ensures
     exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(
diff --git a/build/StarcoinFramework/docs/Genesis.md b/build/StarcoinFramework/docs/Genesis.md
index 1f9b39c3..6d449dab 100644
--- a/build/StarcoinFramework/docs/Genesis.md
+++ b/build/StarcoinFramework/docs/Genesis.md
@@ -24,10 +24,8 @@ The module for init Genesis
 use 0x1::CoreAddresses;
 use 0x1::DummyToken;
 use 0x1::Epoch;
-use 0x1::FlexiDagConfig;
 use 0x1::GenesisNFT;
 use 0x1::GenesisSignerCapability;
-use 0x1::Math;
 use 0x1::Option;
 use 0x1::PackageTxnManager;
 use 0x1::STC;
@@ -466,7 +464,6 @@ The module for init Genesis
         Option::some(0u64),
     );
     BlockReward::initialize(&genesis_account, reward_delay);
-    FlexiDagConfig::initialize(&genesis_account, u64_max());
 
     // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init.
     let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay);
diff --git a/build/StarcoinFramework/docs/STC.md b/build/StarcoinFramework/docs/STC.md
index 9abaa8ef..b22272d5 100644
--- a/build/StarcoinFramework/docs/STC.md
+++ b/build/StarcoinFramework/docs/STC.md
@@ -22,7 +22,6 @@ It uses apis defined in the Token
 
use 0x1::ConsensusConfig;
 use 0x1::CoreAddresses;
 use 0x1::Dao;
-use 0x1::FlexiDagConfig;
 use 0x1::ModifyDaoConfigProposal;
 use 0x1::OnChainConfigDao;
 use 0x1::PackageTxnManager;
@@ -269,7 +268,6 @@ STC initialization.
     OnChainConfigDao::plugin<STC, ConsensusConfig::ConsensusConfig>(account);
     OnChainConfigDao::plugin<STC, RewardConfig::RewardConfig>(account);
     OnChainConfigDao::plugin<STC, TransactionTimeoutConfig::TransactionTimeoutConfig>(account);
-    OnChainConfigDao::plugin<STC, FlexiDagConfig::FlexiDagConfig>(account);
     withdraw_cap
 }
 
diff --git a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md index fbfd1432..0a8950dd 100644 --- a/build/StarcoinFramework/docs/StdlibUpgradeScripts.md +++ b/build/StarcoinFramework/docs/StdlibUpgradeScripts.md @@ -402,6 +402,7 @@ deprecated, use do_upgrade_from_v6_to_v7_with_language_version.
public fun do_upgrade_from_v12_to_v13(sender: &signer) {
     {
         FlexiDagConfig::initialize(sender, u64_max());
+        OnChainConfigDao::plugin<STC, FlexiDagConfig::FlexiDagConfig>(sender);
     };
 }
 
diff --git a/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm b/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm index ccefaa8ff24ae7b25d0b4454af09088c53fa63db..f5c470d5bf2f6c72dc49831a1d7a47ecb4e232e7 100644 GIT binary patch literal 1158 zcmb7@%_{_P7=YiI{VH2)rd+tO;xAAfSuNqJTr^E%W_C)usa@piV4W!cfTHZdMajuU zY2Do2aN4+WljQj+<@S!L=QPjzJ=68CAE)m+V?#^D{l#kWxjeryP@cM9Js)k)^*&dQ z#zkZTEcp9arRsXPoy_`irBRQPnD<>JRSRd=lN?KR8iM*i}en+YW~*GsHRmAaUq+^9KlS{ z=p^Tu0kPArx`Mp`P8daD&`dT%uNEe8O})`FL7^!nw5FZq81W4BRqtSRKwtF}RuA-5 ze_@rfX;%G$*^il1C%VFPF!QQuEEiIYbjS~N0(|)YJ;y0wmnM`lYD*tDeGH(V;{kIJ GQ{)@;<&?qz literal 1368 zcmb8vu}cDB7{~GVJoQQ=Y>bEqho+hoT3S*Z4k8Gu@s#WCyeNe_MWW4rAh)7LD6p+1 z3<`?2{(_*fwf=(!>H7vk+j9xO$0ooMI6gM>VhOhIbPos<$!+o zBpFM-B4ccHmFrk1DiL?oCA3X)p6`2Z6t+F5?u9{JyrXT3JiU~fl1JSK4v0MJ6Vwfn zM?FHNlKKTokKzlNM#`gpL|Vv{*z*CYby}1|RF|HXC@ZK9G9gMAbxbBjxrvHMMwD}? r7Ricoe4-eabjDxA72&7+-v@S0*_|$B8F5SBm<)rKAJ{u`7OB(^`3Cur diff --git a/build/StarcoinFramework/source_maps/Genesis.mvsm b/build/StarcoinFramework/source_maps/Genesis.mvsm index 666697f9d8888c8e4b77e2cbc80520446aca0537..41d1e279bdb026d066772bdf372151237ece8bbc 100644 GIT binary patch literal 25235 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 aV-0{#Tkm5X2Hq>-$kN3vtt~5881pw%3dyDb literal 6236 zcmbW5Yiv_x7{}js*KQrO9pE7brxcumvYSPTNHQ7^tE%%<{0M=YReRF$WV$z)v{DgO znxV{HV2rOf8Vg#XR5TuQwo)HOwcsv(GM$VCLsmjvstzEnEVowUM{V4}xzR5;6% ze-%uF{snC30y{uIq@7q{&=2W)tO)3b^lhy7K|iGXu|5F(kY=~7P(IF|(eFzrlI9Os zzd*4xzry+zJktCa>m-y&vz)W6f>LQVVciK{X>P`9gEDD$VZ~vdGzYOpVZJo4bKl1> zebSu7ItPAfzJv8G1fnT_)%?GdsV2LzOVSNMD(maTD7HXvF_pn2-RGJs)SBY6G z%{122P$$g>tU;)krfuy92d~;*FIx|$(CL_c2KxwjQ}LA56SR7r%;q;JIBpl^GMi6Q za2j%(&C^s|f?Jr)zf+c1b_=uFPf;D@JD$yF<{2{up8s~SFBMYL{2cu+*o(_`nz#6j zX$9}zXlhqDY3+5A9p|%Y!P*Qu0+eC}Ku3VxSV_oVvF@Gw>ebOcz+t85wQ2ylab%Q1BX7{D3^9RVJ~8UY;v zvaeko0luK$BUJ81{n!<157X{v+d9Er;_CI7I>BX+K_|El`gPhXkUQUnwG(uL zyAP`ybb`yCyiRcM((gFv1UH0r0(63#z?ud95$9*DIpDprZF}pMt?gUe9x>)$ZctPJ diff --git a/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm b/build/StarcoinFramework/source_maps/StdlibUpgradeScripts.mvsm index b412aa7e9a5aef97b3d73ab2ebc95c03a6159aa4..55adea0ff1bd6bfbabf5c2aea97dea6685922d7a 100644 GIT binary patch literal 7177 zcmb7}TWnNC9EWGO_Y2Sq6p@QkRIWxX)I>nhw2c)5g;XQ)fn~dUx@>57>+Y!)1j$Rqz!7V4_ZXOA=$*Y-`M1P`)1CZ|M{K& z?3^~QZ$0_Ou@$Snx;Vb(=+Z?4`(jHf8~2UQy657NO`Br1aLhPd26+OdvPyC8AzR4Y(6|IRx^;(P+v`r`3St$e-9N zOw_CC#Otz?%XN2S9fY7XV_1hEOPVLJeuivmX6`9Rnv!$S8L8FLt%OZz(V+jf9U z7r2Z#2D-GLVf_KRv=zn1%m7{5EUcNJOS=K98FXnMz>0zH0$o^pL3e?6tY<-YfoArB z7SLVbP3HRrbQgGv`F4Wt0tHz2f$jngSbIQs0c-6AhsRku$(Z@z9MuKLx7z_EKz4x+ z#I2yC+KIItbX4oHc7TqmwRVC-R{PLSSvBam&wq)021;7OiCB9$=7k>jQt5ayq4xV9 z8T6aI5_yyLTUTPtdeHT2$La!IzYSR3pzC)x)^5Q{Xa)_%~h zdK1=jpkH-s^?<`d7nT`Q1I{l-E%HhTWJSVlDg~Pnx7gVWbqHR>d&N#H+2AF!+hU^4#5vt=Rt?yJ**3$Lr`6A%rej+n2EIKkXPC(u%RpWNxU6)a%t|u>IWT}Ragf=M<%mU9htMt zcOG+5PPX-5U4qZ>7$B;j= z19)0;A!CT+pu_Sl))mlUvDV+^tR4#fFX+IJQx4H~m%b+mim$$?dUN{x% zi2EC(sc=WgVL$50<17jVt?`5(+T?AP-z~~G1Wt!sJ3@D_GpOG|RwCJLS^VQmB5t~1%x?fNa|I|}+l zH-L2v^oi~ztmB|hbYoc42)aJeWiqa}l}xlJ$-bX?B}=54c>zkLS;yV1hB9f+#cF_Z zX>P>Y4wI#sX&h6ed7Al#phB8IVGYAnX^vox!gbQL^I3bEG{><1g6pMu6)TWWPnKpj z)g%^+45%#`LhSHA+Yqi{@xJ|FNMWYB&KaV^71jy1M!^Fqm5Px{s+^y7bvdv!_ATU zN7|ZVp|Drm5R0_=ag%GzDN%7wu`v~30%>tC8unspz-`DYA&?#lhhttmt_B=K{?tAp zPtT?kugeyf^X|qv3`x>#!Ww{NX%1uk0x8l=yi=+)^Gl2=fi!6@#aa&O(yYd+fedLr zg!L$7O0xyahb(E%utM#a+0yLAIt)3|?7Y-5gq^D?}S{FWWy(y`|er$8^m=U9J&UWU>f zW9EWhhGeWV&>g!0s}Xd^-jCG;x?{Vr_JZ!%cC3A%JGPNMyBT!HzCpcTL3ivH>g@vE zv6)z_KzD2n)*jFuYpuQD@NpLA8?ywQqgsx<%noqr*bc;PprhJ}wF7iitFd;1j;ghG zfkRgN(2iR*$?;778u=s?G>4*1?V%>omM_QxmY(B%F-|dsgo80m03XFLi^!l}9 zb%9>L4Orcv*Y7T@9?-2`UPvfFxB5Bi-HfSQeGk@t(5+sN^&IF{x7Go0nCQ|XV=BS9 zF;*k5g+Ovcs7<9{GvZcTJxhn+MZ8yRVHuZBtUk~oNIYMM;1u<~108}Nu*N`#;9ab< zphHkG%a|3QLr{jb5_AaGVMRgj_uH_xgTq9V_#o$ljZ35{s=w4PKwb=i^w!2kFXn|+ zWGa!@+9zj?6gL1n9`TgEa{{GRs-X zJ3vP!6YEaUk*UUNgFLzN)_M{gCfZL12W<{rZ;V68AKL+ZT5=*&h%=zW@-5ay&|$IG z-{7#eqg*X6T)tj79=(4c|78cbyxa|ZW4{IT%N1hX3i{=&RRIohC{H!!9xzGip@xRm z_NcE~_g?HZP~f-vq2^%RZwQ83Tn4UZPzW++HAkXeC>HF9_#4BqP)E?=JUWohy%927 zB2hp1gtuA##!!@I%p6FwBlPZd67@7BM_W7864Wyh57OGaSfo{MjOQr(8)U`(P|Oed zkrq!q;d}I-A@%YiEBiR+H<0sxR&e?V{7iMQ9=^}{UeHqhJkJgn`Yx9dbU^>+Ox^*#iBqZ`B;0)3-<3F{c>8{HJv zY=W+Dbcu}XV0<_YSJ zL#Z@>#F~IBq&bOo0j`v$t!M4o(wxGYhO4A`2`iAno-EB2tUQ=2%_OX3D3j(4PrnHB zq!kS@)^507 znq64kut=IWV)ejcX`zUuUrmRRN9+L3FgcMV{(+GR`d~au$t+BV z{rM)e)mC+#auxCeb^u4Dobo}$UeHtS!+I6;S>Axv5Be;()*)~>d_LfJkP-V^i0d+Z eg?z#eaQWVy!u38I^fF9PG6z#HgSB$On12B==3pEE diff --git a/release/StarcoinFramework.v0.1.0.blob b/release/StarcoinFramework.v0.1.0.blob index a459f64f4e6c947930403e90d5a606bf5215d627..080283cc07e8f44d19374537299694e5e67d8058 100644 GIT binary patch delta 1970 zcmYjRU5I4W5w1Gt+w(jb@w4G z8rkTB=ql3d4~)8qi!EHixDtI3^hH=@9zw{QPa^&h5D^7m5+WiI!T6V?&TJObaH^~7 zRMn|l^;P}-NB`3w{5L+HT=?B1#@qL&=#Q;0ln($3p~YGmKQ<8`;)3@rzKZfZe@6uW zkR|_n$)lg7(Px8yVd1eTKX?>pCm;cgh9D3KsH`R$%sA>dG=!mqLO}we1Sus%k%XY* zZlOpAN{mRE3xEoGC?G~kqACRh^$<}6P334y7f|pvqbQ=SiTbnJfNmG*a<4}kCS{Py z1cfTqX2@Yq*NJxP&Uqd^CPYAyQLqJiI#|TkbbGtQ%8lvk+kcoId1CK{b5CrsAVFkU zQ(}7Vllt__r;gz2^uXDhdkV5hg^W|C$g(1%?{rLwdBikr1U8PSZkfIC=d+)zOx|Xf zY8fH;%ojZBh`#W~HF@}H3_ie8^f`L^Z@5;-8KaUT5Tzn=R}jHCfU5)*!b8cVPwGH& zlw5d%YQ&kZoeD4{8%Sp z1U5AYHHcw>ni`Ir%_;#SS}c)`<8ZBr;O#*V%tpC_qPkh7p7MPJ7ZLAwy|$M%n&2HE z3x2uRqPwm3EJA!mN_YIq{Vg)DTt&629_-AaNLIR}Fo))yI%?>OnX}z^K3RyDla-_w z_mg2fipMs8?U&e{umA%ld>t_!F$`SkLvTutfgph(uRIKpSkJX%mm>|a$|uRu5QGq% z2fKz!Uc4X$7m5NoR|?`dq)UqK@BVT0LujJE8-PnPpg7#U=1jB-c23-YFA_TLx%wPn}y-Oi%9h*Ddn|AbCWfn@$kH}Uk7+|J}L9m9^T zXBa`o6xil2yo>pJ$8aXGMFX~zaRQJ-x-gJ=nVtIKl>K)2Y-db^}jU!4~biB zYm?uTGqKHE-Yfh^CSUU33xltUCI3IgM^K-!&xHA*qd1;G4Q8MY4QN6O+SsL`nio)a zI{-^13Dv4wS@lIHx7!koku(L>Lr$(#v1baCd>2v|1vPI8St{|~;C6V|lB6yJYS$qwqP)e5&s@E>lqt(NDh3Iv?KG9zc z=q2xZw{^=VF3cp2q?NRj*(6QoN^8k_vM1R{Hivz}HbFkxIrnS)C+6?pfb;pO7qGqa z*IV!#+R7+}Et=O7gH=~T10iBVp=QsLTDK3cH3+n_MuGh@K zHuGEW!20AaQVHc{o?bNrwVL^6q}DS@UL6x;K}S49Y*&xXSOs=ojqL*Yc6HzMl_a@O z@`$iHB)6emB7WJ7B>X%LXjjb0zl1{DBa1$r0iB^5+2TkI?1+}AfW>Ffj&pV#C)mj! zJ&yh2su@!LLt8ifj72OzaR*lNcaNj?nv|*7{i^(Hvg~#Bh!SuKjVPf$CD=1P<&)ea Tc}PzU?TC^c?HoRV^SAvM_+jDM delta 2066 zcmZ8i-H#l_5wGg*nVy;Mncd!x+1roX&)d8Gybt?q59VxaFgPJ{B8&JUCyGBF$YBW_ zKt}ilR)DZD5<+4H0}?zK9uOErq66JSlt|$phsUltX@2vo z?y9cpnyT6_{^kDtru&;ePbM$(E48nb3jhIv$2`IHQ0#M^17*3ngWgLl8@$CF{Wd!o z{*^IOLtwxGB!D0e4kN)u;u0K`%yT(#pU%SoBuZ2sN6CdNq(BEbb2SI_0DVALBThHB z`_g^j+}8OAAD>RPH`5yrVQ2cn{w_l?y}3Qt&jeruJx+p6p%o}JEMZQh02w3yoGZvt zNU(ivl5zH34{l#aA=FuYga3RYuHmBdZ~Oq|ReoJ~m%Oa|n#Y4Tyhy+6-Nf*nfK9*s zv@(GZqS?hV8hl?Mpw4MRzid%fH3Wf#D3XA5SjVjLtK!GkS zpoo-=SPJkfKBDkz%Hq5ZQSdsWlbkx`LCVHK9YI*n(5_1>OiI5gV-(ty=E$I}%Y>b> zHC{l63E|VpC|H-=`-?a~{pR_m2rIejGz-eq|JAvz z?JqBFFt>!raBkYYyoGDimo9IP14se|Nk;jMQ}D==ETijNVwgjuX6OqP0!n_8+tx4s zrMJEM@x|9yr{;FDeS~GU+~b=!Q2dEioPV%CqI_R`?s?CKS@)IjNqsrGKFe~Np1?xj zd6`-Aj7bZ}@TrN@qts=)1i3yzXqn%oic|w%ff(8hWkwVbWo2wtSLjm(-3+N(hN}^R zvkM)FcAFfE;(CGd#PLF6pJH<|mjIOwl4*5TB2hrfHBDVl9Xe0T zb<<#WE@U$im}bH>Mz(%<1c^u-q#u)ZY|w(Cq}`^-e4=xGTFqMn)78FNOlWLG{J%i} zByuD1w5z2S+EYC7%}_g`uPBQpMOjg@R7wKP=m0-agv=~{Z>-bi2^_6`UHPBtJ;V;J z^9xs)c$L?j-}0MGe(3(w_uj~6-S@K3pnl)H>f0e<%eOs&Iy7*Bg6|5bF53Rjn-r%(jk zMcpIvSlk+`xv{d(2s5z?pYQ$^FJmH+xtKU&?Q26^b#eZiDCx9DGk`L%M zM6C`&{vauZtp$YQUF4>Ch{WPyg7|I%yoY8;d>=L-*IGm<9bF=)r61@X;Sc)*!uyBh z$@!6;eYvO*R^nP*j~j6_ZpEGKu6TF69`A|wjt0~f)GWbH?`QZe{{L`G%O|nph+}6j zJe2-^3(GqvPU3gy$tU)%pMK=*#hqinz)u)nN%<*!rD;lLE*dMQx@u7^sh%n8wP>8M zXh_f4RMU@6VKF=#u2FSyy&4V8eEQibEaM~TSM-{+BQNoq;%U-d(96-X@=RAPn?+Jw z(1U28B*_Dk$7V^7$kWL5i1(whgzviv%^(`Pw=2^ONrQCFn4V=dHY;jqR_HH6K=)-d ztAaZYW!L`F=T74VY^UFy#(}>UjVS051wA~2U7SykpTWcZ1x?4y!WdH+0}87j^_5Fu V^+_I)gAq9xn3bL1ox#p8{{wtX@TLF& diff --git a/sources/FlexiDagConfig.move b/sources/FlexiDagConfig.move index 98b93b0d..4ac2c486 100644 --- a/sources/FlexiDagConfig.move +++ b/sources/FlexiDagConfig.move @@ -26,13 +26,13 @@ address StarcoinFramework { public fun initialize(account: &signer, effective_height: u64) { CoreAddresses::assert_genesis_address(account); - if (!Config::config_exist_by_address(Signer::address_of(account))) { - Config::publish_new_config(account, new_flexidag_config(effective_height)) - } + Config::publish_new_config(account, new_flexidag_config(effective_height)); } spec initialize { aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS(); + aborts_if exists>(Signer::address_of(account)); + aborts_if exists>(Signer::address_of(account)); ensures exists>(Signer::address_of(account)); ensures exists>( diff --git a/sources/Genesis.move b/sources/Genesis.move index b53099c0..368c8699 100644 --- a/sources/Genesis.move +++ b/sources/Genesis.move @@ -2,8 +2,6 @@ address StarcoinFramework { /// The module for init Genesis module Genesis { - use StarcoinFramework::Math::u64_max; - use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::CoreAddresses; use StarcoinFramework::Account; use StarcoinFramework::Signer; @@ -404,7 +402,6 @@ module Genesis { Option::some(0u64), ); BlockReward::initialize(&genesis_account, reward_delay); - FlexiDagConfig::initialize(&genesis_account, u64_max()); // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init. let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay); diff --git a/sources/STC.move b/sources/STC.move index 15ab8e8f..92fc837d 100644 --- a/sources/STC.move +++ b/sources/STC.move @@ -2,7 +2,6 @@ address StarcoinFramework { /// STC is the token of Starcoin blockchain. /// It uses apis defined in the `Token` module. module STC { - use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::Token::{Self, Token}; use StarcoinFramework::Dao; use StarcoinFramework::ModifyDaoConfigProposal; @@ -123,7 +122,6 @@ module STC { OnChainConfigDao::plugin(account); OnChainConfigDao::plugin(account); OnChainConfigDao::plugin(account); - OnChainConfigDao::plugin(account); withdraw_cap } diff --git a/sources/StdlibUpgradeScripts.move b/sources/StdlibUpgradeScripts.move index 2e34de74..8b7cd6bf 100644 --- a/sources/StdlibUpgradeScripts.move +++ b/sources/StdlibUpgradeScripts.move @@ -126,6 +126,7 @@ module StdlibUpgradeScripts { public fun do_upgrade_from_v12_to_v13(sender: &signer) { { FlexiDagConfig::initialize(sender, u64_max()); + OnChainConfigDao::plugin(sender); }; } } From 9fa19f8725fb74cdf66f03d62fe9c2ee70d6f810 Mon Sep 17 00:00:00 2001 From: simonjiao Date: Thu, 25 Jan 2024 18:53:45 +0800 Subject: [PATCH 4/9] change parents_hash's type to vector --- build/StarcoinFramework/BuildInfo.yaml | 2 +- .../bytecode_modules/Block.mv | Bin 2705 -> 2640 bytes .../bytecode_modules/TransactionManager.mv | Bin 2510 -> 2489 bytes build/StarcoinFramework/docs/Block.md | 18 ++++++++---------- .../docs/TransactionManager.md | 5 ++--- .../StarcoinFramework/source_maps/Block.mvsm | Bin 18845 -> 18509 bytes .../source_maps/TransactionManager.mvsm | Bin 19100 -> 19100 bytes release/StarcoinFramework.v0.1.0.blob | Bin 114142 -> 114056 bytes sources/Block.move | 16 ++++++++-------- sources/TransactionManager.move | 3 +-- 10 files changed, 20 insertions(+), 24 deletions(-) diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index d470b2aa..c6443f94 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: 5590F14E900DBA21E25A1E21CB250F424A36635942AF60F7709E95B3A1B6DA44 + source_digest: 90888FA081474D37F4BF44DF0EC799C2B01C10750D4955CBE34B7C4D919C70AA build_flags: dev_mode: false test_mode: false diff --git a/build/StarcoinFramework/bytecode_modules/Block.mv b/build/StarcoinFramework/bytecode_modules/Block.mv index cb1b4ec752d3cd9d1f24a667772c1a9525885305..d9c1080694215d339962b9b3b31e17be858ab90d 100644 GIT binary patch delta 637 zcmXAmJ8x4#5QS%E-}hd7{kVSH@#`jb3;|*wJQ5NUpye-6(;-nKgM{d#ttnDcrAR@C zglH+~>1Zg7_zld4Ek4bhopW}iJ!|~P*XR9BssSKH$SI$QgWo7WQlY-mUo;o;m$qkV zMW3fHlDFA$_9gpfO7HSE8xRNtNKl}`fCUGMELkxVGF3p@#c zO6;qMYk->KvaT69vb%vC(?kc*ifAW%(LuI!c}3_sMn6Lk*Q^D79m@!2ufo(fsx{`# za-DgrjI8fBEOXhcva+nU*mRps>W*`OcRLpFptEM)>vRF{$NoXY!%h#};UESaZ4KFa zG#oJ>jbrffm~}egMQOz=o5yyFU{6_;PxLlw`E-V;E3WEmzV371@J-+HHP>>Z{@73a z)D>>#cZ)?Kj3tqT_t-xroh4)>v*tkWQColg2tTsCX delta 697 zcmXw%Id2nD6ov17Z{9XDw%>TSV>|ZPjva@vBrJw(K#UuHL_o-PEJaWdu@uM>1qB_N z9tjD0q!ctD1Qiv6nhJ>y=#Xf+ z+GcFl=4{>;Y}yn|z1py$ZJL(p*yZ*LwxjzPUPsSCmoe$POvMnK^J9w+7Jt%VP`aQXDBmM)VE4D*j)Qc3Ib-r<4JTIng%D`y#HPkz|PI2J5Ag!-LU->EPyM z_s;F{baM2Rt?|H)#^ceg!|A=z-u`Gh**}clibum5UvybrG2k8>t!ye?Mw{{+1ONJbCkUCc$lb`QjDDDde|wfn`~Uy| diff --git a/build/StarcoinFramework/bytecode_modules/TransactionManager.mv b/build/StarcoinFramework/bytecode_modules/TransactionManager.mv index cff245e057e8acfda3fd2bf950d4cd0d33c1cef9..91fa50f780abcaf7f5eecf795bd6c2d511cdfc5d 100644 GIT binary patch delta 395 zcmWlVIa0$g7=`~Q$+9ggvEw)niR~<`frKrrVM)g^xB?fTNW%pf7nBS`!2vQ9TmpJ} zDy~4mZx!D>N$>shq|fF@bMlh^2AYU`&`6Aooc=&PiJtQ=zTiHnXV-fTBE1aWV80(H z<3$)M5Uh2H5&}_60E$vsv8^huI2AjZsk5Wp8$(gyS*Uui29o_c$Qy(asbK?T zSCK%uYlxWZ6@!fysJ7{)q_>cgKjM76Z59bNcG84`aU0Z_u)=PqOV~>}*i6OfXs1G5Kel0c-rR1wQx0j}b{T4S5+Pnh}JG@@$$S^U=ryMifG3Uie%K6iT{bz|s zt}miORLm~WvwT7}#rYU;1eAe*l`9|oK%tDKmGOjaS-Ft~clhuxu#mPV*yo7s7i}Ob Vh%R#|CR$xiZ?3Kuse 0x1::CoreAddresses; use 0x1::Errors; use 0x1::Event; -use 0x1::FlexiDagConfig; use 0x1::Hash; use 0x1::Option; use 0x1::Ring; @@ -85,10 +84,10 @@ Block metadata struct. number of uncles.
-parents_hash: Option::Option<vector<u8>> +parents_hash: vector<u8>
- Hash of the parents hash for a Dag block. + An Array of the parents hash for a Dag block.
new_block_events: Event::EventHandle<Block::NewBlockEvent> @@ -143,7 +142,7 @@ Events emitted when new block generated.
-parents_hash: Option::Option<vector<u8>> +parents_hash: vector<u8>
@@ -326,7 +325,7 @@ This can only be invoked by the GENESIS_ACCOUNT at genesis parent_hash, author: CoreAddresses::GENESIS_ADDRESS(), uncles: 0, - parents_hash: Option::none<vector<u8>>(), + parents_hash: Vector::empty(), new_block_events: Event::new_event_handle<Self::NewBlockEvent>(account), }); } @@ -430,7 +429,7 @@ Get the hash of the parent block. -
public fun get_parents_hash(): Option::Option<vector<u8>>
+
public fun get_parents_hash(): vector<u8>
 
@@ -439,7 +438,7 @@ Get the hash of the parent block. Implementation -
public fun get_parents_hash(): Option::Option<vector<u8>> acquires BlockMetadata {
+
public fun get_parents_hash(): vector<u8> acquires BlockMetadata {
     *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parents_hash
 }
 
@@ -504,7 +503,7 @@ Gets the address of the author of the current block Call at block prologue -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: Option::Option<vector<u8>>)
+
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: vector<u8>)
 
@@ -513,12 +512,11 @@ Call at block prologue Implementation -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option<vector<u8>>) acquires BlockMetadata{
+
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector<u8>) acquires BlockMetadata{
     CoreAddresses::assert_genesis_address(account);
 
     let block_metadata_ref = borrow_global_mut<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
     assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
-    assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH));
     block_metadata_ref.number = number;
     block_metadata_ref.author= author;
     block_metadata_ref.parent_hash = parent_hash;
diff --git a/build/StarcoinFramework/docs/TransactionManager.md b/build/StarcoinFramework/docs/TransactionManager.md
index 6477ab0d..f45beb27 100644
--- a/build/StarcoinFramework/docs/TransactionManager.md
+++ b/build/StarcoinFramework/docs/TransactionManager.md
@@ -28,7 +28,6 @@
 use 0x1::Epoch;
 use 0x1::Errors;
 use 0x1::Hash;
-use 0x1::Option;
 use 0x1::PackageTxnManager;
 use 0x1::STC;
 use 0x1::Signer;
@@ -465,7 +464,7 @@ Set the metadata for the current block and distribute transaction fees and block
 The runtime always runs this before executing the transactions in a block.
 
 
-
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: Option::Option<vector<u8>>)
+
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: vector<u8>)
 
@@ -484,7 +483,7 @@ The runtime always runs this before executing the transactions in a block. number: u64, chain_id: u8, parent_gas_used: u64, - parents_hash: Option::Option<vector<u8>>, + parents_hash: vector<u8>, ) { // Can only be invoked by genesis account CoreAddresses::assert_genesis_address(&account); diff --git a/build/StarcoinFramework/source_maps/Block.mvsm b/build/StarcoinFramework/source_maps/Block.mvsm index 496f52b178d1292b16b76122ee2d551612b11341..47ce2d08f219bbd401fb3386b8c5583564f90a47 100644 GIT binary patch literal 18509 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 xqN2hg@8rS~@6Q8Ok7@t_ diff --git a/build/StarcoinFramework/source_maps/TransactionManager.mvsm b/build/StarcoinFramework/source_maps/TransactionManager.mvsm index 2d9cf9915d3a66a35fc57844edb193159384abb6..34b37bd63520da91cedfdfc5ee51690d7e433244 100644 GIT binary patch literal 19100 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 diff --git a/release/StarcoinFramework.v0.1.0.blob b/release/StarcoinFramework.v0.1.0.blob index 080283cc07e8f44d19374537299694e5e67d8058..76913027caf443ba4b8b5deaaeb0f217948584b8 100644 GIT binary patch delta 1081 zcmYk4-)kII6vxlGckaFOYj3GqX^c^!f{#{E5FdP0@WBV4 zBo(CiT86MRAX0tsv7t*7tR|rT0s8ENs2~;!g7{bvzc(UyA3k&Lne#n!?w#*XPxZ%7 z_2J_O8$YD?+D`&aL;+JO(t%w6ot;m_P<#Tr)~vN*B4Zqo$^=G262*33VIWaJRRbwQTw`>}*dwZ2%=viH zU?`dxh*}=d4w>XR*CoBmWhOI@L4Cfmm*8=sTm>(d(b`OEF1VIekXftLp}GW>y6kzx z&oo@(b&D&FCh>-iu3B7cw8-1ct$wT1g>tLg1F!dO-|ar~;#mwTb}+Je&Yfp+cae0S z*W(4&&I?P-I`%425>=x#szq5;j}ou$_1gVt5Y2l-Zz)PHeZ9%tDqcDn^PqVD$9|LXfZ8F4q8W6MC_gLw`L( z{dVS)7l@>sL`j@DiAtK&{kzC2d0GPsNRBa|RM8=nVhDU%DUdUmKv1(uq8ywEQgl0+NE7E0G+NDvinx#s zsIm~`$hAl=amsN3PZt#68H1(57~ol>mJL=4MQ~Tk#=lmnl5?$EBc7|9x##OtXRpwr z>;kQil^ zJ$vku4v@`AvXR}4Geb~u^lT$&Y3i_}SMPTc@r}2;@AucQ^)B6fcdOqUZQq~gdEMRG z>R#XO-|BAO==OUzw%zVK{q4=}tq2F1=*I_dZIpS%WmUVz>+~j7aZ-Ji7kyJ9Ac{rl)PE=6|^ zORTjT?HzV>vYG5Oth`lp KU~dXJbK diff --git a/sources/Block.move b/sources/Block.move index b90033d9..e43a1372 100644 --- a/sources/Block.move +++ b/sources/Block.move @@ -1,7 +1,6 @@ address StarcoinFramework { /// Block module provide metadata for generated blocks. module Block { - use StarcoinFramework::FlexiDagConfig; use StarcoinFramework::Event; use StarcoinFramework::Timestamp; use StarcoinFramework::Signer; @@ -19,6 +18,7 @@ module Block { } /// Block metadata struct. + // parents_hash is for FLexiDag block struct BlockMetadata has key { /// number of the current block number: u64, @@ -28,19 +28,20 @@ module Block { author: address, /// number of uncles. uncles: u64, - /// Hash of the parents hash for a Dag block. - parents_hash: Option::Option>, + /// An Array of the parents hash for a Dag block. + parents_hash: vector, /// Handle of events when new blocks are emitted new_block_events: Event::EventHandle, } /// Events emitted when new block generated. + // parents_hash is for FLexiDag block struct NewBlockEvent has drop, store { number: u64, author: address, timestamp: u64, uncles: u64, - parents_hash: Option::Option>, + parents_hash: vector, } // @@ -82,7 +83,7 @@ module Block { parent_hash, author: CoreAddresses::GENESIS_ADDRESS(), uncles: 0, - parents_hash: Option::none>(), + parents_hash: Vector::empty(), new_block_events: Event::new_event_handle(account), }); } @@ -111,7 +112,7 @@ module Block { aborts_if !exists(CoreAddresses::GENESIS_ADDRESS()); } - public fun get_parents_hash(): Option::Option> acquires BlockMetadata { + public fun get_parents_hash(): vector acquires BlockMetadata { *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parents_hash } @@ -129,12 +130,11 @@ module Block { } /// Call at block prologue - public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option>) acquires BlockMetadata{ + public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector) acquires BlockMetadata{ CoreAddresses::assert_genesis_address(account); let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS()); assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH)); - assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH)); block_metadata_ref.number = number; block_metadata_ref.author= author; block_metadata_ref.parent_hash = parent_hash; diff --git a/sources/TransactionManager.move b/sources/TransactionManager.move index a26498c4..526e00be 100644 --- a/sources/TransactionManager.move +++ b/sources/TransactionManager.move @@ -3,7 +3,6 @@ address StarcoinFramework { /// 1. prologue and epilogue of transactions. /// 2. prologue of blocks. module TransactionManager { - use StarcoinFramework::Option; use StarcoinFramework::Authenticator; use StarcoinFramework::Account::{exists_at, is_signer_delegated, transaction_fee_simulate, balance, Account, Balance @@ -226,7 +225,7 @@ module TransactionManager { number: u64, chain_id: u8, parent_gas_used: u64, - parents_hash: Option::Option>, + parents_hash: vector, ) { // Can only be invoked by genesis account CoreAddresses::assert_genesis_address(&account); From 02192bec74d83846fabd66a6d54bcf55825d60c8 Mon Sep 17 00:00:00 2001 From: simonjiao Date: Sun, 28 Jan 2024 19:35:26 +0800 Subject: [PATCH 5/9] add block_prolonge_v2 and process_block_meta_v2 --- build/StarcoinFramework/BuildInfo.yaml | 2 +- .../bytecode_modules/Block.mv | Bin 2640 -> 2712 bytes .../bytecode_modules/TransactionManager.mv | Bin 2489 -> 2564 bytes build/StarcoinFramework/docs/Block.md | 45 ++++++++++++++- .../docs/TransactionManager.md | 54 +++++++++++++++++- .../StarcoinFramework/source_maps/Block.mvsm | Bin 18509 -> 19184 bytes .../source_maps/TransactionManager.mvsm | Bin 19100 -> 20059 bytes release/StarcoinFramework.v0.1.0.blob | Bin 114056 -> 114203 bytes sources/Block.move | 17 +++++- sources/TransactionManager.move | 25 +++++++- 10 files changed, 133 insertions(+), 10 deletions(-) diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml index c6443f94..cd88cac2 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: 90888FA081474D37F4BF44DF0EC799C2B01C10750D4955CBE34B7C4D919C70AA + source_digest: ACB946891FC53BC3D9C7F256E8E66057FF6A2C37E0B77D70D56F4752448542EE build_flags: dev_mode: false test_mode: false diff --git a/build/StarcoinFramework/bytecode_modules/Block.mv b/build/StarcoinFramework/bytecode_modules/Block.mv index d9c1080694215d339962b9b3b31e17be858ab90d..1e09c42eb28b2d184712709b331c03eb2bcef5aa 100644 GIT binary patch delta 817 zcmZ8fJ8u&~5T2R6+q=Cz+q?GVVaM;-zQiGrcfupV1dym`XpyWCQt=2P5r`^(f#@14 zB&ZM_N<~476w%O8BM=Qx(@-#Hz)0*$-|Wopymr3#(UXy-XXUS20)R${C~At8Z|FRy zmiv}|p!df4DgD>l$Yb3PUW6Orm++I9IX+y9v2}R;+Chi_WyMg*Aczyb4{{cB2;ND{ zC{N`JjB~k&aXyD^Ul{cn7sv8!SbnH0{J%An3w zQ~&i^ojup<4aSY;)im(=CSOnwJ)jGcpKSUq1pgu%olCNV(z!f^D6Ptyf{DzC88u^O z+!WNfYE+tL(zH}tO_^?crky;*SV5tX-M-bov$MZ- zb8COA|6t+how!TAs;C82cN?M^(4=>bz4#bC&z8bm7SrJjmYoPy7PYeFFkl(jN~pt-Puf;P zJ&?6Oa^gQ($IxVQ8rK4yv!w+652_do{x+a;^3jiKoi1tAV1XQT*otJiSRU+T7=VqF zNKGGfX28gZJOtjZO;s-w+o6UvlZRR0 zS^x#erGb9WEXaqu)9E5!a_q$hma`f`2xh_4~V9rp-7K} z(Doq24$kN zJ;Iy)yzkk)K5gJF2pBE}rQ8mOz`}D9y*nZS;oVIEL{U0hvSl0FirukQTas1TYxV8G z4&_Lub~2idvZs(N><3$;s9*+Rh&bdRf6}AYblamdj&z@>c&QpTfP~tVPphax~5SSm1`Mo z46U?l8@-90f3fjj?1Cv4tcFvit*d8~@LQ*ra&m-W)3|^f`8%oxTxgg}vW~2Yflnn%cuQrBin>DNcJn5RZGS_9OSWX$%09|^IhmmY oq~`%_e5fg(zCf!U8MCKOng!A^KXr<0v@6rDS7=FPmhlQh%U^tDNvqD#T08}T3LpYYBLSO;>+oO|v)=icFcj9-q-zpMShkTDhko8dDi zSo{s*Ew9T@{1>QK;)BxPuoV8p_h6qFe(cX*1h&6D)?*a~Ai}BvCTpNsG=a!UbyEOQ zY!rb7%^_eqEjcD8hk@BCD1%Vb;3&3y#B3B;p=}Zt&OpMVS*jnN!!mP6k}|`iW5C=o z`UmrsDud$*l|(0qqZWt_y~P?ZI7#{V)I=GWIbE+aIMX2TY?C}dCnbBOa|McU-nY3x zA-YHn_@z2ESW1Y$oFFqch=<}*>|z;*aW$^mrk;wY<0;#+tvIrV2aR=r?)L7zr(5gK7W=i}b!D7@jjg@C^+9@P>q&RB z`=m?hgYUst-UEva0XYUJP-2J*^<_;DlOG2hfF7w`WKKDaDiul^C7ee(%wmxl?kFM{ zvSy?SF>;pBkXlOAu3!yiLo~Snx+3S)5DEj;%hUg){x^V82Y5idk<1JCQFU9xTzKFn z0kIoNMJOW`xN>{oswkaz)!$dEy-_hQ7gT{f8m)#>an%?%GAXX)m5ErASCq;Jpt%j% z9h0l5RVfv#Ib&ShkgG})gG*8zUqP~PxExop)}n!qGBy(>87uB;?GA5>hMVYUgY`_* zWJ5`>Pm2wyM}9_K-GFQKU+5%A-DLlbo`#A37oGGxrTWmz5Fz_F8C}{<;U}|hhI+Y% zXkg${H)|jjRasXdX~BRw|e=Dk7 xtC2uQVU&p#c|Fhjk=Fc3s55a}t__MfDILi~S8ggKb$VsGr{cccQO2)~{RIroVkZCq delta 961 zcmX|AJ#XAb5ZzhMa=ANu)GhB!N%zh3i6<%cIZ_mbN*sSwh7kiXAOkjFAc`!zaiZ9; z)nB7O5L_Xo3Je!1QwS+i`WL7-(k4y1{DREVLAH3{%)FU-Z%LlEe{ap+^!}z;2w_01 z%XJ%V{|R^|2kJL@0s0hw*2!CH#^>}4xcBbYA7|I+fFh58aTx=ysDP_6W86tVs4f^` zde(|&KXHKRpaCKprXZ5hQd3~zLAWur0rh2QGEM^0+9eQ;GRZ|egX(KP~4kU%fbb_WJd~lkZ;~eRpvD?Bww2;mP6oKhZlm z*V9z^*lW@SYGpP0gfo?JlnN`oO$CAF1yU~bD(Ih zdCTyttWRB5Ow^Q+sX$7mwaT!!T0GR>u6Y@S%mdD3zExnXjE;PJ`axByd{DLcL+{To z;Y@Am25Yp5UMld8wZ1jR+jVD-H`HydYXhvnvfO30Pl;|8xL-3?@V?sD2{R<}#+7@- z8d&>(;{2*}jx1E#x)PhJrKRsqD>=fU?^TJVs>GfeY8Cdg#h7Q*C-;2|et=ifs4^pG z)XX?T26vbh`H?Rcepublic fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: vector<u8>) +
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64)
 
@@ -512,7 +513,47 @@ Call at block prologue Implementation -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector<u8>) acquires BlockMetadata{
+
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64) acquires BlockMetadata{
+    Self::process_block_metadata_v2(account, parent_hash, author, timestamp, uncles, number, Vector::empty<u8>())
+
+}
+
+ + + + + +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if number != global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+
+ + + +
+ + + +## Function `process_block_metadata_v2` + +Call at block prologue for flexidag + + +
public fun process_block_metadata_v2(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun process_block_metadata_v2(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector<u8>) acquires BlockMetadata{
     CoreAddresses::assert_genesis_address(account);
 
     let block_metadata_ref = borrow_global_mut<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
diff --git a/build/StarcoinFramework/docs/TransactionManager.md b/build/StarcoinFramework/docs/TransactionManager.md
index f45beb27..33f76b55 100644
--- a/build/StarcoinFramework/docs/TransactionManager.md
+++ b/build/StarcoinFramework/docs/TransactionManager.md
@@ -13,6 +13,7 @@
 -  [Function `epilogue`](#0x1_TransactionManager_epilogue)
 -  [Function `epilogue_v2`](#0x1_TransactionManager_epilogue_v2)
 -  [Function `block_prologue`](#0x1_TransactionManager_block_prologue)
+-  [Function `block_prologue_v2`](#0x1_TransactionManager_block_prologue_v2)
 -  [Function `txn_prologue_v2`](#0x1_TransactionManager_txn_prologue_v2)
 -  [Function `txn_epilogue_v3`](#0x1_TransactionManager_txn_epilogue_v3)
 -  [Module Specification](#@Module_Specification_1)
@@ -464,7 +465,7 @@ Set the metadata for the current block and distribute transaction fees and block
 The runtime always runs this before executing the transactions in a block.
 
 
-
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: vector<u8>)
+
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64)
 
@@ -483,6 +484,55 @@ The runtime always runs this before executing the transactions in a block. number: u64, chain_id: u8, parent_gas_used: u64, +) { + Self::block_prologue_v2(account, parent_hash, timestamp, author, auth_key_vec, uncles, number, chain_id, parent_gas_used, Vector::empty<u8>()) +} +
+ + + +
+ +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `block_prologue_v2` + +Set the metadata for the current block and distribute transaction fees and block rewards. +The runtime always runs this before executing the transactions in a block. +For Flexidag block + + +
public fun block_prologue_v2(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun block_prologue_v2(
+    account: signer,
+    parent_hash: vector<u8>,
+    timestamp: u64,
+    author: address,
+    auth_key_vec: vector<u8>,
+    uncles: u64,
+    number: u64,
+    chain_id: u8,
+    parent_gas_used: u64,
     parents_hash: vector<u8>,
 ) {
     // Can only be invoked by genesis account
@@ -496,7 +546,7 @@ The runtime always runs this before executing the transactions in a block.
 
     // then deal with current block.
     Timestamp::update_global_time(&account, timestamp);
-    Block::process_block_metadata(
+    Block::process_block_metadata_v2(
         &account,
         parent_hash,
         author,
diff --git a/build/StarcoinFramework/source_maps/Block.mvsm b/build/StarcoinFramework/source_maps/Block.mvsm
index 47ce2d08f219bbd401fb3386b8c5583564f90a47..21d5047f4e3308ec2ab2e7f32bb012b492369b60 100644
GIT binary patch
literal 19184
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

literal 18509
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
yLwUWx@`(!(<4NY$g*z+|a6MthgW1
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�oWQ67;5^KZ#GYua6?K@+VN?(r
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

delta 1719
zcmZ8h&5smC6t7oZ)z$Se-BUfiJ-hQgvok$A3%jrjE)6Wpf(BzG(PT9-ArV)=5EU@O
z+0n#2jdBFQL+I{2!DWHykNYT7)>~>bkLb?Y5OJGdK-}&F+ULeR#QE5wW!@Gs
zXa@%Iol+8bWWpn`kio8r5`i>(+MU6ki87IUt6BVFt&Wk4^#1C~H=L%TEzQ7lfI4lbqiCWzC`zf*)h>82<@6kf@~Ttk)6U2p
zFO%d3?`~{|U~p^WAVh!@yA@vL=K>9>(g9}WisWg^jfX2l%EKGE|0_-ow%xqBINo*ewg@d7D;}O1
zu%02dGfg#UVhLry&O>(ifneR!FDz`%asR2i6&`2Br^oL5TL-Y2DLzO!hj@V4*4avGx+mX11~qe
zy{nuXxgix~Pb{TAFbs1rdv5*Y?eFi+Z4~~SaO5>br<61QGq548@vrE&Al_z|h4&dw
z_`3ca%sq3(9bCOr8h-pN_`?hDL!l3h#10@9S%%|0!wDDBEn(xl43fx-!W*x82AE$%
zMot|C;5C9gVND!%(}Du&Q#~dAn_OwiaQgkaMS>1Ga;WE6?u@vW@6rMp-XbVl|aw!}eb??*ixy@(|%b&nX
ze~iuYIgvw_$`e78J+723wAg`BXv~)Q0n~BU0&-ADxX4$uC-P0UGV&N_PxBSwp$Do7
zWq%ll(|t$}wQ7u3kP2lImgfaQZMmD$2CLgj>M5NjtitPpXZ5kkO|izds=(IRR^Lfw
z!$>|WjntCuL@&oSY;)LIgZ9aaQA+7ts*#&cO`79R;?5t*xpX??f>}D7{o^KSu&jS$
zyI2ql)JN&26f{|x*My5icrUZzX|Kr=-pg#mYim#lCyc~Tjwk#MTj0Ah(u4C~#KYg$
zz&}*Rbg9rXVTbusqkgh3k7QkHFJaH|Blnxc&xD;$*eX9RG}gjbkNYNjnV%BMdN-Co
Ig&)fQ0@tdyQUCw|

diff --git a/sources/Block.move b/sources/Block.move
index e43a1372..bfa5d88b 100644
--- a/sources/Block.move
+++ b/sources/Block.move
@@ -128,9 +128,20 @@ module Block {
     spec get_current_author {
         aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
-
     /// Call at block prologue
-    public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector) acquires BlockMetadata{
+    public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64) acquires BlockMetadata{
+        Self::process_block_metadata_v2(account, parent_hash, author, timestamp, uncles, number, Vector::empty())
+
+    }
+
+    spec process_block_metadata {
+        aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+    }
+
+    /// Call at block prologue for flexidag
+    public fun process_block_metadata_v2(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector) acquires BlockMetadata{
         CoreAddresses::assert_genesis_address(account);
 
         let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
@@ -153,7 +164,7 @@ module Block {
         );
     }
 
-    spec process_block_metadata {
+    spec process_block_metadata_v2 {
         aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
         aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
         aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
diff --git a/sources/TransactionManager.move b/sources/TransactionManager.move
index 526e00be..d98607a8 100644
--- a/sources/TransactionManager.move
+++ b/sources/TransactionManager.move
@@ -225,6 +225,27 @@ module TransactionManager {
         number: u64,
         chain_id: u8,
         parent_gas_used: u64,
+    ) {
+        Self::block_prologue_v2(account, parent_hash, timestamp, author, auth_key_vec, uncles, number, chain_id, parent_gas_used, Vector::empty())
+    }
+
+    spec block_prologue {
+        pragma verify = false;//fixme : timeout
+    }
+
+    /// Set the metadata for the current block and distribute transaction fees and block rewards.
+    /// The runtime always runs this before executing the transactions in a block.
+    /// For Flexidag block
+    public fun block_prologue_v2(
+        account: signer,
+        parent_hash: vector,
+        timestamp: u64,
+        author: address,
+        auth_key_vec: vector,
+        uncles: u64,
+        number: u64,
+        chain_id: u8,
+        parent_gas_used: u64,
         parents_hash: vector,
     ) {
         // Can only be invoked by genesis account
@@ -238,7 +259,7 @@ module TransactionManager {
 
         // then deal with current block.
         Timestamp::update_global_time(&account, timestamp);
-        Block::process_block_metadata(
+        Block::process_block_metadata_v2(
             &account,
             parent_hash,
             author,
@@ -252,7 +273,7 @@ module TransactionManager {
         BlockReward::process_block_reward(&account, number, reward, author, auth_key_vec, txn_fee);
     }
 
-    spec block_prologue {
+    spec block_prologue_v2 {
         pragma verify = false;//fixme : timeout
     }
 

From 975539d8bcad6210b443a5f26685bd2e0d14263f Mon Sep 17 00:00:00 2001
From: simonjiao 
Date: Mon, 29 Jan 2024 09:24:54 +0800
Subject: [PATCH 6/9] add new structs for blockmetadata and newblockevent

---
 build/StarcoinFramework/BuildInfo.yaml        |   2 +-
 .../bytecode_modules/Block.mv                 | Bin 2712 -> 2879 bytes
 .../bytecode_modules/FlexiDagConfig.mv        | Bin 326 -> 371 bytes
 build/StarcoinFramework/docs/Block.md         | 237 +++++++++++++++---
 .../StarcoinFramework/docs/FlexiDagConfig.md  |   4 +-
 .../docs/TransactionTimeout.md                |   4 +-
 .../StarcoinFramework/source_maps/Block.mvsm  | Bin 19184 -> 20581 bytes
 .../source_maps/FlexiDagConfig.mvsm           | Bin 1158 -> 1242 bytes
 .../source_maps/TransactionTimeout.mvsm       | Bin 1393 -> 1393 bytes
 release/StarcoinFramework.v0.1.0.blob         | Bin 114203 -> 114415 bytes
 sources/Block.move                            | 120 ++++++---
 sources/FlexiDagConfig.move                   |   2 +
 sources/TransactionTimeout.move               |   4 +-
 13 files changed, 299 insertions(+), 74 deletions(-)

diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml
index cd88cac2..e1cca14e 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: ACB946891FC53BC3D9C7F256E8E66057FF6A2C37E0B77D70D56F4752448542EE
+  source_digest: 9280A56F445BC59176E3E1323C8B6159C411D74258DCD6679977DD49BA0C45D5
   build_flags:
     dev_mode: false
     test_mode: false
diff --git a/build/StarcoinFramework/bytecode_modules/Block.mv b/build/StarcoinFramework/bytecode_modules/Block.mv
index 1e09c42eb28b2d184712709b331c03eb2bcef5aa..e72b98b179bbd3497ba9e60fbecbaac3c9309ef0 100644
GIT binary patch
delta 1282
zcmZ8hO>Z1U5Ur}7>7MEC-I-p``eS!(uRqsbJAoKT3^<7iNkBqy1QC#|C0MdWFo;+|
z;^H5Ggd)ua!HHi05*KbcaN)oS6!9035C?832gK{OWh7df*HzW^s;g_d`pfpC$&+t-
ze>hDs|jn?+AxtZ36M&#DTpFEX+^^X1F96z)__SygegX-Y0ime
zB6KVkx^cC~;LRdmn)8799MEqtsi(4x^wV50nM(nvw^|dxXNn5=Y=J$@bCVhH@>C0!
z%dKgq6LkfwbUV+9pYLSEFGP5;(dzFuyu
zY^-grDU&H>g;-}wAPDsOAz!>>I1_dTm4G0|Wso52Qxiioij`8)kcqZ}rRXE4lVY7y
zp_r|}DGoDs1lH5izZzW?M;n3~&`w1th!S^>4xAx(AG
z<`|FA^Ldk99%jA8Y{Q&)-a~R>-n;SKKbw31n-|!Zjl%J^bw%jb>)CHRoq@u&Vb$}&
z#9KWcQ=UWSDGY|nv7YaS{U7SfkWacysHn`N4pu^5pQwgs6
zxtdjiJ~>zON@728BMf6eiyl53j>ACLkMi~j4W{E7f|F-UmP=a!Tm)Y^E*sVE>^Y6L
zLyIr4pe2!S0+tFaXiMywJ3KE=oN|dv|Ko(FG~@dEB^(v|4A~o-T2q<|2dign3x8(Q
zcHeHct+uAf+s+h)OV1+dR=V91^f~rJ2~aXTDN=F*9pwu}ya0GBL7IV<&h+l=-QK=#Z*On+e8(A#@%b=*^7sKxomiHIWD?85EFGqiRO+=ol
zmU^a+|KjXRndd*tYc@Y*|LEd7U+Gu=zWXZN41a{*P3u+N2Z2dQQARmwGE|TyS0Ifc
z3W2DlDVt}kS!=^Y#$-ThgGHq%qAJ;u`IM-WL+xrn&0zN!X*SprZ6@eDyx3w;1}Kq+
z0Wh+Faf?a4Q52+)xMVUHBT&ED=>p#>Yv84l;eUIh0AAkgz;n6N2k9M<@+;O79}i9o
z;;RF|$zVwQZqlwLcyBNwdwr4;+}NIidSki+yg5sWZ_VJB+o)FVplw8E1IpML!Kv#0kTJ$U-4d6rGS
z{XTom*YrefJDKJ?YUX4YDUe9io?19rVoMxT)c$It3+g~A$tP->A1Z`5)?DSPxnq{h
z%_rv9hg(ZQ<7_=+W8xr`ZBEU)T5%X`o4t*r;2>Qb2Ok17A1A@D>S!5-Xi_h()@I;X1d59T@$4y*WSk+0C8B6V?FL72*?eusr*b3$
zBAz@h4yn?$p!3(JsRezwHj7%&#B0;mlKPz6@j^=IFjMEtb6l*A+vByHPO1(a5$Ylq
z&f=BDp+pvp2OjG&&tAOpna}?t#g<@bn3k7tmL*O_%{Oj>>;A}RNMdn

diff --git a/build/StarcoinFramework/bytecode_modules/FlexiDagConfig.mv b/build/StarcoinFramework/bytecode_modules/FlexiDagConfig.mv
index 50363aad2d38813b79e3db9110a7ffe10a62642e..243f8a06b159d837f03298c27c88714a0f20a5e6 100644
GIT binary patch
delta 216
zcmYk0y$%6U6oluT`?q`Vl3kG~Xf--QqE@SQBI_ryv1m35h3GXrf+z42;$@Udjk}$x
zX1<)9nHPU}dT+g*24D#R2U0|B*_CS0FyjXWUyAL8RdnTk<;m>N2n+!jKza|wK4_9)
z14TvzT7W|%$dL8+HtA?J%J+-S?R;7{vt3qXX`UTdvv~=(t0G;dMLIk5{Of=D8j_-H
hkj7z%h^iE$&g6**EfQ(rDB&SFB$~Oz!lCBZ0Y6%W8v_6U

delta 170
zcmYj~u?@md3`Fnj|G%UE141~Bj5ZV$w$f8%j
+Fields
+
+
+
+
+number: u64 +
+
+ number of the current block +
+
+parent_hash: vector<u8> +
+
+ Hash of the parent block. +
+
+author: address +
+
+ Author of the current block. +
+
+uncles: u64 +
+
+ number of uncles. +
+
+new_block_events: Event::EventHandle<Block::NewBlockEvent> +
+
+ Handle of events when new blocks are emitted +
+
+ + +
+ + + +## Struct `NewBlockEvent` + +Events emitted when new block generated. + + +
struct NewBlockEvent has drop, store
+
+ + + +
+Fields + + +
+
+number: u64 +
+
+ +
+
+author: address +
+
+ +
+
+timestamp: u64 +
+
+ +
+
+uncles: u64 +
+
+ +
+
+ + +
+ + + +## Resource `BlockMetadataV2` + +Block metadata struct. + + +
struct BlockMetadataV2 has key
+
+ + +
Fields @@ -91,7 +192,7 @@ Block metadata struct. An Array of the parents hash for a Dag block.
-new_block_events: Event::EventHandle<Block::NewBlockEvent> +new_block_events: Event::EventHandle<Block::NewBlockEventV2>
Handle of events when new blocks are emitted @@ -101,14 +202,14 @@ Block metadata struct. - + -## Struct `NewBlockEvent` +## Struct `NewBlockEventV2` Events emitted when new block generated. -
struct NewBlockEvent has drop, store
+
struct NewBlockEventV2 has drop, store
 
@@ -326,7 +427,6 @@ This can only be invoked by the GENESIS_ACCOUNT at genesis parent_hash, author: CoreAddresses::GENESIS_ADDRESS(), uncles: 0, - parents_hash: Vector::empty(), new_block_events: Event::new_event_handle<Self::NewBlockEvent>(account), }); } @@ -348,6 +448,58 @@ This can only be invoked by the GENESIS_ACCOUNT at genesis + + + + +## Function `initialize_blockmetadata_v2` + + + +
public fun initialize_blockmetadata_v2(account: &signer)
+
+ + + +
+Implementation + + +
public fun initialize_blockmetadata_v2(account: &signer) acquires BlockMetadata {
+    CoreAddresses::assert_genesis_address(account);
+
+    let block_meta_ref = borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
+    // create new resource base on current block metadata
+    move_to<BlockMetadataV2>(
+        account,
+        BlockMetadataV2 {
+            number: block_meta_ref.number,
+            parent_hash: block_meta_ref.parent_hash,
+            author: block_meta_ref.author,
+            uncles: block_meta_ref.uncles,
+            parents_hash: Vector::empty(),
+            new_block_events: Event::new_event_handle<Self::NewBlockEventV2>(account),
+        });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<BlockMetadata>(Signer::address_of(account));
+ensures exists<BlockMetadataV2>(Signer::address_of(account));
+
+ + +
@@ -366,8 +518,8 @@ Get the current block number Implementation -
public fun get_current_block_number(): u64 acquires BlockMetadata {
-  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number
+
public fun get_current_block_number(): u64 acquires BlockMetadataV2 {
+    borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).number
 }
 
@@ -380,7 +532,7 @@ Get the current block number -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
@@ -403,8 +555,8 @@ Get the hash of the parent block. Implementation -
public fun get_parent_hash(): vector<u8> acquires BlockMetadata {
-  *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parent_hash
+
public fun get_parent_hash(): vector<u8> acquires BlockMetadataV2 {
+    *&borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).parent_hash
 }
 
@@ -417,20 +569,21 @@ Get the hash of the parent block. -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
- + -## Function `get_parents_hash` +## Function `get_current_author` +Gets the address of the author of the current block -
public fun get_parents_hash(): vector<u8>
+
public fun get_current_author(): address
 
@@ -439,8 +592,8 @@ Get the hash of the parent block. Implementation -
public fun get_parents_hash(): vector<u8> acquires BlockMetadata {
-    *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parents_hash
+
public fun get_current_author(): address acquires BlockMetadataV2 {
+    borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).author
 }
 
@@ -453,21 +606,20 @@ Get the hash of the parent block. -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
- + -## Function `get_current_author` +## Function `get_parents_hash` -Gets the address of the author of the current block -
public fun get_current_author(): address
+
public fun get_parents_hash(): vector<u8>
 
@@ -476,8 +628,8 @@ Gets the address of the author of the current block Implementation -
public fun get_current_author(): address acquires BlockMetadata {
-  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).author
+
public fun get_parents_hash(): vector<u8> acquires BlockMetadataV2 {
+    *&borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).parents_hash
 }
 
@@ -490,7 +642,7 @@ Gets the address of the author of the current block -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
@@ -513,7 +665,12 @@ Call at block prologue Implementation -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64) acquires BlockMetadata{
+
public fun process_block_metadata(account: &signer,
+                                  parent_hash: vector<u8>,
+                                  author: address,
+                                  timestamp: u64,
+                                  uncles:u64,
+                                  number:u64) acquires BlockMetadataV2{
     Self::process_block_metadata_v2(account, parent_hash, author, timestamp, uncles, number, Vector::empty<u8>())
 
 }
@@ -529,8 +686,8 @@ Call at block prologue
 
 
 
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
-aborts_if number != global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if number != global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
 
@@ -553,10 +710,16 @@ Call at block prologue for flexidag Implementation -
public fun process_block_metadata_v2(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector<u8>) acquires BlockMetadata{
+
public fun process_block_metadata_v2(account: &signer,
+                                     parent_hash: vector<u8>,
+                                     author: address,
+                                     timestamp: u64,
+                                     uncles:u64,
+                                     number:u64,
+                                     parents_hash: vector<u8>) acquires BlockMetadataV2 {
     CoreAddresses::assert_genesis_address(account);
 
-    let block_metadata_ref = borrow_global_mut<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    let block_metadata_ref = borrow_global_mut<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
     assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
     block_metadata_ref.number = number;
     block_metadata_ref.author= author;
@@ -564,9 +727,9 @@ Call at block prologue for flexidag
     block_metadata_ref.uncles = uncles;
     block_metadata_ref.parents_hash = parents_hash;
 
-    Event::emit_event<NewBlockEvent>(
+    Event::emit_event<NewBlockEventV2>(
       &mut block_metadata_ref.new_block_events,
-      NewBlockEvent {
+      NewBlockEventV2 {
           number,
           author,
           timestamp,
@@ -587,8 +750,8 @@ Call at block prologue for flexidag
 
 
 
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
-aborts_if number != global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if number != global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
 
@@ -598,7 +761,7 @@ Call at block prologue for flexidag
schema AbortsIfBlockMetadataNotExist {
-    aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 }
 
@@ -666,7 +829,7 @@ Call at block prologue for flexidag Implementation -
public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints {
+
public entry fun checkpoint_entry(_account: signer) acquires BlockMetadataV2, Checkpoints {
     checkpoint();
 }
 
@@ -702,7 +865,7 @@ Call at block prologue for flexidag Implementation -
public fun checkpoint() acquires BlockMetadata, Checkpoints{
+
public fun checkpoint() acquires BlockMetadataV2, Checkpoints{
     let parent_block_number = get_current_block_number() - 1;
     let parent_block_hash   = get_parent_hash();
 
diff --git a/build/StarcoinFramework/docs/FlexiDagConfig.md b/build/StarcoinFramework/docs/FlexiDagConfig.md
index bda75c0e..c8090f6e 100644
--- a/build/StarcoinFramework/docs/FlexiDagConfig.md
+++ b/build/StarcoinFramework/docs/FlexiDagConfig.md
@@ -12,7 +12,8 @@
 -  [Module Specification](#@Module_Specification_0)
 
 
-
use 0x1::Config;
+
use 0x1::Block;
+use 0x1::Config;
 use 0x1::CoreAddresses;
 
@@ -91,6 +92,7 @@ Create a new configuration for flexidag, mainly used in DAO.
public fun initialize(account: &signer, effective_height: u64) {
     CoreAddresses::assert_genesis_address(account);
     Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height));
+    Block::initialize_blockmetadata_v2(account);
 }
 
diff --git a/build/StarcoinFramework/docs/TransactionTimeout.md b/build/StarcoinFramework/docs/TransactionTimeout.md index 9e5baaf1..01d2b3f2 100644 --- a/build/StarcoinFramework/docs/TransactionTimeout.md +++ b/build/StarcoinFramework/docs/TransactionTimeout.md @@ -56,7 +56,7 @@ Check whether the given timestamp is valid for transactions.
aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
-aborts_if !exists<Block::BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if !exists<Block::BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 include Timestamp::AbortsIfTimestampNotExists;
 aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
 aborts_if Block::get_current_block_number() != 0 && !exists<Config::Config<TransactionTimeoutConfig::TransactionTimeoutConfig>>(CoreAddresses::GENESIS_ADDRESS());
@@ -70,7 +70,7 @@ Check whether the given timestamp is valid for transactions.
 
 
schema AbortsIfTimestampNotValid {
     aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
-    aborts_if !exists<Block::BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if !exists<Block::BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
     include Timestamp::AbortsIfTimestampNotExists;
     aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
     aborts_if Block::get_current_block_number() != 0 && !exists<Config::Config<TransactionTimeoutConfig::TransactionTimeoutConfig>>(CoreAddresses::GENESIS_ADDRESS());
diff --git a/build/StarcoinFramework/source_maps/Block.mvsm b/build/StarcoinFramework/source_maps/Block.mvsm
index 21d5047f4e3308ec2ab2e7f32bb012b492369b60..63f80aa9aa7b67e9df91600147a5d558e233d8a4 100644
GIT binary patch
literal 20581
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%0DWIESV7SD72Rk$46u~e>9
zuydew<6kwod~q+p587JzY9`m8I>dFLpWPv>qoAMNCaiZrKf52X!U(_gygUjk1@yd}
zgH-@}UarP^81%fn6KfafdD%YmaM1Jeaa$gyo|ijf#$f7s`83b-Jm?Rrv6R;t9188w
zmVFCwk0u6U4~3AnSI&u)2CEAL93xPN2!6#iJ8Vs?7s_3Nx6;-j%|fgPL3iA@us#Rf
zad%a72zg#WeGl}wTaWbw=y7)z%V+=MLU)vi7(Pvd33FXS>&@Xfq)?=Vw=;K(MK~JPxv37!7h`@3Cfv1)-i957rgYIq@wb3u7d?%74&1wFr#KF)fMXY(h?-}0x1)^rpe}=m
zD}ilQz$LPMi3<)uNQbL&#jHZN*kVXmGCSZXgd7racs)T6i3VB|kEw^m9azgj4~a2Y
zQ$Y_2@1FFKc%1S!gB}u3V(kMxB&_*5=-A=_)^9<_7H?p^2|Co>g0&5F6tWiUThI~1
zIjl>dPw^eXx(qtD@M_nwMYn56PC>^OKCDg_*^{l=6?AN2OBy@0RB+6a09pN~}!dI7iACU97rE)%yz+WQZ6
z{t(p;Jr*3Fa6D>XTZ2m)Sb|sy`Uw|cRe^rO)~W^*-ab7mGkyG|oUs%00uwSPj>*dk
zHBo63a?-~KvNHV{nYoSs%My6ye-Sft^ZgS76Q^XSW#)#M=*%m>xbp8n_SnhU{=D=o
zAHT@W&B+Z+%*hMz>%

literal 19184
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

diff --git a/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm b/build/StarcoinFramework/source_maps/FlexiDagConfig.mvsm
index f5c470d5bf2f6c72dc49831a1d7a47ecb4e232e7..d3ecfcbb4e666f0f87a44ce3113dc6e0e44978b6 100644
GIT binary patch
literal 1242
zcmb7@y-LJT5Jo5a7j2e2!h(V*h!(EGHWn@lc4}`7F@GRQirqyJ3o8r77qAfo!N$VE
zM-UXW5VQ~ls})?_PAv6A5bP!fPL(rr=YGTO^*<*%FUKoq+v6wg@Z;e5{4RR$HX8o!
z+kG;+KQL94V(ks3%@pKB3s2@ExsA*^L6sOInaMb%uRUkasM
z<_>0#L04Hv2vW!!b%dRQ<@vtnwxW(_hh7wf>W;Q3+RKiTK|ShA#2e6~KEk>MJ!-Qg
zQUyKgVXP_8qqeZ>P*#`n#EjFJ71a!|VlY*+iIu>BYGzgnIbyotkzN6h>Ax$!rtC2*
Umt1HGy+p8x;=

literal 1158
zcmb7@%_{_P7=YiI{VH2)rd+tO;xAAfSuNqJTr^E%W_C)usa@piV4W!cfTHZdMajuU
zY2Do2aN4+WljQj+<@S!L=QPjzJ=68CAE)m+V?#^D{l#kWxjeryP@cM9Js)k)^*&dQ
z#zkZTEcp9arRsXPoy_`irBRQPnD<>JRSRd=lN?KR8iM*i}en+YW~*GsHRmAaUq+^9KlS{
z=p^Tu0kPArx`Mp`P8daD&`dT%uNEe8O})`FL7^!nw5FZq81W4BRqtSRKwtF}RuA-5
ze_@rfX;%G$*^il1C%VFPF!QQuEEiIYbjS~N0(|)YJ;y0wmnM`lYD*tDeGH(V;{kIJ
GQ{)@;<&?qz

diff --git a/build/StarcoinFramework/source_maps/TransactionTimeout.mvsm b/build/StarcoinFramework/source_maps/TransactionTimeout.mvsm
index 31b8e697cdc3ec4a952a8a044db42680465014ee..8aab55651c355e4015a0c98bddf8ca89fb6f4550 100644
GIT binary patch
literal 1393
zcmajfze@sP9LMqRd1qI8W@=V*W=lgjML9bZ4G}_F!EuR@l#h8nf>Q($NJB$}OG|sJ
zbALb()X?0Its$C&hCUY^w0#cV+w1vpk3QG`*nB+y&RpIUuP;jV_1KxSx2BYvvMb5>
z!`FPz6_FM)(ErCsmwivQy{fJ^Rk_}%H9I;$eKOyiDYA^jNa(I|HAc3z*EnS3RxoA*
zS!O<0VEEG#DMUrm)sFAily-Lyn$`W^#n@1VHI9+f@VaieLpJCZ>)jzccpV%B^GC3!
zNT&FKonSLp$e>3XZaqTf0P{T|lgcIRvWP4y7oZkVl*(BsjfSXPg{mN%${i?$hN;|w
z+D0Q(mj339QQ3nWpg5J`FYi!!kNKWag333jcQi`n3)Cx0QW^fE$EXbMnt{8PqS6Xf
oa4V^dK$$2*Wq8xasmx-&X_Tch4;6epCaBCo&7est!+nbU0G2P`(f|Me

literal 1393
zcmajfJ4?e*7{>88O=7LKUaHmLXswGl6bDgf2Ssryh!+SkbO_p0ZBL<-3Mx3dJGggo
zu&(_8f)1iv!3!=LlOHO;z2(G5i9xksB>`&+Z?V@$uUe4Jo-;-@M
zl5qUHFIPnNkb(X`M!Hb(RMqo!P*#PYR4mtYh#F+R2~%VNiILKEfC6c#A(tfQ{DJt!5?UeoP-^JKag*6UQvgFm>XoqZ23+vsWc=$Rv2ct)b7at?jkX@6vWfW~kxAt&b~%SEDyN}lkWJ+{ltvv?E>

diff --git a/release/StarcoinFramework.v0.1.0.blob b/release/StarcoinFramework.v0.1.0.blob
index c495eefeeb915d4f831086cdf8737fbadba9647e..1e9519997ac12c24b5b4f4654400763ad339ea5b 100644
GIT binary patch
delta 1592
zcmaJ?JB%Df5Ur}7>F$~C-I>{&z3<-n{(Ii@2OEEupE(T14gd)PKoFc3ypm6t1L2b`
zIp7j9BV=g?CMo@RoAC$x@s=|
zrGNfge{}nD`}4sM8b3KrM2@MHvZW5);pmdg$G7AkHs3~{8hg&?`l4S>|L`ySTa})z
z+^$ddCa;XHTOx0WDxRnc7n!DLK4Q&U8zwR)0#Z)ELKIOgtOpoS#(=s83^E)HF+2@(
zLNpR!G=*X;Xd4W(ab!jl9X!}&;FCL_u8_)I>V&n5H8
z_Iz<}abd@TGFGWnh_zJ$MzHRk{dm{9VJqwmDgj1}v*5t%4H08y6f32Iz=}=^krkGQ~rtp~l#(=4WU$8+)1y(U4qzU1_8A-J{>_kA*mjxCJLT6GT*E+{LYn|u!_AXzY&z|X?>5Gq??yjyu_TAMl8e=P~
zD{CvAlPhPt%dZ5R*EemJPw(x$|H*r;e6@RKL$llscBfq5{8(r8_{pw+v-4JvEuZL|
zI&tN>Yrpdg@syfQWhS0gbI1-kir$hmQ|Sw15w)PUr_$;d14UTuA8d!(sUnG{)J(if
z&8k@7Y=dp~-no8|i{8!aO_tt|*S}sLZ3=Gn$ayxV81q?`L-X{XqT!P&yQCQRDQH?u
zc;`JhS8VgHPbW8N<3DtYeO}2Nw^NtFYn)Op?busTE>jzNq5llc^mgC4fgBVrBCCck
z%srjw!g?y2E#=rzK@xFwIpoTgK95QoUG#5G7rJ$9!
zmZlW+6tCY^+fvYyTk52g(7IeHS|L(OTaFzU&3g-K=QY|%g2rZQ4u`#nMxIkjIZsP~
z3*bw~d8J$$-#k4zY8N%$S!cmGz{w(*se%O~fw}k1&5@!i)xdAxg95;5i+jJ_oLDcK
zX`GtO)N%byrt6MDY(0%Ys`XTZBz0%9%*9Tea*@-uxLp$r7DPcQP*Th=$vMIrfDj_Fr(ceGx4_p=|4F8?BT*C>(|8!0~*?TO<3L*}VVZ2!c`
z&q?gh%f8B&@Ve;=bCf88TZ+RB)d(Vn&~(abgikOF(AQuud=+y`$NfgTa3|)s|F^|1
qe80d0tw;sOkwINi{VM191YnqvO7Kpi6nCVMcDPIW+J~A?UHcc_9kIgz

delta 1316
zcmZ8h&5ImG6o2nkbyas&&vf@}&wkAA&dz?#Y-ZgxF}fM^Z8YQ$@FKZ{JqQsbh^q%h
z*jzm*LW3&^0R_RMxNeqgj0X>afG1CaHw6_8cnFe91b;P~j9@qX-bcTWUsczuzy2|w
zJ~ChZ@%7-7=4Ug1dP78>sg!a-ZQN)5xhzF@mMa!fSN3DHD=Nrw+p
zjEok@&~yrzNdU7oCiPStlUd`8$*vbb^YnIO4B}{30*_^=Z=V^DfyXBr@EmVUBI{XX
zMb9M(@kT2qJ`rHhnkIfeXeR@lYRyn`x*hV*%yp1?rZW#byAbN0TYz8AgRQ&(-u6Pg
z#1y{>r+(>z>9WxmSC~zaH1e^$%$xamK9Nu6W65MPKf91G=1a+PvXb|gSC^HIML8ih
zu>?h6SMPtbemUZp*+V2HhOG7?xG6lnRcRjT3wdF>)vrn}jmO>;ysKvBN-M
zRqS;(La5^4Ls5&gLlp+9gw7#=W5r$%BjOODt806gtDp9|RsH7o)%}|v*3vgN-+cAj
zTU%GIZf;$z-raBSezE_MPnx!xbJB_C)q;~nlt3X-%c|?7hn85TsFh)(BdV{IL~YfH
zRu#gl2e(deUacPVn5&l$e%PMs3C_*bM{I4;O0znLV>x_^=`^XcPl}n;LAqi#^=S&t
z7wyy!<=kUA{Xf~^G_Pfz2hL}x8ac{k5T!9Bmo5%xarjIuRyS_nj;DGG|C^-R{I
z?Tcqm1&L-2Crg0^AY(CgRP?M2vJ~I_e?&)&8?q*X;&`K?yGpq!1;a5iZ7DdaBQq`q
z2YqBFrC=5=5!Z_&p_8LgVb4W(WSpOU%$__A@&>ID2onoy^pt`HBg9m_erKwv35JNN
zcMR+472Q5nAKz(j=RFrWo7tul2-EZo5jUNNa7||*lBTzr_mLN`y!NJ{28GmzU9d9j
z5EUXBYjjm0SH};>Mg,
+        /// Author of the current block.
+        author: address,
+        /// number of uncles.
+        uncles: u64,
+        /// Handle of events when new blocks are emitted
+        new_block_events: Event::EventHandle,
+    }
+
+    /// Events emitted when new block generated.
+    struct NewBlockEvent has drop, store {
+        number: u64,
+        author: address,
+        timestamp: u64,
+        uncles: u64,
+    }
+
+    /// Block metadata struct.
+    // parents_hash is for FLexiDag block
+    struct BlockMetadataV2 has key {
         /// number of the current block
         number: u64,
         /// Hash of the parent block.
@@ -31,12 +53,12 @@ module Block {
         /// An Array of the parents hash for a Dag block.
         parents_hash: vector,
         /// Handle of events when new blocks are emitted
-        new_block_events: Event::EventHandle,
+        new_block_events: Event::EventHandle,
     }
 
     /// Events emitted when new block generated.
     // parents_hash is for FLexiDag block
-    struct NewBlockEvent has drop, store {
+    struct NewBlockEventV2 has drop, store {
         number: u64,
         author: address,
         timestamp: u64,
@@ -83,7 +105,6 @@ module Block {
                 parent_hash,
                 author: CoreAddresses::GENESIS_ADDRESS(),
                 uncles: 0,
-                parents_hash: Vector::empty(),
                 new_block_events: Event::new_event_handle(account),
             });
     }
@@ -94,57 +115,94 @@ module Block {
         aborts_if exists(Signer::address_of(account));
     }
 
+    public fun initialize_blockmetadata_v2(account: &signer) acquires BlockMetadata {
+        CoreAddresses::assert_genesis_address(account);
+
+        let block_meta_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS());
+
+        // create new resource base on current block metadata
+        move_to(
+            account,
+            BlockMetadataV2 {
+                number: block_meta_ref.number,
+                parent_hash: block_meta_ref.parent_hash,
+                author: block_meta_ref.author,
+                uncles: block_meta_ref.uncles,
+                parents_hash: Vector::empty(),
+                new_block_events: Event::new_event_handle(account),
+            });
+    }
+
+    spec initialize_blockmetadata_v2 {
+        aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+        aborts_if exists(Signer::address_of(account));
+
+        ensures exists(Signer::address_of(account));
+    }
+
     /// Get the current block number
-    public fun get_current_block_number(): u64 acquires BlockMetadata {
-      borrow_global(CoreAddresses::GENESIS_ADDRESS()).number
+    public fun get_current_block_number(): u64 acquires BlockMetadataV2 {
+        borrow_global(CoreAddresses::GENESIS_ADDRESS()).number
     }
 
     spec get_current_block_number {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
     /// Get the hash of the parent block.
-    public fun get_parent_hash(): vector acquires BlockMetadata {
-      *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parent_hash
+    public fun get_parent_hash(): vector acquires BlockMetadataV2 {
+        *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parent_hash
     }
 
     spec get_parent_hash {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
-    public fun get_parents_hash(): vector acquires BlockMetadata {
-        *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parents_hash
+    /// Gets the address of the author of the current block
+    public fun get_current_author(): address acquires BlockMetadataV2 {
+        borrow_global(CoreAddresses::GENESIS_ADDRESS()).author
     }
 
-    spec get_parents_hash {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+    spec get_current_author {
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
-    /// Gets the address of the author of the current block
-    public fun get_current_author(): address acquires BlockMetadata {
-      borrow_global(CoreAddresses::GENESIS_ADDRESS()).author
+    public fun get_parents_hash(): vector acquires BlockMetadataV2 {
+        *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parents_hash
     }
 
-    spec get_current_author {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+    spec get_parents_hash {
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
+
     /// Call at block prologue
-    public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64) acquires BlockMetadata{
+    public fun process_block_metadata(account: &signer,
+                                      parent_hash: vector,
+                                      author: address,
+                                      timestamp: u64,
+                                      uncles:u64,
+                                      number:u64) acquires BlockMetadataV2{
         Self::process_block_metadata_v2(account, parent_hash, author, timestamp, uncles, number, Vector::empty())
 
     }
 
     spec process_block_metadata {
         aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
-        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
     }
 
     /// Call at block prologue for flexidag
-    public fun process_block_metadata_v2(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: vector) acquires BlockMetadata{
+    public fun process_block_metadata_v2(account: &signer,
+                                         parent_hash: vector,
+                                         author: address,
+                                         timestamp: u64,
+                                         uncles:u64,
+                                         number:u64,
+                                         parents_hash: vector) acquires BlockMetadataV2 {
         CoreAddresses::assert_genesis_address(account);
 
-        let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
+        let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
         assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
         block_metadata_ref.number = number;
         block_metadata_ref.author= author;
@@ -152,9 +210,9 @@ module Block {
         block_metadata_ref.uncles = uncles;
         block_metadata_ref.parents_hash = parents_hash;
 
-        Event::emit_event(
+        Event::emit_event(
           &mut block_metadata_ref.new_block_events,
-          NewBlockEvent {
+          NewBlockEventV2 {
               number,
               author,
               timestamp,
@@ -166,12 +224,12 @@ module Block {
 
     spec process_block_metadata_v2 {
         aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
-        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
     }
 
     spec schema AbortsIfBlockMetadataNotExist {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
     public fun checkpoints_init(account: &signer){
@@ -191,7 +249,7 @@ module Block {
         pragma verify = false;
     }
 
-    public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints {
+    public entry fun checkpoint_entry(_account: signer) acquires BlockMetadataV2, Checkpoints {
         checkpoint();
     }
 
@@ -199,7 +257,7 @@ module Block {
         pragma verify = false;
     }
 
-    public fun checkpoint() acquires BlockMetadata, Checkpoints{
+    public fun checkpoint() acquires BlockMetadataV2, Checkpoints{
         let parent_block_number = get_current_block_number() - 1;
         let parent_block_hash   = get_parent_hash();
         
diff --git a/sources/FlexiDagConfig.move b/sources/FlexiDagConfig.move
index 4ac2c486..75fa8e7a 100644
--- a/sources/FlexiDagConfig.move
+++ b/sources/FlexiDagConfig.move
@@ -1,6 +1,7 @@
 address StarcoinFramework {
     module FlexiDagConfig {
 
+        use StarcoinFramework::Block;
         use StarcoinFramework::Config;
         use StarcoinFramework::CoreAddresses;
         use StarcoinFramework::Signer;
@@ -27,6 +28,7 @@ address StarcoinFramework {
         public fun initialize(account: &signer, effective_height: u64) {
             CoreAddresses::assert_genesis_address(account);
             Config::publish_new_config(account, new_flexidag_config(effective_height));
+            Block::initialize_blockmetadata_v2(account);
         }
 
         spec initialize {
diff --git a/sources/TransactionTimeout.move b/sources/TransactionTimeout.move
index 0f8e55e5..c9dfa68d 100644
--- a/sources/TransactionTimeout.move
+++ b/sources/TransactionTimeout.move
@@ -36,7 +36,7 @@ module TransactionTimeout {
   }
   spec is_valid_transaction_timestamp {
     aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
-    aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     include Timestamp::AbortsIfTimestampNotExists;
     aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
     aborts_if Block::get_current_block_number() != 0 && !exists>(CoreAddresses::GENESIS_ADDRESS());
@@ -44,7 +44,7 @@ module TransactionTimeout {
 
     spec schema AbortsIfTimestampNotValid {
         aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
         include Timestamp::AbortsIfTimestampNotExists;
         aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
         aborts_if Block::get_current_block_number() != 0 && !exists>(CoreAddresses::GENESIS_ADDRESS());

From 18495e079a70076c590cc9c03db9494db631838b Mon Sep 17 00:00:00 2001
From: simonjiao 
Date: Fri, 2 Feb 2024 16:39:53 +0800
Subject: [PATCH 7/9] update release v13 files

---
 release/v13/BuildInfo.yaml                    |   2 +-
 release/v13/bytecode_modules/Block.mv         | Bin 2705 -> 2879 bytes
 .../v13/bytecode_modules/FlexiDagConfig.mv    | Bin 399 -> 371 bytes
 release/v13/bytecode_modules/Genesis.mv       | Bin 3439 -> 3391 bytes
 release/v13/bytecode_modules/STC.mv           | Bin 1371 -> 1339 bytes
 .../bytecode_modules/StdlibUpgradeScripts.mv  | Bin 2195 -> 2210 bytes
 .../bytecode_modules/TransactionManager.mv    | Bin 2510 -> 2564 bytes
 release/v13/docs/Block.md                     | 282 +++++++++++++++---
 release/v13/docs/FlexiDagConfig.md            |  11 +-
 release/v13/docs/Genesis.md                   |   3 -
 release/v13/docs/STC.md                       |   2 -
 release/v13/docs/StdlibUpgradeScripts.md      |   1 +
 release/v13/docs/TransactionManager.md        |  57 +++-
 release/v13/docs/TransactionTimeout.md        |   4 +-
 release/v13/source_maps/Block.mvsm            | Bin 18845 -> 20581 bytes
 release/v13/source_maps/FlexiDagConfig.mvsm   | Bin 1368 -> 1242 bytes
 release/v13/source_maps/Genesis.mvsm          | Bin 25361 -> 25235 bytes
 release/v13/source_maps/STC.mvsm              | Bin 6236 -> 6152 bytes
 .../v13/source_maps/StdlibUpgradeScripts.mvsm | Bin 7093 -> 7177 bytes
 .../v13/source_maps/TransactionManager.mvsm   | Bin 19100 -> 20059 bytes
 .../v13/source_maps/TransactionTimeout.mvsm   | Bin 1393 -> 1393 bytes
 release/v13/sources/Block.move                | 131 ++++++--
 release/v13/sources/FlexiDagConfig.move       |   8 +-
 release/v13/sources/Genesis.move              |   3 -
 release/v13/sources/STC.move                  |   2 -
 release/v13/sources/StdlibUpgradeScripts.move |   1 +
 release/v13/sources/TransactionManager.move   |  28 +-
 release/v13/sources/TransactionTimeout.move   |   4 +-
 28 files changed, 437 insertions(+), 102 deletions(-)

diff --git a/release/v13/BuildInfo.yaml b/release/v13/BuildInfo.yaml
index c0d3580a..e1cca14e 100644
--- a/release/v13/BuildInfo.yaml
+++ b/release/v13/BuildInfo.yaml
@@ -5,7 +5,7 @@ compiled_package_info:
     StarcoinAssociation: "0x0000000000000000000000000a550c18"
     StarcoinFramework: "0x00000000000000000000000000000001"
     VMReserved: "0x00000000000000000000000000000000"
-  source_digest: E203083CDEA5D40EEA2400D1D89CE602FF1778668B8DC34A0672D1EFCB44A57E
+  source_digest: 9280A56F445BC59176E3E1323C8B6159C411D74258DCD6679977DD49BA0C45D5
   build_flags:
     dev_mode: false
     test_mode: false
diff --git a/release/v13/bytecode_modules/Block.mv b/release/v13/bytecode_modules/Block.mv
index cb1b4ec752d3cd9d1f24a667772c1a9525885305..e72b98b179bbd3497ba9e60fbecbaac3c9309ef0 100644
GIT binary patch
delta 1442
zcmZ8hy>A>v6o2o{?#%4Y-0kjp&mZS=eEvN997AFtHjo4p2t*(#p`bV&&PlN_jul&p
zK#}|h(15n2qJxTph7KWGIus!~N(3~t6cN8Un+sy3`@J{s<2Uo>_Px)V-%Xx=(f-3}
zB63Wnls$F*FOI&J)%cM-X7f|@t+Ai@Tz~HS>EHf6|EN~k+HcJc5}1S(MHG`JLzWUs
zEokubhN$L=>fp^ZMXM2O*4i+UF%gh*WK$uE=(G_G6AUP0KvM%I84Obls%cJ$W&*TQ
zIA(*l&B&X>ed&S+%qM_OjY&OiE$K^~F`3H+P;WIRfX`$l@YxJ!nCB)f@XAyJmMe{E
zrcCWQupldiF7+@45
zGZ?Js4Y2D`kems{I-yK4jzUyeW)ummTGF`|_!I{l=uAR5BB|`2_wMcukB`s1{r|duS8w+6!{LK-*D%l?yAk`X
z!Qt(Lp+6ej3%359!SS7M`q4wK{)`{K8!xEERF>jpwSpp0is-SWo65)-i>NiVo=Okp
zPx-NMfI!hvQ*amxYz0mdST{MHl~>MS)D^4
zj#kn3Nu6C%%=r{DEiQQHJv3L$dpDAubJ_l%TwtHqGRHfq%Zk}*+x~pD)m8XHS+#v(
zLIaJ~l;^^FD!M)8*ik_eafBe2LP_YvC7)8UR=ttTouVc|BEFuu=x%VXOF=V_x26Z1U5Ur}7>F(+7-I-pm*Xy;tUfa7~e_#j%oCO?6h?5H^et~60>kkP9L@a~^
zk|o3s2$~C5ByJ#t#F0ZpPDmgmPW%WECnT=C-b6m653fF^>eZW3*F5fgIe+=}@?TyP
zk!R{iXI)MH=Ik38=D)~)Y#wKy8~d}b^dJ7n{SXerzu|Y&c+&2ofk{YFMmcFRWT_xW
z-Vy~v)CfdPq>W*sY?!fTYcu#%qK_(3L@~v!O9sy6fVKwAGrBtrnguS1y6lJ+A&q*B
zmZbo1xd5y*nA8i_lG)>u$-WqY=B3sg@LJghzFdOYzS6P4>kBPpuD7~qdKFFjwW1*2
z?^)u@8wn@9CF0kU_eO#@d&}ew`ibD?>Hw`b2W!B$))VpD>&VM32$kEAY~Qg%rs58g
z*`eNKo!>Q1%Nm4wRwFQd
zJXNd$};zjqu^|N7Dxv50B1{AD-2Zvi^@hWuJ1a
zrY9%U`xoaQPmj)~=ci{E^}hb>mhP)nCxd)VtwV&94a~%3Q6shKWIW5^Gj7e4ZL1xn
zB=4(1zN?;g)P=dhWqsR>nd@`&+x_lXa4i=fu`zKmlub^{FgvjqiYEIaE(Hhc;&SjI
z!1Hk>_?hiLv%Tl+Du=33dY(96#>M(8`{zM-tkTBFa)>6~^x0Vm9BrUD+7Zv5B1y&>
zidZ6aqiQ2KiktPf#mc4Z;R-O;hx0hvrAoI2+jSM1w&1E?g|;o&ldG_3ivt}u<5nVc
z*x6^ta~xd-6Y?~vTC_*dLoA$Olth-m4Umlwpm7swss7IO+vV6nO57P{i+SH0HY#@O
zU)|DsZr*8U%3|J|()-+t$9?s>r6y6ZxZp(}UYVjulQYB$G8%%zSOh^y`c~;5li?qe
F)Bo!TW5WOd

diff --git a/release/v13/bytecode_modules/FlexiDagConfig.mv b/release/v13/bytecode_modules/FlexiDagConfig.mv
index 4845bb9b88b05bde7823d7d610c46fb572c844bc..243f8a06b159d837f03298c27c88714a0f20a5e6 100644
GIT binary patch
delta 197
zcmeBY{>-GcQ06r^8v_Fa7b61)69)@3k1C5H3#+L(yU%(?j^B&|T-{8pJQJ8qc#llf
zl67NZXJBPyXXapIW?kT#e+Y}boYz$mO1ZPayl(u}
zYSs9*^{u=KW#yZZFABfx!oAPdK9uXuger6)-}GOziOF~EtS%0gTT~XgZI|6W_P>+Y
hQ#?=i42*e{nBoa{7A%fwN@8dMi4cG>3;RIv^*^Xyy~MtA9=CZXc5ElPJ0QRv?^nTZphF-k3Ob5FMR_`0Pys^x
zgov77fP^S%u0^7_9wEV4qG6=@^nLcselzx-H9t4=5AC1a1^^G?&^SCWpT05JE3<8V
zG=Ce;d;6>Bp4EK&Pwgd&7wY&VKU!m-0S*{MLxF(4??4bRV$rD7osI)iItUP4FLiLE
zMA)SSZ4h*kphvPXCgx3$PMb0d8rnu+nmXMQ4DBLpYZ|MiD+oK~TSs$*HP>{a7gJv+
zsYn
z>oG!bYeJ^MZ80Uh6DNdsXXIqvqq*6ZY*cr`X4nop;clqIp1%l};a<2O9&AqW7ZyLv
z!NzCG*u?fH1K$;=?&~Hu_=u1BgiqDBSjuc=$Qfm(qT<90CJ(AhZmvwRkTccdixsP|
zJ^I7{#gIKIzIf5PE8UgbWzVU(FLIf4R}FZshSb^@iA=adIw75@kw|66Q#B?&k(mSb
zqw?ZVIH;yFv;QejF;yg#Gs=`_D&sSi8MG~oj#1^zv@H5;WfTu9&#+s3uO!}FrnEy!
vJ5>3|YVrAsmD?2e`84i}jI7I1G8!eJ(P9~Mn{-S%C6km)5|wS<@^APTJhxGn

delta 788
zcmY*X%Wl(95S_8FAMtf=ebdHn-f`Y>Y$s{c5*~#>OL>WJKv_VkL}62;u88;o1W^|(
zSaeAx7AWeP4`9aHqbLQ%P$p6U4C&jN^2Y?j9M461#!xM!a
zt3~a-`b#n1>EBZ3Ysb;wI?vHQmB%mRtr?V|f(-`PWKd|?2$;zj;CYO)LObD=iUE#e
zAb_`%aPNA8P^AE0A*dliov7QPEY(Gt7BCH5Uq@g*b(#q%zKM|Y$y&*`5c0`iW9D-N
z?$g9nkNPTMT7VucAsRA92b{jlAjrWof|}GX4KWRNl4a^ES->?Lky%N5VclCrwlcCw
zd?QC+3!C`@;khE^#c_#nHK{9~FIUL^1)Ka|^l=7wsY-myu7U9D2+NnLDD5{8vR6nZ
zJ0Y6AO5k22z-^7PU93RHZy|U$+9c}Tv^#{ix&h(s9w}*eXaklJE9tyjbjxnVt-8Kj
zch=l>cjRukn_-};j4{<(e8!)+Bz7O&Kic1!?rlGL{9u1?{!y)K?C$jN;o`e071MaS
zIl6Z+JzD(M&J;YEpP8?!(vzzq;tFr_7H{*8%-KT`jTO`fSnQvH!Seu_(
zL24*M+99MJzF1AI#QS5GY%?$NPPbvxsJ~VsvJ#NBuIO@|taXWpBodNHAp460{t5p8
Dj;UW5

diff --git a/release/v13/bytecode_modules/STC.mv b/release/v13/bytecode_modules/STC.mv
index 213831b4eadcf00d73097aba35795e5f129f2575..b462ed908f1f2910168bbd9515060d11ca25c6e4 100644
GIT binary patch
delta 373
zcmWlVJx&BM427Q^&m@y%W@ncD-&t5-si8qiLB$ym9D!qOK}k6+LZadTloVWm22pYY
zH~R^DloebXb^d-E#p)7JT~HU7_5@z(uN
zdE;5@2@C^4h8z|S1v~;GN@$2G!Z{&OXrj{1dghCWqOd4S3nB|^EwM$JHYQ=W(Wl)JwOyn&4;S4D-F0tt`ZVS<&L>1n)9y;H>9~85%kzNbL%~L8
kBu)d?6?;*0refK6G$Z{6O3gHd$SOI-Xw+4vDwuw?e;JV>Jpcdz

delta 404
zcmWlVJxT;Y5QSe=*Gy0U%%=r7P
zh|k$C$p
ziRECZ^P6#`+#0psZAw_g6`D-KJNmrarPU^-b;*}|E6pA~a2A^nsyoHx^899Yd^SD0
zzPgxA-+t(j(*Y6FusM(^?Ke+yGV!Q=K-~$BjV@1IcUkXmMahYZap_Sm>Mv2<8`L4P
PO0Hux>dNaPnD*v>@kA$*

diff --git a/release/v13/bytecode_modules/StdlibUpgradeScripts.mv b/release/v13/bytecode_modules/StdlibUpgradeScripts.mv
index c98c9deabd1956ad445e3cf0cca5bfe4c4e6d79c..cebf13e904604b7e5038b49384f43660e0802cae 100644
GIT binary patch
delta 636
zcmYLGyKYlK5S`ig-ralcwXd&}*bv9T!A@+0aD6mqpSZQX@o^$3*v32+oW}o|OrvShr%-MX(pZ-DdgZ1Ta_8s+C
z@zaG@L1KA(0%7pobCYBpM_rX~QKVhM-gQO5K7Gf^)MmI(;b+!G)usG)f@}
zA&Hc(HWx=_p@(V{z%>~tho^1H;+?s8!p@miuV21dy?9lx#qwezkJ&b2f|wml)KOmrA|8xErOyx{+00iuc4E3duq#_^biBQJC7j1yg_oOHU|jm|Tgx6xB)
M;o$#lUa!pbFI>ntegFUf

delta 621
zcmYLG&2AGh5T5bB*Ip;iW|K52G!3LAZIU7ysQHJNK;po;0wKf&IH5}1IF>!49^lBe
zPrx0CD-utDcmj}+m`#vaX~v)D`?2i(7^^t{u=&#|0I&!PwwUk-zfgQ-effiZM*T^A
zGv-a+RPXXv{%!bvGCxqxX^8RU$?Ib|0fgq5T5C!zuaO;R2yWLp5PKd`H)eoLYdf!{
z`w$=-H%M9|yc`hZ6_gMTVhcsNY$FPO4G6anJ6#m<`bHn*4N~x%azNaz&2tFt+vkbn
zcdiadUfe|s<-M&Tiq34C2I2mQ`iAT0+s#pNp}bgJDktT%*ez$pyjV1=Qyd)&NxQmR5JGTnRzj!N1P!=wdTkK6LP#W~tJT6$
zQHUac#{$W?_o>iN?bM~|PKE#;E!3rFuATZ|z9h74js)ut+`
zIu0~bNA(}1PxIKV-s@rPCCDHlIR{LVFH~Q2uhVPAn9bh^4be;98Wgxd6`>BFVJ;#Bd5FFlzB#en;dl(cm8{Q_0r7#
E0!(x_$p8QV

diff --git a/release/v13/bytecode_modules/TransactionManager.mv b/release/v13/bytecode_modules/TransactionManager.mv
index cff245e057e8acfda3fd2bf950d4cd0d33c1cef9..799c306a8a3ce8efc09b8336895ca36066be77a4 100644
GIT binary patch
delta 1099
zcmYLIzmFS56n<}h?Cj2)U3+fr^ZD$vy?5vJISCGTgs_2dNh%a2QX(A%Qi_w4oFYMz
zLnKhf6#N5dMS(;^11(ah=qPEZXb=@G{0kuQW=|p``SZTt-}h$s*Zhml;@jch6ahej
zuqXDcJopRMH)5oJ5`UoiO8sc!U#K1ZPT!;ZJpJv<#eCIjDFk%R0CWHWx`JU{A}Z*q
zfEzksKMJ^M7^8tj&_j$N*&>4W$fl^WafTo#Erhsedr;eJ2yO?vsLU>U#%Vw**Add0
z?LoAMJxJ!XB3L^|UGV37U7!ma2>vyG!o}tQ@M4c^lGk~N+2?dT7&6s2IGkVF>LS=T
zM@SH^-wuzRP5mfj2%TQz)aYQ9gJo
zaFl@+o{`WpU8`+GiFfRcxTU7pr_ORTBHIigpNa5tV0t$7I>zZLo|xry
zP4Ei^o%h+1`%a-Eofzr6voi*n_JKkDojF>qtA*Y-Df6+hX%*@{Ykg;1-DoO%>QLV>
zrXkB3EmPajM--cOp^lo2zPhWAOw1WV^ThsbVhXPo;WwRgWU(^Vm8z|CBm8hyiHREf
zttz%um1?NRMu+*l#E5$|XWfr1`mwr@$tsz+L@yGTP@*nzmh^?+u78MkS6j|nOKC++
zjVf2A`W9PR(`N8AP~j%!|LWP8O;k|t{2tHa{^O?G++v{ydSoKzq36NJ(Q}0=^}O)~
zMd6cfPPk(hmbfhDon=#XSzieX>SeNfbI5%wLrJM_>pP9Ep!Qx+OL3__(D%;73LbF2
WR7?HP5D(?cX1h=y>LFKWCx#`)xxx4+I^WLuaFbf7_#s+*`gbnY0%*E}O$k1Ve-*w?vVyfNbb8zt8tlnyM3A}cnQMP8^v7yY77
z6T4enD0XQ^v%+~Nq~@O#k^r56<|!T=2t|mgz{I0K8Fw685QTA3BdAa5cFTN_?
zC?;zAntyPD*i1ylcqmRxa_jNgho>jaGx1q-AivrwAAfp!|KXD-_dfXK^!~^99z8re
zesFwt{QckZC$Tn*3_=nNnMxV$j0!1dYVeeS6TxLb=%f=)yM%0r*@OgXN`v?DG$BWl
z6jA8#*9HFE#4RM=wESe+)gEguG?bF9Q3x*U&g0y=xnthn3qr=sZO#;-Td71_BSUX-
zt}4?Zs%m~SN9#?s(w9w#HM-PnRO&6~LU&gkwwYhdmFi3>a4dvaJC=jSTdT_eI^QH!aXgkhaJs^@B`Cq~ElY%yVu
zc9mh|FpSluOxAYltzKDg$*L<{CBrmS%^&G(J@n2w>eR&2sP=V7zr#@`G}H7?q7)|C
z``use 0x1::CoreAddresses;
 use 0x1::Errors;
 use 0x1::Event;
-use 0x1::FlexiDagConfig;
 use 0x1::Hash;
 use 0x1::Option;
 use 0x1::Ring;
@@ -85,12 +88,6 @@ Block metadata struct.
  number of uncles.
 
-parents_hash: Option::Option<vector<u8>> -
-
- Hash of the parents hash for a Dag block. -
-
new_block_events: Event::EventHandle<Block::NewBlockEvent>
@@ -113,6 +110,110 @@ Events emitted when new block generated. +
+Fields + + +
+
+number: u64 +
+
+ +
+
+author: address +
+
+ +
+
+timestamp: u64 +
+
+ +
+
+uncles: u64 +
+
+ +
+
+ + +
+ + + +## Resource `BlockMetadataV2` + +Block metadata struct. + + +
struct BlockMetadataV2 has key
+
+ + + +
+Fields + + +
+
+number: u64 +
+
+ number of the current block +
+
+parent_hash: vector<u8> +
+
+ Hash of the parent block. +
+
+author: address +
+
+ Author of the current block. +
+
+uncles: u64 +
+
+ number of uncles. +
+
+parents_hash: vector<u8> +
+
+ An Array of the parents hash for a Dag block. +
+
+new_block_events: Event::EventHandle<Block::NewBlockEventV2> +
+
+ Handle of events when new blocks are emitted +
+
+ + +
+ + + +## Struct `NewBlockEventV2` + +Events emitted when new block generated. + + +
struct NewBlockEventV2 has drop, store
+
+ + +
Fields @@ -143,7 +244,7 @@ Events emitted when new block generated.
-parents_hash: Option::Option<vector<u8>> +parents_hash: vector<u8>
@@ -326,7 +427,6 @@ This can only be invoked by the GENESIS_ACCOUNT at genesis parent_hash, author: CoreAddresses::GENESIS_ADDRESS(), uncles: 0, - parents_hash: Option::none<vector<u8>>(), new_block_events: Event::new_event_handle<Self::NewBlockEvent>(account), }); } @@ -348,6 +448,58 @@ This can only be invoked by the GENESIS_ACCOUNT at genesis + + + + +## Function `initialize_blockmetadata_v2` + + + +
public fun initialize_blockmetadata_v2(account: &signer)
+
+ + + +
+Implementation + + +
public fun initialize_blockmetadata_v2(account: &signer) acquires BlockMetadata {
+    CoreAddresses::assert_genesis_address(account);
+
+    let block_meta_ref = borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
+    // create new resource base on current block metadata
+    move_to<BlockMetadataV2>(
+        account,
+        BlockMetadataV2 {
+            number: block_meta_ref.number,
+            parent_hash: block_meta_ref.parent_hash,
+            author: block_meta_ref.author,
+            uncles: block_meta_ref.uncles,
+            parents_hash: Vector::empty(),
+            new_block_events: Event::new_event_handle<Self::NewBlockEventV2>(account),
+        });
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<BlockMetadata>(Signer::address_of(account));
+ensures exists<BlockMetadataV2>(Signer::address_of(account));
+
+ + +
@@ -366,8 +518,8 @@ Get the current block number Implementation -
public fun get_current_block_number(): u64 acquires BlockMetadata {
-  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number
+
public fun get_current_block_number(): u64 acquires BlockMetadataV2 {
+    borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).number
 }
 
@@ -380,7 +532,7 @@ Get the current block number -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
@@ -403,8 +555,8 @@ Get the hash of the parent block. Implementation -
public fun get_parent_hash(): vector<u8> acquires BlockMetadata {
-  *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parent_hash
+
public fun get_parent_hash(): vector<u8> acquires BlockMetadataV2 {
+    *&borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).parent_hash
 }
 
@@ -417,20 +569,21 @@ Get the hash of the parent block. -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
- + -## Function `get_parents_hash` +## Function `get_current_author` +Gets the address of the author of the current block -
public fun get_parents_hash(): Option::Option<vector<u8>>
+
public fun get_current_author(): address
 
@@ -439,8 +592,8 @@ Get the hash of the parent block. Implementation -
public fun get_parents_hash(): Option::Option<vector<u8>> acquires BlockMetadata {
-    *&borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).parents_hash
+
public fun get_current_author(): address acquires BlockMetadataV2 {
+    borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).author
 }
 
@@ -453,21 +606,20 @@ Get the hash of the parent block. -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
- + -## Function `get_current_author` +## Function `get_parents_hash` -Gets the address of the author of the current block -
public fun get_current_author(): address
+
public fun get_parents_hash(): vector<u8>
 
@@ -476,8 +628,8 @@ Gets the address of the author of the current block Implementation -
public fun get_current_author(): address acquires BlockMetadata {
-  borrow_global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).author
+
public fun get_parents_hash(): vector<u8> acquires BlockMetadataV2 {
+    *&borrow_global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).parents_hash
 }
 
@@ -490,7 +642,7 @@ Gets the address of the author of the current block -
aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+
aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 
@@ -504,7 +656,52 @@ Gets the address of the author of the current block Call at block prologue -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: Option::Option<vector<u8>>)
+
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64)
+
+ + + +
+Implementation + + +
public fun process_block_metadata(account: &signer,
+                                  parent_hash: vector<u8>,
+                                  author: address,
+                                  timestamp: u64,
+                                  uncles:u64,
+                                  number:u64) acquires BlockMetadataV2{
+    Self::process_block_metadata_v2(account, parent_hash, author, timestamp, uncles, number, Vector::empty<u8>())
+
+}
+
+ + + +
+ +
+Specification + + + +
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if number != global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+
+ + + +
+ + + +## Function `process_block_metadata_v2` + +Call at block prologue for flexidag + + +
public fun process_block_metadata_v2(account: &signer, parent_hash: vector<u8>, author: address, timestamp: u64, uncles: u64, number: u64, parents_hash: vector<u8>)
 
@@ -513,21 +710,26 @@ Call at block prologue Implementation -
public fun process_block_metadata(account: &signer, parent_hash: vector<u8>,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option<vector<u8>>) acquires BlockMetadata{
+
public fun process_block_metadata_v2(account: &signer,
+                                     parent_hash: vector<u8>,
+                                     author: address,
+                                     timestamp: u64,
+                                     uncles:u64,
+                                     number:u64,
+                                     parents_hash: vector<u8>) acquires BlockMetadataV2 {
     CoreAddresses::assert_genesis_address(account);
 
-    let block_metadata_ref = borrow_global_mut<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    let block_metadata_ref = borrow_global_mut<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
     assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
-    assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH));
     block_metadata_ref.number = number;
     block_metadata_ref.author= author;
     block_metadata_ref.parent_hash = parent_hash;
     block_metadata_ref.uncles = uncles;
     block_metadata_ref.parents_hash = parents_hash;
 
-    Event::emit_event<NewBlockEvent>(
+    Event::emit_event<NewBlockEventV2>(
       &mut block_metadata_ref.new_block_events,
-      NewBlockEvent {
+      NewBlockEventV2 {
           number,
           author,
           timestamp,
@@ -548,8 +750,8 @@ Call at block prologue
 
 
 
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
-aborts_if number != global<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if number != global<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS()).number + 1;
 
@@ -559,7 +761,7 @@ Call at block prologue
schema AbortsIfBlockMetadataNotExist {
-    aborts_if !exists<BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if !exists<BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 }
 
@@ -627,7 +829,7 @@ Call at block prologue Implementation -
public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints {
+
public entry fun checkpoint_entry(_account: signer) acquires BlockMetadataV2, Checkpoints {
     checkpoint();
 }
 
@@ -663,7 +865,7 @@ Call at block prologue Implementation -
public fun checkpoint() acquires BlockMetadata, Checkpoints{
+
public fun checkpoint() acquires BlockMetadataV2, Checkpoints{
     let parent_block_number = get_current_block_number() - 1;
     let parent_block_hash   = get_parent_hash();
 
diff --git a/release/v13/docs/FlexiDagConfig.md b/release/v13/docs/FlexiDagConfig.md
index 81441e26..c8090f6e 100644
--- a/release/v13/docs/FlexiDagConfig.md
+++ b/release/v13/docs/FlexiDagConfig.md
@@ -12,9 +12,9 @@
 -  [Module Specification](#@Module_Specification_0)
 
 
-
use 0x1::Config;
+
use 0x1::Block;
+use 0x1::Config;
 use 0x1::CoreAddresses;
-use 0x1::Signer;
 
@@ -91,9 +91,8 @@ Create a new configuration for flexidag, mainly used in DAO.
public fun initialize(account: &signer, effective_height: u64) {
     CoreAddresses::assert_genesis_address(account);
-    if (!Config::config_exist_by_address<FlexiDagConfig>(Signer::address_of(account))) {
-        Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height))
-    }
+    Config::publish_new_config<FlexiDagConfig>(account, new_flexidag_config(effective_height));
+    Block::initialize_blockmetadata_v2(account);
 }
 
@@ -107,6 +106,8 @@ Create a new configuration for flexidag, mainly used in DAO.
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+aborts_if exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
+aborts_if exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(Signer::address_of(account));
 ensures exists<Config::Config<FlexiDagConfig>>(Signer::address_of(account));
 ensures
     exists<Config::ModifyConfigCapabilityHolder<FlexiDagConfig>>(
diff --git a/release/v13/docs/Genesis.md b/release/v13/docs/Genesis.md
index 1f9b39c3..6d449dab 100644
--- a/release/v13/docs/Genesis.md
+++ b/release/v13/docs/Genesis.md
@@ -24,10 +24,8 @@ The module for init Genesis
 use 0x1::CoreAddresses;
 use 0x1::DummyToken;
 use 0x1::Epoch;
-use 0x1::FlexiDagConfig;
 use 0x1::GenesisNFT;
 use 0x1::GenesisSignerCapability;
-use 0x1::Math;
 use 0x1::Option;
 use 0x1::PackageTxnManager;
 use 0x1::STC;
@@ -466,7 +464,6 @@ The module for init Genesis
         Option::some(0u64),
     );
     BlockReward::initialize(&genesis_account, reward_delay);
-    FlexiDagConfig::initialize(&genesis_account, u64_max());
 
     // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init.
     let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay);
diff --git a/release/v13/docs/STC.md b/release/v13/docs/STC.md
index 9abaa8ef..b22272d5 100644
--- a/release/v13/docs/STC.md
+++ b/release/v13/docs/STC.md
@@ -22,7 +22,6 @@ It uses apis defined in the Token
 
use 0x1::ConsensusConfig;
 use 0x1::CoreAddresses;
 use 0x1::Dao;
-use 0x1::FlexiDagConfig;
 use 0x1::ModifyDaoConfigProposal;
 use 0x1::OnChainConfigDao;
 use 0x1::PackageTxnManager;
@@ -269,7 +268,6 @@ STC initialization.
     OnChainConfigDao::plugin<STC, ConsensusConfig::ConsensusConfig>(account);
     OnChainConfigDao::plugin<STC, RewardConfig::RewardConfig>(account);
     OnChainConfigDao::plugin<STC, TransactionTimeoutConfig::TransactionTimeoutConfig>(account);
-    OnChainConfigDao::plugin<STC, FlexiDagConfig::FlexiDagConfig>(account);
     withdraw_cap
 }
 
diff --git a/release/v13/docs/StdlibUpgradeScripts.md b/release/v13/docs/StdlibUpgradeScripts.md index fbfd1432..0a8950dd 100644 --- a/release/v13/docs/StdlibUpgradeScripts.md +++ b/release/v13/docs/StdlibUpgradeScripts.md @@ -402,6 +402,7 @@ deprecated, use do_upgrade_from_v6_to_v7_with_language_version.
public fun do_upgrade_from_v12_to_v13(sender: &signer) {
     {
         FlexiDagConfig::initialize(sender, u64_max());
+        OnChainConfigDao::plugin<STC, FlexiDagConfig::FlexiDagConfig>(sender);
     };
 }
 
diff --git a/release/v13/docs/TransactionManager.md b/release/v13/docs/TransactionManager.md index 6477ab0d..33f76b55 100644 --- a/release/v13/docs/TransactionManager.md +++ b/release/v13/docs/TransactionManager.md @@ -13,6 +13,7 @@ - [Function `epilogue`](#0x1_TransactionManager_epilogue) - [Function `epilogue_v2`](#0x1_TransactionManager_epilogue_v2) - [Function `block_prologue`](#0x1_TransactionManager_block_prologue) +- [Function `block_prologue_v2`](#0x1_TransactionManager_block_prologue_v2) - [Function `txn_prologue_v2`](#0x1_TransactionManager_txn_prologue_v2) - [Function `txn_epilogue_v3`](#0x1_TransactionManager_txn_epilogue_v3) - [Module Specification](#@Module_Specification_1) @@ -28,7 +29,6 @@ use 0x1::Epoch; use 0x1::Errors; use 0x1::Hash; -use 0x1::Option; use 0x1::PackageTxnManager; use 0x1::STC; use 0x1::Signer; @@ -465,7 +465,7 @@ Set the metadata for the current block and distribute transaction fees and block The runtime always runs this before executing the transactions in a block. -
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: Option::Option<vector<u8>>)
+
public fun block_prologue(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64)
 
@@ -484,7 +484,56 @@ The runtime always runs this before executing the transactions in a block. number: u64, chain_id: u8, parent_gas_used: u64, - parents_hash: Option::Option<vector<u8>>, +) { + Self::block_prologue_v2(account, parent_hash, timestamp, author, auth_key_vec, uncles, number, chain_id, parent_gas_used, Vector::empty<u8>()) +} +
+ + + + + +
+Specification + + + +
pragma verify = false;
+
+ + + +
+ + + +## Function `block_prologue_v2` + +Set the metadata for the current block and distribute transaction fees and block rewards. +The runtime always runs this before executing the transactions in a block. +For Flexidag block + + +
public fun block_prologue_v2(account: signer, parent_hash: vector<u8>, timestamp: u64, author: address, auth_key_vec: vector<u8>, uncles: u64, number: u64, chain_id: u8, parent_gas_used: u64, parents_hash: vector<u8>)
+
+ + + +
+Implementation + + +
public fun block_prologue_v2(
+    account: signer,
+    parent_hash: vector<u8>,
+    timestamp: u64,
+    author: address,
+    auth_key_vec: vector<u8>,
+    uncles: u64,
+    number: u64,
+    chain_id: u8,
+    parent_gas_used: u64,
+    parents_hash: vector<u8>,
 ) {
     // Can only be invoked by genesis account
     CoreAddresses::assert_genesis_address(&account);
@@ -497,7 +546,7 @@ The runtime always runs this before executing the transactions in a block.
 
     // then deal with current block.
     Timestamp::update_global_time(&account, timestamp);
-    Block::process_block_metadata(
+    Block::process_block_metadata_v2(
         &account,
         parent_hash,
         author,
diff --git a/release/v13/docs/TransactionTimeout.md b/release/v13/docs/TransactionTimeout.md
index 9e5baaf1..01d2b3f2 100644
--- a/release/v13/docs/TransactionTimeout.md
+++ b/release/v13/docs/TransactionTimeout.md
@@ -56,7 +56,7 @@ Check whether the given timestamp is valid for transactions.
 
 
 
aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
-aborts_if !exists<Block::BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+aborts_if !exists<Block::BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
 include Timestamp::AbortsIfTimestampNotExists;
 aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
 aborts_if Block::get_current_block_number() != 0 && !exists<Config::Config<TransactionTimeoutConfig::TransactionTimeoutConfig>>(CoreAddresses::GENESIS_ADDRESS());
@@ -70,7 +70,7 @@ Check whether the given timestamp is valid for transactions.
 
 
schema AbortsIfTimestampNotValid {
     aborts_if !exists<Timestamp::CurrentTimeMilliseconds>(CoreAddresses::GENESIS_ADDRESS());
-    aborts_if !exists<Block::BlockMetadata>(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if !exists<Block::BlockMetadataV2>(CoreAddresses::GENESIS_ADDRESS());
     include Timestamp::AbortsIfTimestampNotExists;
     aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
     aborts_if Block::get_current_block_number() != 0 && !exists<Config::Config<TransactionTimeoutConfig::TransactionTimeoutConfig>>(CoreAddresses::GENESIS_ADDRESS());
diff --git a/release/v13/source_maps/Block.mvsm b/release/v13/source_maps/Block.mvsm
index 496f52b178d1292b16b76122ee2d551612b11341..63f80aa9aa7b67e9df91600147a5d558e233d8a4 100644
GIT binary patch
literal 20581
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%0DWIESV7SD72Rk$46u~e>9
zuydew<6kwod~q+p587JzY9`m8I>dFLpWPv>qoAMNCaiZrKf52X!U(_gygUjk1@yd}
zgH-@}UarP^81%fn6KfafdD%YmaM1Jeaa$gyo|ijf#$f7s`83b-Jm?Rrv6R;t9188w
zmVFCwk0u6U4~3AnSI&u)2CEAL93xPN2!6#iJ8Vs?7s_3Nx6;-j%|fgPL3iA@us#Rf
zad%a72zg#WeGl}wTaWbw=y7)z%V+=MLU)vi7(Pvd33FXS>&@Xfq)?=Vw=;K(MK~JPxv37!7h`@3Cfv1)-i957rgYIq@wb3u7d?%74&1wFr#KF)fMXY(h?-}0x1)^rpe}=m
zD}ilQz$LPMi3<)uNQbL&#jHZN*kVXmGCSZXgd7racs)T6i3VB|kEw^m9azgj4~a2Y
zQ$Y_2@1FFKc%1S!gB}u3V(kMxB&_*5=-A=_)^9<_7H?p^2|Co>g0&5F6tWiUThI~1
zIjl>dPw^eXx(qtD@M_nwMYn56PC>^OKCDg_*^{l=6?AN2OBy@0RB+6a09pN~}!dI7iACU97rE)%yz+WQZ6
z{t(p;Jr*3Fa6D>XTZ2m)Sb|sy`Uw|cRe^rO)~W^*-ab7mGkyG|oUs%00uwSPj>*dk
zHBo63a?-~KvNHV{nYoSs%My6ye-Sft^ZgS76Q^XSW#)#M=*%m>xbp8n_SnhU{=D=o
zAHT@W&B+Z+%*hMz>%

literal 18845
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
xqN2hg@8rS~@6Q8Ok7@t_

diff --git a/release/v13/source_maps/FlexiDagConfig.mvsm b/release/v13/source_maps/FlexiDagConfig.mvsm
index ccefaa8ff24ae7b25d0b4454af09088c53fa63db..d3ecfcbb4e666f0f87a44ce3113dc6e0e44978b6 100644
GIT binary patch
literal 1242
zcmb7@y-LJT5Jo5a7j2e2!h(V*h!(EGHWn@lc4}`7F@GRQirqyJ3o8r77qAfo!N$VE
zM-UXW5VQ~ls})?_PAv6A5bP!fPL(rr=YGTO^*<*%FUKoq+v6wg@Z;e5{4RR$HX8o!
z+kG;+KQL94V(ks3%@pKB3s2@ExsA*^L6sOInaMb%uRUkasM
z<_>0#L04Hv2vW!!b%dRQ<@vtnwxW(_hh7wf>W;Q3+RKiTK|ShA#2e6~KEk>MJ!-Qg
zQUyKgVXP_8qqeZ>P*#`n#EjFJ71a!|VlY*+iIu>BYGzgnIbyotkzN6h>Ax$!rtC2*
Umt1HGy+p8x;=

literal 1368
zcmb8vu}cDB7{~GVJoQQ=Y>bEqho+hoT3S*Z4k8Gu@s#WCyeNe_MWW4rAh)7LD6p+1
z3<`?2{(_*fwf=(!>H7vk+j9xO$0ooMI6gM>VhOhIbPos<$!+o
zBpFM-B4ccHmFrk1DiL?oCA3X)p6`2Z6t+F5?u9{JyrXT3JiU~fl1JSK4v0MJ6Vwfn
zM?FHNlKKTokKzlNM#`gpL|Vv{*z*CYby}1|RF|HXC@ZK9G9gMAbxbBjxrvHMMwD}?
r7Ricoe4-eabjDxA72&7+-v@S0*_|$B8F5SBm<)rKAJ{u`7OB(^`3Cur

diff --git a/release/v13/source_maps/Genesis.mvsm b/release/v13/source_maps/Genesis.mvsm
index 666697f9d8888c8e4b77e2cbc80520446aca0537..41d1e279bdb026d066772bdf372151237ece8bbc 100644
GIT binary patch
literal 25235
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
aV-0{#Tkm5X2Hq>-$kN3vtt~5881pw%3dyDb

literal 6236
zcmbW5Yiv_x7{}js*KQrO9pE7brxcumvYSPTNHQ7^tE%%<{0M=YReRF$WV$z)v{DgO
znxV{HV2rOf8Vg#XR5TuQwo)HOwcsv(GM$VCLsmjvstzEnEVowUM{V4}xzR5;6%
ze-%uF{snC30y{uIq@7q{&=2W)tO)3b^lhy7K|iGXu|5F(kY=~7P(IF|(eFzrlI9Os
zzd*4xzry+zJktCa>m-y&vz)W6f>LQVVciK{X>P`9gEDD$VZ~vdGzYOpVZJo4bKl1>
zebSu7ItPAfzJv8G1fnT_)%?GdsV2LzOVSNMD(maTD7HXvF_pn2-RGJs)SBY6G
z%{122P$$g>tU;)krfuy92d~;*FIx|$(CL_c2KxwjQ}LA56SR7r%;q;JIBpl^GMi6Q
za2j%(&C^s|f?Jr)zf+c1b_=uFPf;D@JD$yF<{2{up8s~SFBMYL{2cu+*o(_`nz#6j
zX$9}zXlhqDY3+5A9p|%Y!P*Qu0+eC}Ku3VxSV_oVvF@Gw>ebOcz+t85wQ2ylab%Q1BX7{D3^9RVJ~8UY;v
zvaeko0luK$BUJ81{n!<157X{v+d9Er;_CI7I>BX+K_|El`gPhXkUQUnwG(uL
zyAP`ybb`yCyiRcM((gFv1UH0r0(63#z?ud95$9*DIpDprZF}pMt?gUe9x>)$ZctPJ

diff --git a/release/v13/source_maps/StdlibUpgradeScripts.mvsm b/release/v13/source_maps/StdlibUpgradeScripts.mvsm
index b412aa7e9a5aef97b3d73ab2ebc95c03a6159aa4..55adea0ff1bd6bfbabf5c2aea97dea6685922d7a 100644
GIT binary patch
literal 7177
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

diff --git a/release/v13/source_maps/TransactionManager.mvsm b/release/v13/source_maps/TransactionManager.mvsm
index 2d9cf9915d3a66a35fc57844edb193159384abb6..ae0c7182bc2efbab8cc152f07889c22d2585e846 100644
GIT binary patch
literal 20059
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�oWQ67;5^KZ#GYua6?K@+VN?(r
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

diff --git a/release/v13/source_maps/TransactionTimeout.mvsm b/release/v13/source_maps/TransactionTimeout.mvsm
index 31b8e697cdc3ec4a952a8a044db42680465014ee..8aab55651c355e4015a0c98bddf8ca89fb6f4550 100644
GIT binary patch
literal 1393
zcmajfze@sP9LMqRd1qI8W@=V*W=lgjML9bZ4G}_F!EuR@l#h8nf>Q($NJB$}OG|sJ
zbALb()X?0Its$C&hCUY^w0#cV+w1vpk3QG`*nB+y&RpIUuP;jV_1KxSx2BYvvMb5>
z!`FPz6_FM)(ErCsmwivQy{fJ^Rk_}%H9I;$eKOyiDYA^jNa(I|HAc3z*EnS3RxoA*
zS!O<0VEEG#DMUrm)sFAily-Lyn$`W^#n@1VHI9+f@VaieLpJCZ>)jzccpV%B^GC3!
zNT&FKonSLp$e>3XZaqTf0P{T|lgcIRvWP4y7oZkVl*(BsjfSXPg{mN%${i?$hN;|w
z+D0Q(mj339QQ3nWpg5J`FYi!!kNKWag333jcQi`n3)Cx0QW^fE$EXbMnt{8PqS6Xf
oa4V^dK$$2*Wq8xasmx-&X_Tch4;6epCaBCo&7est!+nbU0G2P`(f|Me

literal 1393
zcmajfJ4?e*7{>88O=7LKUaHmLXswGl6bDgf2Ssryh!+SkbO_p0ZBL<-3Mx3dJGggo
zu&(_8f)1iv!3!=LlOHO;z2(G5i9xksB>`&+Z?V@$uUe4Jo-;-@M
zl5qUHFIPnNkb(X`M!Hb(RMqo!P*#PYR4mtYh#F+R2~%VNiILKEfC6c#A(tfQ{DJt!5?UeoP-^JKag*6UQvgFm>XoqZ23+vsWc=$Rv2ct)b7at?jkX@6vWfW~kxAt&b~%SEDyN}lkWJ+{ltvv?E>

diff --git a/release/v13/sources/Block.move b/release/v13/sources/Block.move
index b90033d9..f8fb1528 100644
--- a/release/v13/sources/Block.move
+++ b/release/v13/sources/Block.move
@@ -1,7 +1,6 @@
 address StarcoinFramework {
 /// Block module provide metadata for generated blocks.
 module Block {
-    use StarcoinFramework::FlexiDagConfig;
     use StarcoinFramework::Event;
     use StarcoinFramework::Timestamp;
     use StarcoinFramework::Signer;
@@ -28,8 +27,6 @@ module Block {
         author: address,
         /// number of uncles.
         uncles: u64,
-        /// Hash of the parents hash for a Dag block.
-        parents_hash: Option::Option>,
         /// Handle of events when new blocks are emitted
         new_block_events: Event::EventHandle,
     }
@@ -40,7 +37,33 @@ module Block {
         author: address,
         timestamp: u64,
         uncles: u64,
-        parents_hash: Option::Option>,
+    }
+
+    /// Block metadata struct.
+    // parents_hash is for FLexiDag block
+    struct BlockMetadataV2 has key {
+        /// number of the current block
+        number: u64,
+        /// Hash of the parent block.
+        parent_hash: vector,
+        /// Author of the current block.
+        author: address,
+        /// number of uncles.
+        uncles: u64,
+        /// An Array of the parents hash for a Dag block.
+        parents_hash: vector,
+        /// Handle of events when new blocks are emitted
+        new_block_events: Event::EventHandle,
+    }
+
+    /// Events emitted when new block generated.
+    // parents_hash is for FLexiDag block
+    struct NewBlockEventV2 has drop, store {
+        number: u64,
+        author: address,
+        timestamp: u64,
+        uncles: u64,
+        parents_hash: vector,
     }
 
     //
@@ -82,7 +105,6 @@ module Block {
                 parent_hash,
                 author: CoreAddresses::GENESIS_ADDRESS(),
                 uncles: 0,
-                parents_hash: Option::none>(),
                 new_block_events: Event::new_event_handle(account),
             });
     }
@@ -93,57 +115,104 @@ module Block {
         aborts_if exists(Signer::address_of(account));
     }
 
+    public fun initialize_blockmetadata_v2(account: &signer) acquires BlockMetadata {
+        CoreAddresses::assert_genesis_address(account);
+
+        let block_meta_ref = borrow_global(CoreAddresses::GENESIS_ADDRESS());
+
+        // create new resource base on current block metadata
+        move_to(
+            account,
+            BlockMetadataV2 {
+                number: block_meta_ref.number,
+                parent_hash: block_meta_ref.parent_hash,
+                author: block_meta_ref.author,
+                uncles: block_meta_ref.uncles,
+                parents_hash: Vector::empty(),
+                new_block_events: Event::new_event_handle(account),
+            });
+    }
+
+    spec initialize_blockmetadata_v2 {
+        aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+        aborts_if exists(Signer::address_of(account));
+
+        ensures exists(Signer::address_of(account));
+    }
+
     /// Get the current block number
-    public fun get_current_block_number(): u64 acquires BlockMetadata {
-      borrow_global(CoreAddresses::GENESIS_ADDRESS()).number
+    public fun get_current_block_number(): u64 acquires BlockMetadataV2 {
+        borrow_global(CoreAddresses::GENESIS_ADDRESS()).number
     }
 
     spec get_current_block_number {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
     /// Get the hash of the parent block.
-    public fun get_parent_hash(): vector acquires BlockMetadata {
-      *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parent_hash
+    public fun get_parent_hash(): vector acquires BlockMetadataV2 {
+        *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parent_hash
     }
 
     spec get_parent_hash {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
-    public fun get_parents_hash(): Option::Option> acquires BlockMetadata {
-        *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parents_hash
+    /// Gets the address of the author of the current block
+    public fun get_current_author(): address acquires BlockMetadataV2 {
+        borrow_global(CoreAddresses::GENESIS_ADDRESS()).author
     }
 
-    spec get_parents_hash {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+    spec get_current_author {
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
-    /// Gets the address of the author of the current block
-    public fun get_current_author(): address acquires BlockMetadata {
-      borrow_global(CoreAddresses::GENESIS_ADDRESS()).author
+    public fun get_parents_hash(): vector acquires BlockMetadataV2 {
+        *&borrow_global(CoreAddresses::GENESIS_ADDRESS()).parents_hash
     }
 
-    spec get_current_author {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+    spec get_parents_hash {
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
     /// Call at block prologue
-    public fun process_block_metadata(account: &signer, parent_hash: vector,author: address, timestamp: u64, uncles:u64, number:u64, parents_hash: Option::Option>) acquires BlockMetadata{
+    public fun process_block_metadata(account: &signer,
+                                      parent_hash: vector,
+                                      author: address,
+                                      timestamp: u64,
+                                      uncles:u64,
+                                      number:u64) acquires BlockMetadataV2{
+        Self::process_block_metadata_v2(account, parent_hash, author, timestamp, uncles, number, Vector::empty())
+
+    }
+
+    spec process_block_metadata {
+        aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+    }
+
+    /// Call at block prologue for flexidag
+    public fun process_block_metadata_v2(account: &signer,
+                                         parent_hash: vector,
+                                         author: address,
+                                         timestamp: u64,
+                                         uncles:u64,
+                                         number:u64,
+                                         parents_hash: vector) acquires BlockMetadataV2 {
         CoreAddresses::assert_genesis_address(account);
 
-        let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
+        let block_metadata_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
         assert!(number == (block_metadata_ref.number + 1), Errors::invalid_argument(EBLOCK_NUMBER_MISMATCH));
-        assert!(number > FlexiDagConfig::effective_height(CoreAddresses::GENESIS_ADDRESS()), Errors::invalid_state(EBLOCK_NUMBER_MISMATCH));
         block_metadata_ref.number = number;
         block_metadata_ref.author= author;
         block_metadata_ref.parent_hash = parent_hash;
         block_metadata_ref.uncles = uncles;
         block_metadata_ref.parents_hash = parents_hash;
 
-        Event::emit_event(
+        Event::emit_event(
           &mut block_metadata_ref.new_block_events,
-          NewBlockEvent {
+          NewBlockEventV2 {
               number,
               author,
               timestamp,
@@ -153,14 +222,14 @@ module Block {
         );
     }
 
-    spec process_block_metadata {
+    spec process_block_metadata_v2 {
         aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
-        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if number != global(CoreAddresses::GENESIS_ADDRESS()).number + 1;
     }
 
     spec schema AbortsIfBlockMetadataNotExist {
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
 
     public fun checkpoints_init(account: &signer){
@@ -180,7 +249,7 @@ module Block {
         pragma verify = false;
     }
 
-    public entry fun checkpoint_entry(_account: signer) acquires BlockMetadata, Checkpoints {
+    public entry fun checkpoint_entry(_account: signer) acquires BlockMetadataV2, Checkpoints {
         checkpoint();
     }
 
@@ -188,7 +257,7 @@ module Block {
         pragma verify = false;
     }
 
-    public fun checkpoint() acquires BlockMetadata, Checkpoints{
+    public fun checkpoint() acquires BlockMetadataV2, Checkpoints{
         let parent_block_number = get_current_block_number() - 1;
         let parent_block_hash   = get_parent_hash();
         
diff --git a/release/v13/sources/FlexiDagConfig.move b/release/v13/sources/FlexiDagConfig.move
index 98b93b0d..75fa8e7a 100644
--- a/release/v13/sources/FlexiDagConfig.move
+++ b/release/v13/sources/FlexiDagConfig.move
@@ -1,6 +1,7 @@
 address StarcoinFramework {
     module FlexiDagConfig {
 
+        use StarcoinFramework::Block;
         use StarcoinFramework::Config;
         use StarcoinFramework::CoreAddresses;
         use StarcoinFramework::Signer;
@@ -26,13 +27,14 @@ address StarcoinFramework {
 
         public fun initialize(account: &signer, effective_height: u64) {
             CoreAddresses::assert_genesis_address(account);
-            if (!Config::config_exist_by_address(Signer::address_of(account))) {
-                Config::publish_new_config(account, new_flexidag_config(effective_height))
-            }
+            Config::publish_new_config(account, new_flexidag_config(effective_height));
+            Block::initialize_blockmetadata_v2(account);
         }
 
         spec initialize {
             aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
+            aborts_if exists>(Signer::address_of(account));
+            aborts_if exists>(Signer::address_of(account));
             ensures exists>(Signer::address_of(account));
             ensures
                 exists>(
diff --git a/release/v13/sources/Genesis.move b/release/v13/sources/Genesis.move
index b53099c0..368c8699 100644
--- a/release/v13/sources/Genesis.move
+++ b/release/v13/sources/Genesis.move
@@ -2,8 +2,6 @@ address StarcoinFramework {
 /// The module for init Genesis
 module Genesis {
 
-    use StarcoinFramework::Math::u64_max;
-    use StarcoinFramework::FlexiDagConfig;
     use StarcoinFramework::CoreAddresses;
     use StarcoinFramework::Account;
     use StarcoinFramework::Signer;
@@ -404,7 +402,6 @@ module Genesis {
             Option::some(0u64),
         );
         BlockReward::initialize(&genesis_account, reward_delay);
-        FlexiDagConfig::initialize(&genesis_account, u64_max());
 
         // stc should be initialized after genesis_account's module upgrade strategy set and all on chain config init.
         let withdraw_cap = STC::initialize_v2(&genesis_account, total_stc_amount, voting_delay, voting_period, voting_quorum_rate, min_action_delay);
diff --git a/release/v13/sources/STC.move b/release/v13/sources/STC.move
index 15ab8e8f..92fc837d 100644
--- a/release/v13/sources/STC.move
+++ b/release/v13/sources/STC.move
@@ -2,7 +2,6 @@ address StarcoinFramework {
 /// STC is the token of Starcoin blockchain.
 /// It uses apis defined in the `Token` module.
 module STC {
-    use StarcoinFramework::FlexiDagConfig;
     use StarcoinFramework::Token::{Self, Token};
     use StarcoinFramework::Dao;
     use StarcoinFramework::ModifyDaoConfigProposal;
@@ -123,7 +122,6 @@ module STC {
         OnChainConfigDao::plugin(account);
         OnChainConfigDao::plugin(account);
         OnChainConfigDao::plugin(account);
-        OnChainConfigDao::plugin(account);
         withdraw_cap
     }
 
diff --git a/release/v13/sources/StdlibUpgradeScripts.move b/release/v13/sources/StdlibUpgradeScripts.move
index 2e34de74..8b7cd6bf 100644
--- a/release/v13/sources/StdlibUpgradeScripts.move
+++ b/release/v13/sources/StdlibUpgradeScripts.move
@@ -126,6 +126,7 @@ module StdlibUpgradeScripts {
         public fun do_upgrade_from_v12_to_v13(sender: &signer) {
             {
                 FlexiDagConfig::initialize(sender, u64_max());
+                OnChainConfigDao::plugin(sender);
             };
         }
 }
diff --git a/release/v13/sources/TransactionManager.move b/release/v13/sources/TransactionManager.move
index a26498c4..d98607a8 100644
--- a/release/v13/sources/TransactionManager.move
+++ b/release/v13/sources/TransactionManager.move
@@ -3,7 +3,6 @@ address StarcoinFramework {
 /// 1. prologue and epilogue of transactions.
 /// 2. prologue of blocks.
 module TransactionManager {
-    use StarcoinFramework::Option;
     use StarcoinFramework::Authenticator;
     use StarcoinFramework::Account::{exists_at, is_signer_delegated, transaction_fee_simulate,
         balance, Account, Balance
@@ -226,7 +225,28 @@ module TransactionManager {
         number: u64,
         chain_id: u8,
         parent_gas_used: u64,
-        parents_hash: Option::Option>,
+    ) {
+        Self::block_prologue_v2(account, parent_hash, timestamp, author, auth_key_vec, uncles, number, chain_id, parent_gas_used, Vector::empty())
+    }
+
+    spec block_prologue {
+        pragma verify = false;//fixme : timeout
+    }
+
+    /// Set the metadata for the current block and distribute transaction fees and block rewards.
+    /// The runtime always runs this before executing the transactions in a block.
+    /// For Flexidag block
+    public fun block_prologue_v2(
+        account: signer,
+        parent_hash: vector,
+        timestamp: u64,
+        author: address,
+        auth_key_vec: vector,
+        uncles: u64,
+        number: u64,
+        chain_id: u8,
+        parent_gas_used: u64,
+        parents_hash: vector,
     ) {
         // Can only be invoked by genesis account
         CoreAddresses::assert_genesis_address(&account);
@@ -239,7 +259,7 @@ module TransactionManager {
 
         // then deal with current block.
         Timestamp::update_global_time(&account, timestamp);
-        Block::process_block_metadata(
+        Block::process_block_metadata_v2(
             &account,
             parent_hash,
             author,
@@ -253,7 +273,7 @@ module TransactionManager {
         BlockReward::process_block_reward(&account, number, reward, author, auth_key_vec, txn_fee);
     }
 
-    spec block_prologue {
+    spec block_prologue_v2 {
         pragma verify = false;//fixme : timeout
     }
 
diff --git a/release/v13/sources/TransactionTimeout.move b/release/v13/sources/TransactionTimeout.move
index 0f8e55e5..c9dfa68d 100644
--- a/release/v13/sources/TransactionTimeout.move
+++ b/release/v13/sources/TransactionTimeout.move
@@ -36,7 +36,7 @@ module TransactionTimeout {
   }
   spec is_valid_transaction_timestamp {
     aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
-    aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+    aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     include Timestamp::AbortsIfTimestampNotExists;
     aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
     aborts_if Block::get_current_block_number() != 0 && !exists>(CoreAddresses::GENESIS_ADDRESS());
@@ -44,7 +44,7 @@ module TransactionTimeout {
 
     spec schema AbortsIfTimestampNotValid {
         aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
-        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
+        aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
         include Timestamp::AbortsIfTimestampNotExists;
         aborts_if Block::get_current_block_number() != 0 && Timestamp::now_seconds() + TransactionTimeoutConfig::duration_seconds() > max_u64();
         aborts_if Block::get_current_block_number() != 0 && !exists>(CoreAddresses::GENESIS_ADDRESS());

From 3f8a1557504e97135011ed6c8107e942e0f2863f Mon Sep 17 00:00:00 2001
From: jackzhhuang 
Date: Tue, 23 Apr 2024 16:40:36 +0800
Subject: [PATCH 8/9] no assert for uncle count == 0

---
 sources/Epoch.move | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sources/Epoch.move b/sources/Epoch.move
index de12b7ea..1bd95eee 100644
--- a/sources/Epoch.move
+++ b/sources/Epoch.move
@@ -153,14 +153,14 @@ module Epoch {
         CoreAddresses::assert_genesis_address(account);
 
         let epoch_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
-        assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+        // assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
 
         let epoch_data = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
         let (new_epoch, reward_per_block) = if (block_number < epoch_ref.end_block_number) {
             (false, epoch_ref.reward_per_block)
         } else if (block_number == epoch_ref.end_block_number) {
             //start a new epoch
-            assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+            // assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
             // block time target unit is milli_seconds.
             let now_milli_seconds = timestamp;
 
@@ -377,4 +377,4 @@ module Epoch {
     }
 
 }
-}
\ No newline at end of file
+}

From d1f0b2db44f2a36a3fb747e002cd57299f7d9dc1 Mon Sep 17 00:00:00 2001
From: simonjiao 
Date: Sun, 28 Apr 2024 14:29:22 +0800
Subject: [PATCH 9/9] update build/release files

1. fix warning
---
 build/StarcoinFramework/BuildInfo.yaml        |   2 +-
 .../bytecode_modules/Epoch.mv                 | Bin 2724 -> 2648 bytes
 build/StarcoinFramework/docs/Epoch.md         | 100 +++++++++++++----
 .../StarcoinFramework/source_maps/Epoch.mvsm  | Bin 23967 -> 23337 bytes
 release/StarcoinFramework.v0.1.0.blob         | Bin 114415 -> 114338 bytes
 release/v13/BuildInfo.yaml                    |   2 +-
 release/v13/bytecode_modules/Epoch.mv         | Bin 2724 -> 2648 bytes
 release/v13/docs/Epoch.md                     | 100 +++++++++++++----
 release/v13/source_maps/Epoch.mvsm            | Bin 23967 -> 23337 bytes
 release/v13/sources/Epoch.move                | 103 ++++++++++++++----
 sources/Epoch.move                            |  97 ++++++++++++++---
 11 files changed, 325 insertions(+), 79 deletions(-)

diff --git a/build/StarcoinFramework/BuildInfo.yaml b/build/StarcoinFramework/BuildInfo.yaml
index e1cca14e..ab73f252 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: 9280A56F445BC59176E3E1323C8B6159C411D74258DCD6679977DD49BA0C45D5
+  source_digest: 0899528282F044F9621C6B7686759D0D2AE52CF34CFAE8BF0917D02F2699ADF9
   build_flags:
     dev_mode: false
     test_mode: false
diff --git a/build/StarcoinFramework/bytecode_modules/Epoch.mv b/build/StarcoinFramework/bytecode_modules/Epoch.mv
index 2aa602ac288885c085b6f24d688ec4ea3d5c4b81..b9e0f1f9cc0ccdae351d588e6adea7d6069c7fe4 100644
GIT binary patch
delta 944
zcmYjQNp4gz5Uq0A-~Ze0KO}Z{hE6*3$P5jEEP{jt;vTt27C|hL&=&_lL5f(jMX+JP
z0%CPN4>i7c!vh}n`cmWgDdxnQc`Nlpp25KR;^3=Cpw
z3wF|!m}#@vRe%|X;cOnp3@O7WitCQG3jd~(CZT6edlTvH^EfJRc@rP0ZAU3M|gP;xaol^ntv
zPS6vG%_Ps4X#zF^tFkl);!;kli{`4v^gH&DZGUW!2P!I!ZHGsWy4e4)D|3rmp*&E*
zLs$w9xEv}x$fO^Xr@Y#~E}vQGP?q~&<<3G89a1I(?ne1;gnN5xxnHefq^OXKw3s|i
zJx{Hgc8mSCjW-Q?4h2ib6_U
Q{7OL

art|Cu=0p3$Y7ytkO delta 1017 zcmYjQy>1jS5T5aP?Ooe=O0zM=e! zE_)^3pngy9bpFFs>cCtxyLR2}+h2L(YnbK$1OWsRGEkraa{gEf1&A7y(g+}DBq{{M zzF-9bIFbO31kH?-mRjxrR5@FGQjQf2osX-h|U78|C)1qfH%sGlW)R%23gg)sv%Q?Bs==RWpue@IZ zXN;*J7+R1n^VV>&{n&sl=n8{u!!RfN1rrgRb}HM&L-h`ZzFakw?)q@_2w!dz9yVy#WYt7e9skJy_x#6eu1;~t^AH=J!^V(oiEpyw##ylrVWkbXLa5VhsW7g0wqQm&RIJ2gLrIvwGMgC_S dtQ@v1lr{?PM&iaid_9MEl3LWDK!gG;`~wYFR0#k8 diff --git a/build/StarcoinFramework/docs/Epoch.md b/build/StarcoinFramework/docs/Epoch.md index 17ac2e3c..d249b8d2 100644 --- a/build/StarcoinFramework/docs/Epoch.md +++ b/build/StarcoinFramework/docs/Epoch.md @@ -31,7 +31,6 @@ The module provide epoch functionality for starcoin.
use 0x1::ConsensusConfig;
 use 0x1::CoreAddresses;
-use 0x1::Errors;
 use 0x1::Event;
 use 0x1::Math;
 use 0x1::Option;
@@ -369,13 +368,21 @@ compute next block time_target.
 Implementation
 
 
-
public fun compute_next_block_time_target(config: &ConsensusConfig, last_epoch_time_target: u64, epoch_start_time: u64, now_milli_second: u64, start_block_number: u64, end_block_number: u64, total_uncles: u64): u64 {
+
public fun compute_next_block_time_target(
+    config: &ConsensusConfig,
+    last_epoch_time_target: u64,
+    epoch_start_time: u64,
+    now_milli_second: u64,
+    start_block_number: u64,
+    end_block_number: u64,
+    total_uncles: u64
+): u64 {
     let total_time = now_milli_second - epoch_start_time;
     let blocks = end_block_number - start_block_number;
     let avg_block_time = total_time / blocks;
     let uncles_rate = total_uncles * THOUSAND / blocks;
     let new_epoch_block_time_target = (THOUSAND + uncles_rate) * avg_block_time /
-            (ConsensusConfig::uncle_rate_target(config) + THOUSAND);
+        (ConsensusConfig::uncle_rate_target(config) + THOUSAND);
     if (new_epoch_block_time_target > last_epoch_time_target * 2) {
         new_epoch_block_time_target = last_epoch_time_target * 2;
     };
@@ -426,26 +433,43 @@ adjust_epoch try to advance to next epoch if current epoch ends.
 Implementation
 
 
-
public fun adjust_epoch(account: &signer, block_number: u64, timestamp: u64, uncles: u64, parent_gas_used:u64): u128
+
public fun adjust_epoch(
+    account: &signer,
+    block_number: u64,
+    timestamp: u64,
+    uncles: u64,
+    parent_gas_used: u64
+): u128
 acquires Epoch, EpochData {
     CoreAddresses::assert_genesis_address(account);
 
     let epoch_ref = borrow_global_mut<Epoch>(CoreAddresses::GENESIS_ADDRESS());
-    assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+    // assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
 
     let epoch_data = borrow_global_mut<EpochData>(CoreAddresses::GENESIS_ADDRESS());
     let (new_epoch, reward_per_block) = if (block_number < epoch_ref.end_block_number) {
         (false, epoch_ref.reward_per_block)
     } else if (block_number == epoch_ref.end_block_number) {
         //start a new epoch
-        assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+        // assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
         // block time target unit is milli_seconds.
         let now_milli_seconds = timestamp;
 
         let config = ConsensusConfig::get_config();
         let last_epoch_time_target = epoch_ref.block_time_target;
-        let new_epoch_block_time_target = compute_next_block_time_target(&config, last_epoch_time_target, epoch_ref.start_time, now_milli_seconds, epoch_ref.start_block_number, epoch_ref.end_block_number, epoch_data.uncles);
-        let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(&config, new_epoch_block_time_target);
+        let new_epoch_block_time_target = compute_next_block_time_target(
+            &config,
+            last_epoch_time_target,
+            epoch_ref.start_time,
+            now_milli_seconds,
+            epoch_ref.start_block_number,
+            epoch_ref.end_block_number,
+            epoch_data.uncles
+        );
+        let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(
+            &config,
+            new_epoch_block_time_target
+        );
 
         //update epoch by adjust result or config, because ConsensusConfig may be updated.
         epoch_ref.number = epoch_ref.number + 1;
@@ -461,7 +485,13 @@ adjust_epoch try to advance to next epoch if current epoch ends.
 
         epoch_data.uncles = 0;
         let last_epoch_total_gas = epoch_data.total_gas + (parent_gas_used as u128);
-        adjust_gas_limit(&config, epoch_ref, last_epoch_time_target, new_epoch_block_time_target, last_epoch_total_gas);
+        adjust_gas_limit(
+            &config,
+            epoch_ref,
+            last_epoch_time_target,
+            new_epoch_block_time_target,
+            last_epoch_total_gas
+        );
         emit_epoch_event(epoch_ref, epoch_data.total_reward);
         (true, new_reward_per_block)
     } else {
@@ -469,7 +499,7 @@ adjust_epoch try to advance to next epoch if current epoch ends.
         abort EUNREACHABLE
     };
     let reward = reward_per_block +
-            reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
+        reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
     update_epoch_data(epoch_data, new_epoch, reward, uncles, parent_gas_used);
     reward
 }
@@ -511,8 +541,20 @@ adjust_epoch try to advance to next epoch if current epoch ends.
 Implementation
 
 
-
fun adjust_gas_limit(config: &ConsensusConfig, epoch_ref: &mut Epoch, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_total_gas:u128) {
-    let new_gas_limit = compute_gas_limit(config, last_epoch_time_target, new_epoch_time_target, epoch_ref.block_gas_limit, last_epoch_total_gas);
+
fun adjust_gas_limit(
+    config: &ConsensusConfig,
+    epoch_ref: &mut Epoch,
+    last_epoch_time_target: u64,
+    new_epoch_time_target: u64,
+    last_epoch_total_gas: u128
+) {
+    let new_gas_limit = compute_gas_limit(
+        config,
+        last_epoch_time_target,
+        new_epoch_time_target,
+        epoch_ref.block_gas_limit,
+        last_epoch_total_gas
+    );
     if (Option::is_some(&new_gas_limit)) {
         epoch_ref.block_gas_limit = Option::destroy_some(new_gas_limit);
     }
@@ -551,17 +593,31 @@ Compute block's gas limit of next epoch.
 Implementation
 
 
-
public fun compute_gas_limit(config: &ConsensusConfig, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_block_gas_limit: u64, last_epoch_total_gas: u128) : Option::Option<u64> {
+
public fun compute_gas_limit(
+    config: &ConsensusConfig,
+    last_epoch_time_target: u64,
+    new_epoch_time_target: u64,
+    last_epoch_block_gas_limit: u64,
+    last_epoch_total_gas: u128
+): Option::Option<u64> {
     let epoch_block_count = (ConsensusConfig::epoch_block_count(config) as u128);
-    let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div((last_epoch_block_gas_limit as u128) * epoch_block_count, (80 as u128), (HUNDRED as u128)));
+    let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div(
+        (last_epoch_block_gas_limit as u128) * epoch_block_count,
+        (80 as u128),
+        (HUNDRED as u128)
+    ));
     let new_gas_limit = Option::none<u64>();
 
     let min_block_time_target = ConsensusConfig::min_block_time_target(config);
     let max_block_time_target = ConsensusConfig::max_block_time_target(config);
-    let base_block_gas_limit =  ConsensusConfig::base_block_gas_limit(config);
+    let base_block_gas_limit = ConsensusConfig::base_block_gas_limit(config);
     if (last_epoch_time_target == new_epoch_time_target) {
         if (new_epoch_time_target == min_block_time_target && gas_limit_threshold) {
-            let increase_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 110, base_block_gas_limit);
+            let increase_gas_limit = in_or_decrease_gas_limit(
+                last_epoch_block_gas_limit,
+                110,
+                base_block_gas_limit
+            );
             new_gas_limit = Option::some(increase_gas_limit);
         } else if (new_epoch_time_target == max_block_time_target && !gas_limit_threshold) {
             let decrease_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 90, base_block_gas_limit);
@@ -606,7 +662,7 @@ Compute block's gas limit of next epoch.
 
 
fun in_or_decrease_gas_limit(last_epoch_block_gas_limit: u64, percent: u64, min_block_gas_limit: u64): u64 {
     let tmp_gas_limit = Math::mul_div((last_epoch_block_gas_limit as u128), (percent as u128), (HUNDRED as u128));
-    let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit  as u128)) {
+    let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit as u128)) {
         (tmp_gas_limit as u64)
     } else {
         min_block_gas_limit
@@ -625,7 +681,7 @@ Compute block's gas limit of next epoch.
 
 
 
-
include Math::MulDivAbortsIf{x: last_epoch_block_gas_limit, y: percent, z: HUNDRED};
+
include Math::MulDivAbortsIf { x: last_epoch_block_gas_limit, y: percent, z: HUNDRED };
 aborts_if Math::spec_mul_div() > MAX_U64;
 
@@ -648,7 +704,13 @@ Compute block's gas limit of next epoch. Implementation -
fun update_epoch_data(epoch_data: &mut EpochData, new_epoch: bool, reward: u128, uncles: u64, parent_gas_used:u64) {
+
fun update_epoch_data(
+    epoch_data: &mut EpochData,
+    new_epoch: bool,
+    reward: u128,
+    uncles: u64,
+    parent_gas_used: u64
+) {
     if (new_epoch) {
         epoch_data.total_reward = reward;
         epoch_data.uncles = uncles;
diff --git a/build/StarcoinFramework/source_maps/Epoch.mvsm b/build/StarcoinFramework/source_maps/Epoch.mvsm
index b6a0521ec5b7cd19f7a9312f9f04cad9c584027e..379bf4fa6c3ed644e5d2c16025c035fa72c07d0f 100644
GIT binary patch
literal 23337
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

diff --git a/release/v13/BuildInfo.yaml b/release/v13/BuildInfo.yaml
index e1cca14e..ab73f252 100644
--- a/release/v13/BuildInfo.yaml
+++ b/release/v13/BuildInfo.yaml
@@ -5,7 +5,7 @@ compiled_package_info:
     StarcoinAssociation: "0x0000000000000000000000000a550c18"
     StarcoinFramework: "0x00000000000000000000000000000001"
     VMReserved: "0x00000000000000000000000000000000"
-  source_digest: 9280A56F445BC59176E3E1323C8B6159C411D74258DCD6679977DD49BA0C45D5
+  source_digest: 0899528282F044F9621C6B7686759D0D2AE52CF34CFAE8BF0917D02F2699ADF9
   build_flags:
     dev_mode: false
     test_mode: false
diff --git a/release/v13/bytecode_modules/Epoch.mv b/release/v13/bytecode_modules/Epoch.mv
index 2aa602ac288885c085b6f24d688ec4ea3d5c4b81..b9e0f1f9cc0ccdae351d588e6adea7d6069c7fe4 100644
GIT binary patch
delta 944
zcmYjQNp4gz5Uq0A-~Ze0KO}Z{hE6*3$P5jEEP{jt;vTt27C|hL&=&_lL5f(jMX+JP
z0%CPN4>i7c!vh}n`cmWgDdxnQc`Nlpp25KR;^3=Cpw
z3wF|!m}#@vRe%|X;cOnp3@O7WitCQG3jd~(CZT6edlTvH^EfJRc@rP0ZAU3M|gP;xaol^ntv
zPS6vG%_Ps4X#zF^tFkl);!;kli{`4v^gH&DZGUW!2P!I!ZHGsWy4e4)D|3rmp*&E*
zLs$w9xEv}x$fO^Xr@Y#~E}vQGP?q~&<<3G89a1I(?ne1;gnN5xxnHefq^OXKw3s|i
zJx{Hgc8mSCjW-Q?4h2ib6_U
Q{7OL

art|Cu=0p3$Y7ytkO delta 1017 zcmYjQy>1jS5T5aP?Ooe=O0zM=e! zE_)^3pngy9bpFFs>cCtxyLR2}+h2L(YnbK$1OWsRGEkraa{gEf1&A7y(g+}DBq{{M zzF-9bIFbO31kH?-mRjxrR5@FGQjQf2osX-h|U78|C)1qfH%sGlW)R%23gg)sv%Q?Bs==RWpue@IZ zXN;*J7+R1n^VV>&{n&sl=n8{u!!RfN1rrgRb}HM&L-h`ZzFakw?)q@_2w!dz9yVy#WYt7e9skJy_x#6eu1;~t^AH=J!^V(oiEpyw##ylrVWkbXLa5VhsW7g0wqQm&RIJ2gLrIvwGMgC_S dtQ@v1lr{?PM&iaid_9MEl3LWDK!gG;`~wYFR0#k8 diff --git a/release/v13/docs/Epoch.md b/release/v13/docs/Epoch.md index 17ac2e3c..d249b8d2 100644 --- a/release/v13/docs/Epoch.md +++ b/release/v13/docs/Epoch.md @@ -31,7 +31,6 @@ The module provide epoch functionality for starcoin.
use 0x1::ConsensusConfig;
 use 0x1::CoreAddresses;
-use 0x1::Errors;
 use 0x1::Event;
 use 0x1::Math;
 use 0x1::Option;
@@ -369,13 +368,21 @@ compute next block time_target.
 Implementation
 
 
-
public fun compute_next_block_time_target(config: &ConsensusConfig, last_epoch_time_target: u64, epoch_start_time: u64, now_milli_second: u64, start_block_number: u64, end_block_number: u64, total_uncles: u64): u64 {
+
public fun compute_next_block_time_target(
+    config: &ConsensusConfig,
+    last_epoch_time_target: u64,
+    epoch_start_time: u64,
+    now_milli_second: u64,
+    start_block_number: u64,
+    end_block_number: u64,
+    total_uncles: u64
+): u64 {
     let total_time = now_milli_second - epoch_start_time;
     let blocks = end_block_number - start_block_number;
     let avg_block_time = total_time / blocks;
     let uncles_rate = total_uncles * THOUSAND / blocks;
     let new_epoch_block_time_target = (THOUSAND + uncles_rate) * avg_block_time /
-            (ConsensusConfig::uncle_rate_target(config) + THOUSAND);
+        (ConsensusConfig::uncle_rate_target(config) + THOUSAND);
     if (new_epoch_block_time_target > last_epoch_time_target * 2) {
         new_epoch_block_time_target = last_epoch_time_target * 2;
     };
@@ -426,26 +433,43 @@ adjust_epoch try to advance to next epoch if current epoch ends.
 Implementation
 
 
-
public fun adjust_epoch(account: &signer, block_number: u64, timestamp: u64, uncles: u64, parent_gas_used:u64): u128
+
public fun adjust_epoch(
+    account: &signer,
+    block_number: u64,
+    timestamp: u64,
+    uncles: u64,
+    parent_gas_used: u64
+): u128
 acquires Epoch, EpochData {
     CoreAddresses::assert_genesis_address(account);
 
     let epoch_ref = borrow_global_mut<Epoch>(CoreAddresses::GENESIS_ADDRESS());
-    assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+    // assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
 
     let epoch_data = borrow_global_mut<EpochData>(CoreAddresses::GENESIS_ADDRESS());
     let (new_epoch, reward_per_block) = if (block_number < epoch_ref.end_block_number) {
         (false, epoch_ref.reward_per_block)
     } else if (block_number == epoch_ref.end_block_number) {
         //start a new epoch
-        assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+        // assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
         // block time target unit is milli_seconds.
         let now_milli_seconds = timestamp;
 
         let config = ConsensusConfig::get_config();
         let last_epoch_time_target = epoch_ref.block_time_target;
-        let new_epoch_block_time_target = compute_next_block_time_target(&config, last_epoch_time_target, epoch_ref.start_time, now_milli_seconds, epoch_ref.start_block_number, epoch_ref.end_block_number, epoch_data.uncles);
-        let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(&config, new_epoch_block_time_target);
+        let new_epoch_block_time_target = compute_next_block_time_target(
+            &config,
+            last_epoch_time_target,
+            epoch_ref.start_time,
+            now_milli_seconds,
+            epoch_ref.start_block_number,
+            epoch_ref.end_block_number,
+            epoch_data.uncles
+        );
+        let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(
+            &config,
+            new_epoch_block_time_target
+        );
 
         //update epoch by adjust result or config, because ConsensusConfig may be updated.
         epoch_ref.number = epoch_ref.number + 1;
@@ -461,7 +485,13 @@ adjust_epoch try to advance to next epoch if current epoch ends.
 
         epoch_data.uncles = 0;
         let last_epoch_total_gas = epoch_data.total_gas + (parent_gas_used as u128);
-        adjust_gas_limit(&config, epoch_ref, last_epoch_time_target, new_epoch_block_time_target, last_epoch_total_gas);
+        adjust_gas_limit(
+            &config,
+            epoch_ref,
+            last_epoch_time_target,
+            new_epoch_block_time_target,
+            last_epoch_total_gas
+        );
         emit_epoch_event(epoch_ref, epoch_data.total_reward);
         (true, new_reward_per_block)
     } else {
@@ -469,7 +499,7 @@ adjust_epoch try to advance to next epoch if current epoch ends.
         abort EUNREACHABLE
     };
     let reward = reward_per_block +
-            reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
+        reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
     update_epoch_data(epoch_data, new_epoch, reward, uncles, parent_gas_used);
     reward
 }
@@ -511,8 +541,20 @@ adjust_epoch try to advance to next epoch if current epoch ends.
 Implementation
 
 
-
fun adjust_gas_limit(config: &ConsensusConfig, epoch_ref: &mut Epoch, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_total_gas:u128) {
-    let new_gas_limit = compute_gas_limit(config, last_epoch_time_target, new_epoch_time_target, epoch_ref.block_gas_limit, last_epoch_total_gas);
+
fun adjust_gas_limit(
+    config: &ConsensusConfig,
+    epoch_ref: &mut Epoch,
+    last_epoch_time_target: u64,
+    new_epoch_time_target: u64,
+    last_epoch_total_gas: u128
+) {
+    let new_gas_limit = compute_gas_limit(
+        config,
+        last_epoch_time_target,
+        new_epoch_time_target,
+        epoch_ref.block_gas_limit,
+        last_epoch_total_gas
+    );
     if (Option::is_some(&new_gas_limit)) {
         epoch_ref.block_gas_limit = Option::destroy_some(new_gas_limit);
     }
@@ -551,17 +593,31 @@ Compute block's gas limit of next epoch.
 Implementation
 
 
-
public fun compute_gas_limit(config: &ConsensusConfig, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_block_gas_limit: u64, last_epoch_total_gas: u128) : Option::Option<u64> {
+
public fun compute_gas_limit(
+    config: &ConsensusConfig,
+    last_epoch_time_target: u64,
+    new_epoch_time_target: u64,
+    last_epoch_block_gas_limit: u64,
+    last_epoch_total_gas: u128
+): Option::Option<u64> {
     let epoch_block_count = (ConsensusConfig::epoch_block_count(config) as u128);
-    let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div((last_epoch_block_gas_limit as u128) * epoch_block_count, (80 as u128), (HUNDRED as u128)));
+    let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div(
+        (last_epoch_block_gas_limit as u128) * epoch_block_count,
+        (80 as u128),
+        (HUNDRED as u128)
+    ));
     let new_gas_limit = Option::none<u64>();
 
     let min_block_time_target = ConsensusConfig::min_block_time_target(config);
     let max_block_time_target = ConsensusConfig::max_block_time_target(config);
-    let base_block_gas_limit =  ConsensusConfig::base_block_gas_limit(config);
+    let base_block_gas_limit = ConsensusConfig::base_block_gas_limit(config);
     if (last_epoch_time_target == new_epoch_time_target) {
         if (new_epoch_time_target == min_block_time_target && gas_limit_threshold) {
-            let increase_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 110, base_block_gas_limit);
+            let increase_gas_limit = in_or_decrease_gas_limit(
+                last_epoch_block_gas_limit,
+                110,
+                base_block_gas_limit
+            );
             new_gas_limit = Option::some(increase_gas_limit);
         } else if (new_epoch_time_target == max_block_time_target && !gas_limit_threshold) {
             let decrease_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 90, base_block_gas_limit);
@@ -606,7 +662,7 @@ Compute block's gas limit of next epoch.
 
 
fun in_or_decrease_gas_limit(last_epoch_block_gas_limit: u64, percent: u64, min_block_gas_limit: u64): u64 {
     let tmp_gas_limit = Math::mul_div((last_epoch_block_gas_limit as u128), (percent as u128), (HUNDRED as u128));
-    let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit  as u128)) {
+    let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit as u128)) {
         (tmp_gas_limit as u64)
     } else {
         min_block_gas_limit
@@ -625,7 +681,7 @@ Compute block's gas limit of next epoch.
 
 
 
-
include Math::MulDivAbortsIf{x: last_epoch_block_gas_limit, y: percent, z: HUNDRED};
+
include Math::MulDivAbortsIf { x: last_epoch_block_gas_limit, y: percent, z: HUNDRED };
 aborts_if Math::spec_mul_div() > MAX_U64;
 
@@ -648,7 +704,13 @@ Compute block's gas limit of next epoch. Implementation -
fun update_epoch_data(epoch_data: &mut EpochData, new_epoch: bool, reward: u128, uncles: u64, parent_gas_used:u64) {
+
fun update_epoch_data(
+    epoch_data: &mut EpochData,
+    new_epoch: bool,
+    reward: u128,
+    uncles: u64,
+    parent_gas_used: u64
+) {
     if (new_epoch) {
         epoch_data.total_reward = reward;
         epoch_data.uncles = uncles;
diff --git a/release/v13/source_maps/Epoch.mvsm b/release/v13/source_maps/Epoch.mvsm
index b6a0521ec5b7cd19f7a9312f9f04cad9c584027e..379bf4fa6c3ed644e5d2c16025c035fa72c07d0f 100644
GIT binary patch
literal 23337
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
m{l%Bpqi5fGrbX89+^aK23?J&t%gr2-HO7}YGB0 last_epoch_time_target * 2) {
             new_epoch_block_time_target = last_epoch_time_target * 2;
         };
@@ -148,26 +155,43 @@ module Epoch {
     }
 
     /// adjust_epoch try to advance to next epoch if current epoch ends.
-    public fun adjust_epoch(account: &signer, block_number: u64, timestamp: u64, uncles: u64, parent_gas_used:u64): u128
+    public fun adjust_epoch(
+        account: &signer,
+        block_number: u64,
+        timestamp: u64,
+        uncles: u64,
+        parent_gas_used: u64
+    ): u128
     acquires Epoch, EpochData {
         CoreAddresses::assert_genesis_address(account);
 
         let epoch_ref = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
-        assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+        // assert!(epoch_ref.max_uncles_per_block >= uncles, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
 
         let epoch_data = borrow_global_mut(CoreAddresses::GENESIS_ADDRESS());
         let (new_epoch, reward_per_block) = if (block_number < epoch_ref.end_block_number) {
             (false, epoch_ref.reward_per_block)
         } else if (block_number == epoch_ref.end_block_number) {
             //start a new epoch
-            assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
+            // assert!(uncles == 0, Errors::invalid_argument(EINVALID_UNCLES_COUNT));
             // block time target unit is milli_seconds.
             let now_milli_seconds = timestamp;
 
             let config = ConsensusConfig::get_config();
             let last_epoch_time_target = epoch_ref.block_time_target;
-            let new_epoch_block_time_target = compute_next_block_time_target(&config, last_epoch_time_target, epoch_ref.start_time, now_milli_seconds, epoch_ref.start_block_number, epoch_ref.end_block_number, epoch_data.uncles);
-            let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(&config, new_epoch_block_time_target);
+            let new_epoch_block_time_target = compute_next_block_time_target(
+                &config,
+                last_epoch_time_target,
+                epoch_ref.start_time,
+                now_milli_seconds,
+                epoch_ref.start_block_number,
+                epoch_ref.end_block_number,
+                epoch_data.uncles
+            );
+            let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(
+                &config,
+                new_epoch_block_time_target
+            );
 
             //update epoch by adjust result or config, because ConsensusConfig may be updated.
             epoch_ref.number = epoch_ref.number + 1;
@@ -183,7 +207,13 @@ module Epoch {
 
             epoch_data.uncles = 0;
             let last_epoch_total_gas = epoch_data.total_gas + (parent_gas_used as u128);
-            adjust_gas_limit(&config, epoch_ref, last_epoch_time_target, new_epoch_block_time_target, last_epoch_total_gas);
+            adjust_gas_limit(
+                &config,
+                epoch_ref,
+                last_epoch_time_target,
+                new_epoch_block_time_target,
+                last_epoch_total_gas
+            );
             emit_epoch_event(epoch_ref, epoch_data.total_reward);
             (true, new_reward_per_block)
         } else {
@@ -191,7 +221,7 @@ module Epoch {
             abort EUNREACHABLE
         };
         let reward = reward_per_block +
-                reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
+            reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
         update_epoch_data(epoch_data, new_epoch, reward, uncles, parent_gas_used);
         reward
     }
@@ -206,8 +236,20 @@ module Epoch {
         // ...
     }
 
-    fun adjust_gas_limit(config: &ConsensusConfig, epoch_ref: &mut Epoch, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_total_gas:u128) {
-        let new_gas_limit = compute_gas_limit(config, last_epoch_time_target, new_epoch_time_target, epoch_ref.block_gas_limit, last_epoch_total_gas);
+    fun adjust_gas_limit(
+        config: &ConsensusConfig,
+        epoch_ref: &mut Epoch,
+        last_epoch_time_target: u64,
+        new_epoch_time_target: u64,
+        last_epoch_total_gas: u128
+    ) {
+        let new_gas_limit = compute_gas_limit(
+            config,
+            last_epoch_time_target,
+            new_epoch_time_target,
+            epoch_ref.block_gas_limit,
+            last_epoch_total_gas
+        );
         if (Option::is_some(&new_gas_limit)) {
             epoch_ref.block_gas_limit = Option::destroy_some(new_gas_limit);
         }
@@ -218,17 +260,31 @@ module Epoch {
     }
 
     /// Compute block's gas limit of next epoch.
-    public fun compute_gas_limit(config: &ConsensusConfig, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_block_gas_limit: u64, last_epoch_total_gas: u128) : Option::Option {
+    public fun compute_gas_limit(
+        config: &ConsensusConfig,
+        last_epoch_time_target: u64,
+        new_epoch_time_target: u64,
+        last_epoch_block_gas_limit: u64,
+        last_epoch_total_gas: u128
+    ): Option::Option {
         let epoch_block_count = (ConsensusConfig::epoch_block_count(config) as u128);
-        let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div((last_epoch_block_gas_limit as u128) * epoch_block_count, (80 as u128), (HUNDRED as u128)));
+        let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div(
+            (last_epoch_block_gas_limit as u128) * epoch_block_count,
+            (80 as u128),
+            (HUNDRED as u128)
+        ));
         let new_gas_limit = Option::none();
 
         let min_block_time_target = ConsensusConfig::min_block_time_target(config);
         let max_block_time_target = ConsensusConfig::max_block_time_target(config);
-        let base_block_gas_limit =  ConsensusConfig::base_block_gas_limit(config);
+        let base_block_gas_limit = ConsensusConfig::base_block_gas_limit(config);
         if (last_epoch_time_target == new_epoch_time_target) {
             if (new_epoch_time_target == min_block_time_target && gas_limit_threshold) {
-                let increase_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 110, base_block_gas_limit);
+                let increase_gas_limit = in_or_decrease_gas_limit(
+                    last_epoch_block_gas_limit,
+                    110,
+                    base_block_gas_limit
+                );
                 new_gas_limit = Option::some(increase_gas_limit);
             } else if (new_epoch_time_target == max_block_time_target && !gas_limit_threshold) {
                 let decrease_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 90, base_block_gas_limit);
@@ -245,7 +301,7 @@ module Epoch {
 
     fun in_or_decrease_gas_limit(last_epoch_block_gas_limit: u64, percent: u64, min_block_gas_limit: u64): u64 {
         let tmp_gas_limit = Math::mul_div((last_epoch_block_gas_limit as u128), (percent as u128), (HUNDRED as u128));
-        let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit  as u128)) {
+        let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit as u128)) {
             (tmp_gas_limit as u64)
         } else {
             min_block_gas_limit
@@ -255,11 +311,17 @@ module Epoch {
     }
 
     spec in_or_decrease_gas_limit {
-        include Math::MulDivAbortsIf{x: last_epoch_block_gas_limit, y: percent, z: HUNDRED};
+        include Math::MulDivAbortsIf { x: last_epoch_block_gas_limit, y: percent, z: HUNDRED };
         aborts_if Math::spec_mul_div() > MAX_U64;
     }
 
-    fun update_epoch_data(epoch_data: &mut EpochData, new_epoch: bool, reward: u128, uncles: u64, parent_gas_used:u64) {
+    fun update_epoch_data(
+        epoch_data: &mut EpochData,
+        new_epoch: bool,
+        reward: u128,
+        uncles: u64,
+        parent_gas_used: u64
+    ) {
         if (new_epoch) {
             epoch_data.total_reward = reward;
             epoch_data.uncles = uncles;
@@ -375,6 +437,5 @@ module Epoch {
     spec block_time_target {
         aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
-
 }
-}
\ No newline at end of file
+}
diff --git a/sources/Epoch.move b/sources/Epoch.move
index 1bd95eee..bc6ef8ad 100644
--- a/sources/Epoch.move
+++ b/sources/Epoch.move
@@ -6,7 +6,6 @@ module Epoch {
     use StarcoinFramework::CoreAddresses;
 
     use StarcoinFramework::Event;
-    use StarcoinFramework::Errors;
     use StarcoinFramework::Timestamp;
     use StarcoinFramework::Math;
     use StarcoinFramework::Option;
@@ -119,13 +118,21 @@ module Epoch {
     }
 
     /// compute next block time_target.
-    public fun compute_next_block_time_target(config: &ConsensusConfig, last_epoch_time_target: u64, epoch_start_time: u64, now_milli_second: u64, start_block_number: u64, end_block_number: u64, total_uncles: u64): u64 {
+    public fun compute_next_block_time_target(
+        config: &ConsensusConfig,
+        last_epoch_time_target: u64,
+        epoch_start_time: u64,
+        now_milli_second: u64,
+        start_block_number: u64,
+        end_block_number: u64,
+        total_uncles: u64
+    ): u64 {
         let total_time = now_milli_second - epoch_start_time;
         let blocks = end_block_number - start_block_number;
         let avg_block_time = total_time / blocks;
         let uncles_rate = total_uncles * THOUSAND / blocks;
         let new_epoch_block_time_target = (THOUSAND + uncles_rate) * avg_block_time /
-                (ConsensusConfig::uncle_rate_target(config) + THOUSAND);
+            (ConsensusConfig::uncle_rate_target(config) + THOUSAND);
         if (new_epoch_block_time_target > last_epoch_time_target * 2) {
             new_epoch_block_time_target = last_epoch_time_target * 2;
         };
@@ -148,7 +155,13 @@ module Epoch {
     }
 
     /// adjust_epoch try to advance to next epoch if current epoch ends.
-    public fun adjust_epoch(account: &signer, block_number: u64, timestamp: u64, uncles: u64, parent_gas_used:u64): u128
+    public fun adjust_epoch(
+        account: &signer,
+        block_number: u64,
+        timestamp: u64,
+        uncles: u64,
+        parent_gas_used: u64
+    ): u128
     acquires Epoch, EpochData {
         CoreAddresses::assert_genesis_address(account);
 
@@ -166,8 +179,19 @@ module Epoch {
 
             let config = ConsensusConfig::get_config();
             let last_epoch_time_target = epoch_ref.block_time_target;
-            let new_epoch_block_time_target = compute_next_block_time_target(&config, last_epoch_time_target, epoch_ref.start_time, now_milli_seconds, epoch_ref.start_block_number, epoch_ref.end_block_number, epoch_data.uncles);
-            let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(&config, new_epoch_block_time_target);
+            let new_epoch_block_time_target = compute_next_block_time_target(
+                &config,
+                last_epoch_time_target,
+                epoch_ref.start_time,
+                now_milli_seconds,
+                epoch_ref.start_block_number,
+                epoch_ref.end_block_number,
+                epoch_data.uncles
+            );
+            let new_reward_per_block = ConsensusConfig::do_compute_reward_per_block(
+                &config,
+                new_epoch_block_time_target
+            );
 
             //update epoch by adjust result or config, because ConsensusConfig may be updated.
             epoch_ref.number = epoch_ref.number + 1;
@@ -183,7 +207,13 @@ module Epoch {
 
             epoch_data.uncles = 0;
             let last_epoch_total_gas = epoch_data.total_gas + (parent_gas_used as u128);
-            adjust_gas_limit(&config, epoch_ref, last_epoch_time_target, new_epoch_block_time_target, last_epoch_total_gas);
+            adjust_gas_limit(
+                &config,
+                epoch_ref,
+                last_epoch_time_target,
+                new_epoch_block_time_target,
+                last_epoch_total_gas
+            );
             emit_epoch_event(epoch_ref, epoch_data.total_reward);
             (true, new_reward_per_block)
         } else {
@@ -191,7 +221,7 @@ module Epoch {
             abort EUNREACHABLE
         };
         let reward = reward_per_block +
-                reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
+            reward_per_block * (epoch_ref.reward_per_uncle_percent as u128) * (uncles as u128) / (HUNDRED as u128);
         update_epoch_data(epoch_data, new_epoch, reward, uncles, parent_gas_used);
         reward
     }
@@ -206,8 +236,20 @@ module Epoch {
         // ...
     }
 
-    fun adjust_gas_limit(config: &ConsensusConfig, epoch_ref: &mut Epoch, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_total_gas:u128) {
-        let new_gas_limit = compute_gas_limit(config, last_epoch_time_target, new_epoch_time_target, epoch_ref.block_gas_limit, last_epoch_total_gas);
+    fun adjust_gas_limit(
+        config: &ConsensusConfig,
+        epoch_ref: &mut Epoch,
+        last_epoch_time_target: u64,
+        new_epoch_time_target: u64,
+        last_epoch_total_gas: u128
+    ) {
+        let new_gas_limit = compute_gas_limit(
+            config,
+            last_epoch_time_target,
+            new_epoch_time_target,
+            epoch_ref.block_gas_limit,
+            last_epoch_total_gas
+        );
         if (Option::is_some(&new_gas_limit)) {
             epoch_ref.block_gas_limit = Option::destroy_some(new_gas_limit);
         }
@@ -218,17 +260,31 @@ module Epoch {
     }
 
     /// Compute block's gas limit of next epoch.
-    public fun compute_gas_limit(config: &ConsensusConfig, last_epoch_time_target: u64, new_epoch_time_target: u64, last_epoch_block_gas_limit: u64, last_epoch_total_gas: u128) : Option::Option {
+    public fun compute_gas_limit(
+        config: &ConsensusConfig,
+        last_epoch_time_target: u64,
+        new_epoch_time_target: u64,
+        last_epoch_block_gas_limit: u64,
+        last_epoch_total_gas: u128
+    ): Option::Option {
         let epoch_block_count = (ConsensusConfig::epoch_block_count(config) as u128);
-        let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div((last_epoch_block_gas_limit as u128) * epoch_block_count, (80 as u128), (HUNDRED as u128)));
+        let gas_limit_threshold = (last_epoch_total_gas >= Math::mul_div(
+            (last_epoch_block_gas_limit as u128) * epoch_block_count,
+            (80 as u128),
+            (HUNDRED as u128)
+        ));
         let new_gas_limit = Option::none();
 
         let min_block_time_target = ConsensusConfig::min_block_time_target(config);
         let max_block_time_target = ConsensusConfig::max_block_time_target(config);
-        let base_block_gas_limit =  ConsensusConfig::base_block_gas_limit(config);
+        let base_block_gas_limit = ConsensusConfig::base_block_gas_limit(config);
         if (last_epoch_time_target == new_epoch_time_target) {
             if (new_epoch_time_target == min_block_time_target && gas_limit_threshold) {
-                let increase_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 110, base_block_gas_limit);
+                let increase_gas_limit = in_or_decrease_gas_limit(
+                    last_epoch_block_gas_limit,
+                    110,
+                    base_block_gas_limit
+                );
                 new_gas_limit = Option::some(increase_gas_limit);
             } else if (new_epoch_time_target == max_block_time_target && !gas_limit_threshold) {
                 let decrease_gas_limit = in_or_decrease_gas_limit(last_epoch_block_gas_limit, 90, base_block_gas_limit);
@@ -245,7 +301,7 @@ module Epoch {
 
     fun in_or_decrease_gas_limit(last_epoch_block_gas_limit: u64, percent: u64, min_block_gas_limit: u64): u64 {
         let tmp_gas_limit = Math::mul_div((last_epoch_block_gas_limit as u128), (percent as u128), (HUNDRED as u128));
-        let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit  as u128)) {
+        let new_gas_limit = if (tmp_gas_limit > (min_block_gas_limit as u128)) {
             (tmp_gas_limit as u64)
         } else {
             min_block_gas_limit
@@ -255,11 +311,17 @@ module Epoch {
     }
 
     spec in_or_decrease_gas_limit {
-        include Math::MulDivAbortsIf{x: last_epoch_block_gas_limit, y: percent, z: HUNDRED};
+        include Math::MulDivAbortsIf { x: last_epoch_block_gas_limit, y: percent, z: HUNDRED };
         aborts_if Math::spec_mul_div() > MAX_U64;
     }
 
-    fun update_epoch_data(epoch_data: &mut EpochData, new_epoch: bool, reward: u128, uncles: u64, parent_gas_used:u64) {
+    fun update_epoch_data(
+        epoch_data: &mut EpochData,
+        new_epoch: bool,
+        reward: u128,
+        uncles: u64,
+        parent_gas_used: u64
+    ) {
         if (new_epoch) {
             epoch_data.total_reward = reward;
             epoch_data.uncles = uncles;
@@ -375,6 +437,5 @@ module Epoch {
     spec block_time_target {
         aborts_if !exists(CoreAddresses::GENESIS_ADDRESS());
     }
-
 }
 }