diff --git a/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md
new file mode 100644
index 0000000..cba403d
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md
@@ -0,0 +1,298 @@
+# ACS0 - Contract Deployment Standard
+
+ACS0 manages contract deployment and updates.
+
+## Interface
+
+Contracts using ACS0 need to implement these methods:
+
+### Methods
+
+| Method Name | Request | Response | Description |
+|------------------------------------|-------------------------------------|-----------------------------------|--------------------------------------------------|
+| DeploySystemSmartContract | `acs0.SystemContractDeploymentInput`| `aelf.Address` | Deploys a system smart contract and returns its address. |
+| DeploySmartContract | `acs0.ContractDeploymentInput` | `aelf.Address` | Deploys a smart contract and returns its address. |
+| UpdateSmartContract | `acs0.ContractUpdateInput` | `aelf.Address` | Updates a smart contract. |
+| ProposeNewContract | `acs0.ContractDeploymentInput` | `aelf.Hash` | Creates a proposal to deploy a new contract and returns its ID. |
+| ProposeContractCodeCheck | `acs0.ContractCodeCheckInput` | `aelf.Hash` | Creates a proposal to check contract code and returns its ID. |
+| ProposeUpdateContract | `acs0.ContractUpdateInput` | `aelf.Hash` | Creates a proposal to update a contract and returns its ID. |
+| ReleaseApprovedContract | `acs0.ReleaseContractInput` | `google.protobuf.Empty` | Releases an approved contract proposal. |
+| ReleaseCodeCheckedContract | `acs0.ReleaseContractInput` | `google.protobuf.Empty` | Releases a proposal that passed the code check. |
+| ValidateSystemContractAddress | `acs0.ValidateSystemContractAddressInput` | `google.protobuf.Empty` | Validates if the input system contract exists. |
+| SetContractProposerRequiredState | `google.protobuf.BoolValue` | `google.protobuf.Empty` | Sets contract deployment authority. |
+| CurrentContractSerialNumber | `google.protobuf.Empty` | `google.protobuf.Int64Value` | Gets the current serial number of the genesis contract. |
+| GetContractInfo | `aelf.Address` | `acs0.ContractInfo` | Gets information about a contract. |
+| GetContractAuthor | `aelf.Address` | `aelf.Address` | Gets the author of a contract. |
+| GetContractHash | `aelf.Address` | `aelf.Hash` | Gets the code hash of a contract by address. |
+| GetContractAddressByName | `aelf.Hash` | `aelf.Address` | Gets the address of a system contract by name. |
+| GetSmartContractRegistrationByAddress | `aelf.Address` | `aelf.SmartContractRegistration` | Gets the registration of a smart contract by address. |
+| GetSmartContractRegistrationByCodeHash | `aelf.Hash` | `aelf.SmartContractRegistration` | Gets the registration of a smart contract by code hash. |
+| DeployUserSmartContract | `acs0.ContractDeploymentInput` | `acs0.DeployUserSmartContractOutput` | Deploys a user smart contract and returns the contract code hash. |
+| UpdateUserSmartContract | `acs0.ContractUpdateInput` | `google.protobuf.Empty` | Updates a user smart contract. |
+| ReleaseApprovedUserSmartContract | `acs0.ReleaseContractInput` | `google.protobuf.Empty` | Releases a proposal that passed the code check. |
+| PerformDeployUserSmartContract | `acs0.ContractDeploymentInput` | `aelf.Address` | Deploys a user contract. |
+| PerformUpdateUserSmartContract | `acs0.ContractUpdateInput` | `google.protobuf.Empty` | Updates a user contract. |
+| SetContractAuthor | `acs0.SetContractAuthorInput` | `google.protobuf.Empty` | Sets the author of a contract. |
+
+### Types
+
+#### acs0.AuthorUpdated
+
+| Field | Type | Description |
+|--------------|--------------|----------------------------------|
+| `address` | `aelf.address` | Contract code byte array. |
+| `old_author` | `aelf.address` | Contract code category (0: C#). |
+
+#### acs0.CodeCheckRequired
+
+| Field | Type | Description |
+|-------------------------------|--------------|--------------------------------|
+| `code` | `bytes` | Contract code byte array. |
+| `proposed_contract_input_hash`| `aelf.Hash` | Proposed contract ID. |
+| `category` | `sint32` | Contract code category (0: C#).|
+| `is_system_contract` | `bool` | Is it a system contract? |
+| `is_user_contract` | `bool` | Is it a user contract? |
+
+#### acs0.CodeUpdated
+
+| Field | Type | Description |
+|-----------------|--------------|--------------------------------|
+| `address` | `aelf.Address` | Contract address. |
+| `old_code_hash` | `aelf.Hash` | Old contract code byte array. |
+| `new_code_hash` | `aelf.Hash` | New contract code byte array. |
+| `version` | `int32` | Contract version. |
+
+### acs0.ContractCodeCheckInput#
+
+| Field | Type | Description |
+|-------------------------------|--------------|-------------------------------------------------------|
+| `contract_input` | `bytes` | Contract code byte array. |
+| `is_contract_deployment` | `bool` | Is the contract being deployed or updated? |
+| `code_check_release_method` | `string` | Method to call after code check (DeploySmartContract or UpdateSmartContract). |
+| `proposed_contract_input_hash`| `aelf.Hash` | Proposed contract ID. |
+| `category` | `sint32` | Contract code category (0: C#). |
+| `is_system_contract` | `bool` | Is it a system contract? |
+
+#### acs0.ContractDeployed
+
+| Field | Type | Description |
+|---------------------|--------------|----------------------------------|
+| `author` | `aelf.Address` | Contract author. |
+| `code_hash` | `aelf.Hash` | Contract code hash. |
+| `address` | `aelf.Address` | Contract address. |
+| `version` | `int32` | Contract version. |
+| `name` | `aelf.Hash` | Contract name (must be unique). |
+| `contract_version` | `string` | Contract version. |
+
+#### acs0.ContractDeploymentInput
+
+| Field | Type | Description |
+|-----------|---------|------------------------------------|
+| `category`| `sint32`| Contract code category (0: C#). |
+| `code` | `bytes` | Contract code byte array. |
+
+#### acs0.DeployUserSmartContractOutput
+
+| Field | Type | Description |
+|------------|------------|---------------------------------|
+| `code_hash`| `aelf.Hash`| Deployed/updated contract code hash. |
+
+#### acs0.ContractInfo
+
+| Field | Type | Description |
+|--------------------|--------------|----------------------------------|
+| `serial_number` | `int64` | Contract serial number. |
+| `author` | `aelf.Address` | Contract author. |
+| `category` | `sint32` | Contract code category (0: C#). |
+| `code_hash` | `aelf.Hash` | Contract code hash. |
+| `is_system_contract`| `bool` | Is it a system contract? |
+| `version` | `int32` | Contract version. |
+| `contract_version` | `string` | Contract version. |
+| `contract_type` | `string` | Contract type. |
+| `deployed_by` | `aelf.Address` | Deployer address. |
+| `deployed_on` | `google.protobuf.Timestamp` | Deployment time. |
+
+#### acs0.ContractUpdateInput
+
+| Field | Type | Description |
+|---------------------|--------------|----------------------------------|
+| `address` | `aelf.Address` | Contract address. |
+| `code` | `bytes` | Contract code byte array. |
+| `category` | `sint32` | Contract code category (0: C#). |
+| `is_system_contract`| `bool` | Is it a system contract? |
+| `is_user_contract` | `bool` | Is it a user contract? |
+
+#### acs0.ReleaseContractInput
+
+| Field | Type | Description |
+|-------------|------------|--------------------------------|
+| `proposal_id` | `aelf.Hash` | Proposal ID to be released. |
+
+#### acs0.SetContractAuthorInput
+
+| Field | Type | Description |
+|-----------------|--------------|----------------------------------|
+| `address` | `aelf.Address` | Contract address. |
+| `author` | `aelf.Address` | New author address. |
+
+#### acs0.SystemContractDeploymentInput
+
+| Field | Type | Description |
+|-----------------|--------------|----------------------------------|
+| `category` | `sint32` | Contract code category (0: C#). |
+| `code` | `bytes` | Contract code byte array. |
+| `name` | `aelf.Hash` | Contract name (must be unique). |
+
+#### acs0.ValidateSystemContractAddressInput
+
+| Field | Type | Description |
+|------------------------|--------------|----------------------------------|
+| `system_contract_hash_name` | `aelf.Hash` | Contract name hash. |
+| `address` | `aelf.Address` | Contract address. |
+
+#### aelf.Address
+
+| Field | Type | Description |
+|-----------|---------|----------------------------|
+| `value` | `bytes` | Address value in bytes. |
+
+#### aelf.BinaryMerkleTree
+
+| Field | Type | Description |
+|-------------|----------|----------------------------------|
+| `nodes` | `Hash` | Leaf nodes. |
+| `root` | `Hash` | Root node hash. |
+| `leaf_count`| `int32` | Number of leaf nodes. |
+
+#### aelf.Hash
+
+| Field | Type | Description |
+|-----------|---------|----------------------------|
+| `value` | `bytes` | Hash value in bytes. |
+
+#### aelf.LogEvent
+
+| Field | Type | Description |
+|-------------|----------|----------------------------------|
+| `address` | `Address`| Contract address. |
+| `name` | `string` | Log event name. |
+| `indexed` | `bytes` | Indexed data for bloom filter. |
+| `non_indexed`| `bytes` | Non-indexed data. |
+
+#### aelf.MerklePath
+
+| Field | Type | Description |
+|----------------------|-----------------|----------------------------------|
+| `merkle_path_nodes` | `MerklePathNode`| Merkle path nodes. |
+
+#### aelf.MerklePathNode
+
+| Field | Type | Description |
+|--------------------|----------|--------------------------------|
+| `hash` | `Hash` | Node hash. |
+| `is_left_child_node`| `bool` | Is it a left child node? |
+
+#### aelf.SInt32Value
+
+| Field | Type | Description |
+|---------|---------|------------------------------|
+| `value` | `sint32`| Signed 32-bit integer value. |
+
+#### aelf.SInt64Value
+
+| Field | Type | Description |
+|---------|---------|------------------------------|
+| `value` | `sint64`| Signed 64-bit integer value. |
+
+#### aelf.ScopedStatePath
+
+| Field | Type | Description |
+|-----------|---------|------------------------------------|
+| `address` | `Address` | Scope address (contract address). |
+| `path` | `StatePath` | Contract state path. |
+
+#### aelf.SmartContractRegistration
+
+| Field | Type | Description |
+|--------------------|----------|----------------------------------|
+| `category` | `sint32` | Contract code category (0: C#). |
+| `code` | `bytes` | Contract code byte array. |
+| `code_hash` | `Hash` | Contract code hash. |
+| `is_system_contract`| `bool` | Is it a system contract? |
+| `version` | `int32` | Contract version. |
+
+#### aelf.StatePath
+
+| Field | Type | Description |
+|---------|---------|--------------------------------------|
+| `parts` | `string`| State path parts. |
+
+#### aelf.Transaction
+
+| Field | Type | Description |
+|------------------|--------------|------------------------------------|
+| `from` | `Address` | Sender address. |
+| `to` | `Address` | Contract address. |
+| `ref_block_number`| `int64` | Referenced block height. |
+| `ref_block_prefix`| `bytes` | Referenced block hash prefix. |
+| `method_name` | `string` | Smart contract method name. |
+| `params` | `bytes` | Smart contract method parameters. |
+| `signature` | `bytes` | Transaction signature. |
+
+#### aelf.TransactionExecutingStateSet
+
+| Field | Type | Description |
+|---------|----------------------------------|---------------------------------|
+| `writes`| `TransactionExecutingStateSet.WritesEntry`| Changed states. |
+| `reads` | `TransactionExecutingStateSet.ReadsEntry` | Read states. |
+| `deletes`| `TransactionExecutingStateSet.DeletesEntry` | Deleted states. |
+
+#### aelf.TransactionExecutingStateSet.DeletesEntry
+
+| Field | Type | Description |
+|---------|---------|---------------------------|
+| `key` | `string`| State key. |
+| `value` | `bool` | Deletion state (true/false).|
+
+#### aelf.TransactionExecutingStateSet.ReadsEntry
+
+| Field | Type | Description |
+|---------|---------|---------------------------|
+| `key` | `string`| State key. |
+| `value` | `bool` | Read state (true/false). |
+
+#### aelf.TransactionExecutingStateSet.WritesEntry
+
+| Field | Type | Description |
+|---------|---------|---------------------------|
+| `key` | `string`| State key. |
+| `value` | `bytes` | Written state value. |
+
+#### aelf.TransactionResult
+
+| Field | Type | Description |
+|-----------------|--------------|------------------------------------|
+| `transaction_id`| `Hash` | Transaction ID. |
+| `status` | `TransactionResultStatus` | Transaction result status. |
+| `logs` | `LogEvent` | Log events. |
+| `bloom` | `bytes` | Bloom filter for logs. |
+| `return_value` | `bytes` | Transaction execution return value.|
+| `block_number` | `int64` | Block height. |
+| `block_hash` | `Hash` | Block hash. |
+| `error` | `string` | Error message. |
+
+#### aelf.TransactionResultStatus
+
+| Name | Value | Description |
+|------------------------|-------|---------------------------------------------------------|
+| `NOT_EXISTED` | 0 | Transaction result does not exist. |
+| `PENDING` | 1 | Transaction in pool waiting to be packaged. |
+| `FAILED` | 2 | Transaction execution failed. |
+| `MINED` | 3 | Transaction successfully executed and packaged. |
+| `CONFLICT` | 4 | Conflicts with other transactions during parallel execution.|
+| `PENDING_VALIDATION` | 5 | Waiting for validation. |
+| `NODE_VALIDATION_FAILED`| 6 | Validation failed. |
+
+## Example
+
+ACS0 defines methods for contract deployment and updates. AElf provides the Genesis Contract as an implementation of ACS0.
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md
new file mode 100644
index 0000000..f4b7f76
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md
@@ -0,0 +1,270 @@
+# ACS1 - Transaction Fee Standard
+ACS1 handles transaction fees.
+
+## Interface
+Contracts using ACS1 must implement these methods:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|--------------------------|--------------------------------|-------------------------|-----------------------------------------------------|
+| SetMethodFee | `acs1.MethodFees` | `google.protobuf.Empty` | Sets the method fees for a method, overriding all fees. |
+| ChangeMethodFeeController| `AuthorityInfo` | `google.protobuf.Empty` | Changes the method fee controller. Default is parliament. |
+| GetMethodFee | `google.protobuf.StringValue` | `acs1.MethodFees` | Queries the fee for a method by name. |
+| GetMethodFeeController | `google.protobuf.Empty` | `AuthorityInfo` | Queries the method fee controller. |
+
+### Types
+#### acs1.MethodFee
+| Field | Type | Description |
+|------------|--------|-----------------------------------|
+| symbol | string | The token symbol for the fee. |
+| basic_fee | int64 | The fee amount. |
+
+#### acs1.MethodFees
+| Field | Type | Description |
+|-----------------|------------|----------------------------------|
+| method_name | string | The name of the method. |
+| fees | MethodFee | List of fees. |
+| is_size_fee_free| bool | Optional based on implementation.|
+
+#### AuthorityInfo
+| Field | Type | Description |
+|------------------|---------------|-----------------------------------|
+| contract_address | aelf.Address | The controller's contract address.|
+| owner_address | aelf.Address | The owner's address. |
+
+**Note:** Only system contracts on the main chain can implement ACS1.
+
+## Usage
+A pre-transaction, generated by FeeChargePreExecutionPlugin, charges the transaction fee before main processing.
+```cs
+///
+/// Related transactions will be generated by acs1 pre-plugin service,
+/// and will be executed before the origin transaction.
+///
+///
+///
+public override BoolValue ChargeTransactionFees(ChargeTransactionFeesInput input)
+{
+ // ...
+ // Record tx fee bill during current charging process.
+ var bill = new TransactionFeeBill();
+ var fromAddress = Context.Sender;
+ var methodFees = Context.Call(input.ContractAddress, nameof(GetMethodFee),
+ new StringValue {Value = input.MethodName});
+ var successToChargeBaseFee = true;
+ if (methodFees != null && methodFees.Fees.Any())
+ {
+ successToChargeBaseFee = ChargeBaseFee(GetBaseFeeDictionary(methodFees), ref bill);
+ }
+ var successToChargeSizeFee = true;
+ if (!IsMethodFeeSetToZero(methodFees))
+ {
+ // Then also do not charge size fee.
+ successToChargeSizeFee = ChargeSizeFee(input, ref bill);
+ }
+ // Update balances.
+ foreach (var tokenToAmount in bill.FeesMap)
+ {
+ ModifyBalance(fromAddress, tokenToAmount.Key, -tokenToAmount.Value);
+ Context.Fire(new TransactionFeeCharged
+ {
+ Symbol = tokenToAmount.Key,
+ Amount = tokenToAmount.Value
+ });
+ if (tokenToAmount.Value == 0)
+ {
+ //Context.LogDebug(() => $"Maybe incorrect charged tx fee of {tokenToAmount.Key}: it's 0.");
+ }
+ }
+ return new BoolValue {Value = successToChargeBaseFee && successToChargeSizeFee};
+}
+```
+
+### Steps:
+1. System calls `GetMethodFee` to determine the fee.
+2. Checks if the balance is sufficient:
+ - If yes, the fee is billed.
+ - If no, the transaction is rejected.
+3. If the method fee is not zero, the system charges a size fee based on the parameter's size.
+4. After charging, an `TransactionFeeCharged` event is thrown, modifying the sender's balance.
+5. The event is processed to calculate the total transaction fees in the block.
+6. In the next block:
+ - 10% of the fees are destroyed.
+ - 90% goes to the dividend pool on the main chain and to the FeeReceiver on the side chain.
+```cs
+///
+/// Burn 10% of tx fees.
+/// If Side Chain didn't set FeeReceiver, burn all.
+///
+///
+///
+private void TransferTransactionFeesToFeeReceiver(string symbol, long totalAmount)
+{
+ Context.LogDebug(() => "Transfer transaction fee to receiver.");
+ if (totalAmount <= 0) return;
+ var burnAmount = totalAmount.Div(10);
+ if (burnAmount > 0)
+ Context.SendInline(Context.Self, nameof(Burn), new BurnInput
+ {
+ Symbol = symbol,
+ Amount = burnAmount
+ });
+ var transferAmount = totalAmount.Sub(burnAmount);
+ if (transferAmount == 0)
+ return;
+ var treasuryContractAddress =
+ Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName);
+ if ( treasuryContractAddress!= null)
+ {
+ // Main chain would donate tx fees to dividend pool.
+ if (State.DividendPoolContract.Value == null)
+ State.DividendPoolContract.Value = treasuryContractAddress;
+ State.DividendPoolContract.Donate.Send(new DonateInput
+ {
+ Symbol = symbol,
+ Amount = transferAmount
+ });
+ }
+ else
+ {
+ if (State.FeeReceiver.Value != null)
+ {
+ Context.SendInline(Context.Self, nameof(Transfer), new TransferInput
+ {
+ To = State.FeeReceiver.Value,
+ Symbol = symbol,
+ Amount = transferAmount,
+ });
+ }
+ else
+ {
+ // Burn all!
+ Context.SendInline(Context.Self, nameof(Burn), new BurnInput
+ {
+ Symbol = symbol,
+ Amount = transferAmount
+ });
+ }
+ }
+}
+```
+
+## Implementation
+### Simple Implementation
+Implement only `GetMethodFee` to set fixed fees for methods.
+```cs
+public override MethodFees GetMethodFee(StringValue input)
+{
+ if (input.Value == nameof(Foo1) || input.Value == nameof(Foo2))
+ {
+ return new MethodFees
+ {
+ MethodName = input.Value,
+ Fees =
+ {
+ new MethodFee
+ {
+ BasicFee = 1_00000000,
+ Symbol = Context.Variables.NativeSymbol
+ }
+ }
+ };
+ }
+ if (input.Value == nameof(Bar1) || input.Value == nameof(Bar2))
+ {
+ return new MethodFees
+ {
+ MethodName = input.Value,
+ Fees =
+ {
+ new MethodFee
+ {
+ BasicFee = 2_00000000,
+ Symbol = Context.Variables.NativeSymbol
+ }
+ }
+ };
+ }
+ return new MethodFees();
+}
+```
+
+
+### Recommended Implementation
+1. Define a `MappedState` in the contract's State file for transaction fees.
+```cs
+public MappedState TransactionFees { get; set; }
+```
+2. Modify `TransactionFees` in `SetMethodFee` and return the value in `GetMethodFee`.
+```cs
+public override MethodFees GetMethodFee(StringValue input) {
+ return State.TransactionFees[input.Value];
+}
+```
+3. Add permission management to `SetMethodFee` to prevent arbitrary fee changes.
+```cs
+public SingletonState MethodFeeController { get; set; }
+```
+
+```cs
+public override Empty SetMethodFee(MethodFees input)
+{
+ foreach (var symbolToAmount in input.Fees)
+ {
+ AssertValidToken(symbolToAmount.Symbol, symbolToAmount.BasicFee);
+ }
+ RequiredMethodFeeControllerSet();
+ Assert(Context.Sender == State.MethodFeeController.Value.OwnerAddress, "Unauthorized to set method fee.");
+ State.TransactionFees[input.MethodName] = input;
+ return new Empty();
+}
+```
+### Permission Management
+1. Define a `SingletonState` with type `AuthorityInfo`.
+```cs
+private void RequiredMethodFeeControllerSet()
+{
+ if (State.MethodFeeController.Value != null) return;
+ if (State.ParliamentContract.Value == null)
+ {
+ State.ParliamentContract.Value = Context.GetContractAddressByName(SmartContractConstants.ParliamentContractSystemName);
+ }
+ var defaultAuthority = new AuthorityInfo();
+ // Parliament Auth Contract maybe not deployed.
+ if (State.ParliamentContract.Value != null)
+ {
+ defaultAuthority.OwnerAddress = State.ParliamentContract.GetDefaultOrganizationAddress.Call(new Empty());
+ defaultAuthority.ContractAddress = State.ParliamentContract.Value;
+ }
+ State.MethodFeeController.Value = defaultAuthority;
+}
+```
+2. Check the sender’s right by comparing its address with the owner’s address.
+3. Implement permission checks to ensure only authorized changes.
+
+### Changing Authority
+The authority for `SetMethodFee` can be changed through a transaction from the default parliament address.
+```cs
+public override Empty ChangeMethodFeeController(AuthorityInfo input)
+{
+ RequiredMethodFeeControllerSet();
+ AssertSenderAddressWith(State.MethodFeeController.Value.OwnerAddress);
+ var organizationExist = CheckOrganizationExist(input);
+ Assert(organizationExist, "Invalid authority input.");
+ State.MethodFeeController.Value = input;
+ return new Empty();
+}
+```
+```cs
+public override AuthorityInfo GetMethodFeeController(Empty input)
+{
+ RequiredMethodFeeControllerSet();
+ return State.MethodFeeController.Value;
+}
+```
+
+## Testing
+Create ACS1’s Stub and call `GetMethodFee` and `GetMethodFeeController` to check the return values.
+
+## Example
+All AElf system contracts implement ACS1 and can be used as references.
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md b/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md
new file mode 100644
index 0000000..a09b12d
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md
@@ -0,0 +1,421 @@
+# ACS10 - Dividend Pool Standard
+ACS10 facilitates the creation and management of dividend pools within a contract.
+
+## Interface
+To create a dividend pool, implement these optional interfaces:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|--------------------------|-----------------------|-------------------------|---------------------------------------------------------------------------------------------------|
+| Donate | `acs10.DonateInput` | `google.protobuf.Empty` | Transfers tokens from the caller to the dividend pool. Converts non-native tokens to native tokens if required. |
+| Release | `acs10.ReleaseInput` | `google.protobuf.Empty` | Releases dividends based on the specified period number. |
+| SetSymbolList | `acs10.SymbolList` | `google.protobuf.Empty` | Sets the list of token symbols supported by the dividend pool. |
+| GetSymbolList | `google.protobuf.Empty` | `acs10.SymbolList` | Retrieves the list of token symbols supported by the dividend pool. |
+| GetUndistributedDividends| `google.protobuf.Empty` | `acs10.Dividends` | Queries the balance of undistributed tokens according to the symbol list. |
+| GetDividends | `google.protobuf.Int64Value` | `acs10.Dividends` | Queries dividend information based on the specified height. |
+
+
+### Types
+
+#### `acs10.Dividends`
+| Field | Type | Description | Label |
+|--------|--------------------|----------------------------------------|--------|
+| `value`| `Dividends.ValueEntry` | The dividends, symbol -> amount. | repeated |
+
+#### `acs10.Dividends.ValueEntry`
+| Field | Type | Description | Label |
+|--------|----------|---------------|-------|
+| `key` | `string` | | |
+| `value`| `int64` | | |
+
+#### `acs10.DonateInput`
+| Field | Type | Description | Label |
+|----------|----------|-----------------------------|-------|
+| `symbol` | `string` | The token symbol to donate. | |
+| `amount` | `int64` | The amount to donate. | |
+
+#### `acs10.DonationReceived`
+| Field | Type | Description | Label |
+|-----------------|-----------------|-------------------------------|--------|
+| `from` | `aelf.Address` | The address of donors. | |
+| `pool_contract` | `aelf.Address` | The address of dividend pool. | |
+| `symbol` | `string` | The token symbol Donated. | |
+| `amount` | `int64` | The amount Donated. | |
+
+#### `acs10.ReleaseInput`
+| Field | Type | Description | Label |
+|-----------------|---------|--------------------------------|--------|
+| `period_number` | `int64` | The period number to release. | |
+
+#### `acs10.SymbolList`
+| Field | Type | Description | Label |
+|--------|----------|--------------------------------|--------|
+| `value`| `string` | The token symbol list. | repeated |
+
+#### `aelf.Address`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `value`| `bytes`| | |
+
+#### `aelf.BinaryMerkleTree`
+| Field | Type | Description | Label |
+|--------|-------|---------------------|--------|
+| `nodes`| `Hash`| The leaf nodes. | |
+| `root` | `Hash`| The root node hash. | repeated |
+| `leaf_count` | `int32` | The count of leaf node. | |
+
+#### `aelf.Hash`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `value`| `bytes`| | |
+
+#### `aelf.LogEvent`
+| Field | Type | Description | Label |
+|-------------|--------------|---------------------------------|--------|
+| `address` | `Address` | The contract address. | |
+| `name` | `string` | The name of the log event. | |
+| `indexed` | `bytes` | The indexed data, used to calculate bloom. | repeated |
+| `non_indexed` | `bytes` | The non indexed data. | repeated |
+
+#### `aelf.MerklePath`
+| Field | Type | Description | Label |
+|-------------------|---------------------|----------------------------|--------|
+| `merkle_path_nodes` | `MerklePathNode` | The merkle path nodes. | repeated |
+
+#### `aelf.MerklePathNode`
+| Field | Type | Description | Label |
+|--------|--------|----------------------|--------|
+| `hash` | `Hash` | The node hash. | |
+| `is_left_child_node` | `bool` | Whether it is a left child node. | |
+
+#### `aelf.SInt32Value`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `value`| `sint32`| | |
+
+#### `aelf.SInt64Value`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `value`| `sint64`| | |
+
+#### `aelf.ScopedStatePath`
+| Field | Type | Description | Label |
+|----------|-----------|---------------------|--------|
+| `address`| `Address` | The scope address. | |
+| `path` | `StatePath`| The path of contract state. | |
+
+#### `aelf.SmartContractRegistration`
+| Field | Type | Description | Label |
+|-------------------|--------|-------------------------------|--------|
+| `category` | `sint32`| The category of contract code (0: C#). | |
+| `code` | `bytes`| The byte array of the contract code. | |
+| `code_hash` | `Hash` | The hash of the contract code. | |
+| `is_system_contract` | `bool`| Whether it is a system contract. | |
+| `version` | `int32`| The version of the current contract. | |
+
+#### `aelf.StatePath`
+| Field | Type | Description | Label |
+|----------|--------|-------------------------------|--------|
+| `parts` | `string`| The partial path of the state path. | repeated |
+
+#### `aelf.Transaction`
+| Field | Type | Description | Label |
+|-------------------|-----------|--------------------------------|--------|
+| `from` | `Address` | The address of the sender of the transaction. | |
+| `to` | `Address` | The address of the contract when calling a contract. | |
+| `ref_block_number`| `int64` | The height of the referenced block hash. | |
+| `ref_block_prefix`| `bytes` | The first four bytes of the referenced block hash. | |
+| `method_name` | `string` | The name of a method in the smart contract at the To address. | |
+| `params` | `bytes` | The parameters to pass to the smart contract method. | |
+| `signature` | `bytes` | When signing a transaction, subset of fields: from/to, target method, parameter, reference block number, prefix. | |
+
+#### `aelf.TransactionExecutingStateSet`
+| Field | Type | Description | Label |
+|-----------------|---------------------|------------------------------|--------|
+| `writes` | `TransactionExecutingStateSet.WritesEntry` | The changed states. | repeated |
+| `reads` | `TransactionExecutingStateSet.ReadsEntry` | The read states. | repeated |
+| `deletes` | `TransactionExecutingStateSet.DeletesEntry` | The deleted states. | repeated |
+
+#### `aelf.TransactionExecutingStateSet.DeletesEntry`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `key` | `string`| | |
+| `value`| `bool` | | |
+
+#### `aelf.TransactionExecutingStateSet.ReadsEntry`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `key` | `string`| | |
+| `value`| `bool` | | |
+
+#### `aelf.TransactionExecutingStateSet.WritesEntry`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `key` | `string`| | |
+| `value`| `bytes` | | |
+
+#### `aelf.TransactionResult`
+| Field | Type | Description | Label |
+|-------------------|-----------|--------------------------------|--------|
+| `transaction_id` | `Hash` | The transaction id. | |
+| `status` | `TransactionResultStatus` | The transaction result status. | |
+| `logs` | `LogEvent`| The log events. | repeated |
+| `bloom` | `bytes` | Bloom filter for transaction logs. | repeated |
+| `return_value` | `bytes` | The return value of the transaction execution. | |
+| `block_number` | `int64` | The height of the block that packages the transaction. | |
+| `block_hash` | `Hash` | The hash of the block that packages the transaction. | |
+| `error` | `string` | Failed execution error message. | |
+
+#### `aelf.TransactionResultStatus`
+| Name | Number | Description |
+|---------------------|--------|-------------------------------------------------------|
+| `NOT_EXISTED` | `0` | The execution result of the transaction does not exist. |
+| `PENDING` | `1` | The transaction is in the transaction pool waiting to be packaged. |
+| `FAILED` | `2` | Transaction execution failed. |
+| `MINED` | `3` | The transaction was successfully executed and packaged into a block. |
+| `CONFLICT` | `4` | When executed in parallel, there are conflicts with other transactions. |
+| `PENDING_VALIDATION`| `5` | The transaction is waiting for validation. |
+| `NODE_VALIDATION_FAILED` | `6`| Transaction validation failed. |
+
+## Usage
+ACS10 provides a standardized interface for dividend pools, independent of AElf chain interactions.
+
+### Implementation
+
+- Using the Profit Contract
+```cs
+State.ProfitContract.Value =
+ Context.GetContractAddressByName(SmartContractConstants.ProfitContractSystemName);
+var schemeToken = HashHelper.ComputeFrom(Context.Self);
+State.ProfitContract.CreateScheme.Send(new CreateSchemeInput
+{
+ Manager = Context.Self,
+ CanRemoveBeneficiaryDirectly = true,
+ IsReleaseAllBalanceEveryTimeByDefault = true,
+ Token = schemeToken
+});
+State.ProfitSchemeId.Value = Context.GenerateId(State.ProfitContract.Value, schemeToken);
+```
+
+- Using the TokenHolder Contract
+```cs
+State.TokenHolderContract.Value =
+ Context.GetContractAddressByName(SmartContractConstants.TokenHolderContractSystemName);
+State.TokenHolderContract.CreateScheme.Send(new CreateTokenHolderProfitSchemeInput
+{
+ Symbol = Context.Variables.NativeSymbol,
+ MinimumLockMinutes = input.MinimumLockMinutes
+});
+return new Empty();
+```
+
+- Donate can be implemented as:
+```cs
+public override Empty Donate(DonateInput input)
+{
+ State.TokenContract.TransferFrom.Send(new TransferFromInput
+ {
+ From = Context.Sender,
+ Symbol = input.Symbol,
+ Amount = input.Amount,
+ To = Context.Self
+ });
+ State.TokenContract.Approve.Send(new ApproveInput
+ {
+ Symbol = input.Symbol,
+ Amount = input.Amount,
+ Spender = State.TokenHolderContract.Value
+ });
+ State.TokenHolderContract.ContributeProfits.Send(new ContributeProfitsInput
+ {
+ SchemeManager = Context.Self,
+ Symbol = input.Symbol,
+ Amount = input.Amount
+ });
+ Context.Fire(new DonationReceived
+ {
+ From = Context.Sender,
+ Symbol = input.Symbol,
+ Amount = input.Amount,
+ PoolContract = Context.Self
+ });
+ var currentReceivedDividends = State.ReceivedDividends[Context.CurrentHeight];
+ if (currentReceivedDividends != null && currentReceivedDividends.Value.ContainsKey(input.Symbol))
+ {
+ currentReceivedDividends.Value[input.Symbol] =
+ currentReceivedDividends.Value[input.Symbol].Add(input.Amount);
+ }
+ else
+ {
+ currentReceivedDividends = new Dividends
+ {
+ Value =
+ {
+ {
+ input.Symbol, input.Amount
+ }
+ }
+ };
+ }
+ State.ReceivedDividends[Context.CurrentHeight] = currentReceivedDividends;
+ Context.LogDebug(() => string.Format("Contributed {0} {1}s to side chain dividends pool.", input.Amount, input.Symbol));
+ return new Empty();
+}
+```
+
+- The method Release directly sends the TokenHolder’s method DistributeProfits transaction:
+```cs
+public override Empty Release(ReleaseInput input)
+{
+ State.TokenHolderContract.DistributeProfits.Send(new DistributeProfitsInput
+ {
+ SchemeManager = Context.Self
+ });
+ return new Empty();
+}
+```
+
+- GetSymbolList returns the symbol list recorded in dividend scheme:
+```cs
+public override SymbolList GetSymbolList(Empty input)
+{
+ return new SymbolList
+ {
+ Value =
+ {
+ GetDividendPoolScheme().ReceivedTokenSymbols
+ }
+ };
+}
+private Scheme GetDividendPoolScheme()
+{
+ if (State.DividendPoolSchemeId.Value == null)
+ {
+ var tokenHolderScheme = State.TokenHolderContract.GetScheme.Call(Context.Self);
+ State.DividendPoolSchemeId.Value = tokenHolderScheme.SchemeId;
+ }
+ return Context.Call(
+ Context.GetContractAddressByName(SmartContractConstants.ProfitContractSystemName),
+ nameof(ProfitContractContainer.ProfitContractReferenceState.GetScheme),
+ State.DividendPoolSchemeId.Value);
+}
+```
+- Implementation of GetUndistributedDividends returns the balance (same as previous section):
+```cs
+public override Dividends GetUndistributedDividends(Empty input)
+{
+ var scheme = GetDividendPoolScheme();
+ return new Dividends
+ {
+ Value =
+ {
+ scheme.ReceivedTokenSymbols.Select(s => State.TokenContract.GetBalance.Call(new GetBalanceInput
+ {
+ Owner = scheme.VirtualAddress,
+ Symbol = s
+ })).ToDictionary(b => b.Symbol, b => b.Balance)
+ }
+ };
+}
+```
+
+### Test
+Testing includes sending Donate, Release transactions, and querying operations. Example:
+
+- Define the required Stubs:
+```cs
+const long amount = 10_00000000;
+var keyPair = SampleECKeyPairs.KeyPairs[0];
+var address = Address.FromPublicKey(keyPair.PublicKey);
+var acs10DemoContractStub =
+ GetTester(DAppContractAddress, keyPair);
+var tokenContractStub =
+ GetTester(TokenContractAddress, keyPair);
+var tokenHolderContractStub =
+ GetTester(TokenHolderContractAddress,
+ keyPair);
+```
+
+- Approve the TokenHolder contract and the dividend pool contract
+```cs
+await tokenContractStub.Approve.SendAsync(new ApproveInput
+{
+ Spender = TokenHolderContractAddress,
+ Symbol = "ELF",
+ Amount = long.MaxValue
+});
+await tokenContractStub.Approve.SendAsync(new ApproveInput
+{
+ Spender = DAppContractAddress,
+ Symbol = "ELF",
+ Amount = long.MaxValue
+});
+```
+
+- Lock the position to reducethe account balance by 10 ELF:
+```cs
+await tokenHolderContractStub.RegisterForProfits.SendAsync(new RegisterForProfitsInput
+{
+ SchemeManager = DAppContractAddress,
+ Amount = amount
+});
+```
+
+- Implement Donate to reduce the account balance by another 10 ELF:
+await acs10DemoContractStub.Donate.SendAsync(new DonateInput
+{
+ Symbol = "ELF",
+ Amount = amount
+});
+
+- Test the GetUndistributedDividends and GetDividends:
+```cs
+// Check undistributed dividends before releasing.
+{
+ var undistributedDividends =
+ await acs10DemoContractStub.GetUndistributedDividends.CallAsync(new Empty());
+ undistributedDividends.Value["ELF"].ShouldBe(amount);
+}
+var blockchainService = Application.ServiceProvider.GetRequiredService();
+var currentBlockHeight = (await blockchainService.GetChainAsync()).BestChainHeight;
+var dividends =
+ await acs10DemoContractStub.GetDividends.CallAsync(new Int64Value {Value = currentBlockHeight});
+dividends.Value["ELF"].ShouldBe(amount);
+```
+
+- Release bonus, and test GetUndistributedDividends again:
+```cs
+await acs10DemoContractStub.Release.SendAsync(new ReleaseInput
+{
+ PeriodNumber = 1
+});
+// Check undistributed dividends after releasing.
+{
+ var undistributedDividends =
+ await acs10DemoContractStub.GetUndistributedDividends.CallAsync(new Empty());
+ undistributedDividends.Value["ELF"].ShouldBe(0);
+}
+```
+
+- Account will receive the dividend and will change the balance:
+```cs
+var balanceBeforeClaimForProfits = await tokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+{
+ Owner = address,
+ Symbol = "ELF"
+});
+await tokenHolderContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput
+{
+ SchemeManager = DAppContractAddress,
+ Beneficiary = address
+});
+var balanceAfterClaimForProfits = await tokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+{
+ Owner = address,
+ Symbol = "ELF"
+});
+balanceAfterClaimForProfits.Balance.ShouldBe(balanceBeforeClaimForProfits.Balance + amount);
+```
+
+### Example
+Implementing ACS10 facilitates building dividend pools on main and side chains.
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md b/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md
new file mode 100644
index 0000000..a0d5dd9
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md
@@ -0,0 +1,142 @@
+# ACS11 - Cross Chain Consensus Standard
+ACS11 is a standard used to customize consensus mechanisms for cross-chain operations.
+
+## Interface
+Contracts inheriting from ACS11 must implement the following interfaces:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|-----------------------------------|----------------------------------|----------------------|-------------------------------------------------|
+| `UpdateInformationFromCrossChain` | `google.protobuf.BytesValue` | `google.protobuf.Empty` | Update the consensus information of the side chain. |
+| `GetChainInitializationInformation` | `google.protobuf.BytesValue` | `google.protobuf.BytesValue` | Get the current miner list and consensus round information. |
+| `CheckCrossChainIndexingPermission` | `aelf.Address` | `google.protobuf.BoolValue` | Verify that the input address is the current miner. |
+
+### Types
+
+#### `aelf.Address`
+| Field | Type | Description | Label |
+|--------|--------|------------------------|--------|
+| `value`| `bytes`| | |
+
+#### `aelf.BinaryMerkleTree`
+| Field | Type | Description | Label |
+|--------|-------|---------------------|--------|
+| `nodes`| `Hash`| The leaf nodes. | |
+| `root` | `Hash`| The root node hash. | repeated |
+| `leaf_count` | `int32` | The count of leaf node. | |
+
+#### `aelf.Hash`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `value`| `bytes`| | |
+
+#### `aelf.LogEvent`
+| Field | Type | Description | Label |
+|-------------|--------------|---------------------------------|--------|
+| `address` | `Address` | The contract address. | |
+| `name` | `string` | The name of the log event. | |
+| `indexed` | `bytes` | The indexed data, used to calculate bloom. | repeated |
+| `non_indexed` | `bytes` | The non-indexed data. | repeated |
+
+#### `aelf.MerklePath`
+| Field | Type | Description | Label |
+|-------------------|---------------------|----------------------------|--------|
+| `merkle_path_nodes` | `MerklePathNode` | The merkle path nodes. | repeated |
+
+#### `aelf.MerklePathNode`
+| Field | Type | Description | Label |
+|--------|--------|----------------------|--------|
+| `hash` | `Hash` | The node hash. | |
+| `is_left_child_node` | `bool` | Whether it is a left child node. | |
+
+#### `aelf.SInt32Value`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `value`| `sint32`| | |
+
+#### `aelf.SInt64Value`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `value`| `sint64`| | |
+
+#### `aelf.ScopedStatePath`
+| Field | Type | Description | Label |
+|----------|-----------|---------------------|--------|
+| `address`| `Address` | The scope address. | |
+| `path` | `StatePath`| The path of contract state. | |
+
+#### `aelf.SmartContractRegistration`
+| Field | Type | Description | Label |
+|-------------------|--------|-------------------------------|--------|
+| `category` | `sint32`| The category of contract code (0: C#). | |
+| `code` | `bytes`| The byte array of the contract code. | |
+| `code_hash` | `Hash` | The hash of the contract code. | |
+| `is_system_contract` | `bool`| Whether it is a system contract. | |
+| `version` | `int32`| The version of the current contract. | |
+
+#### `aelf.StatePath`
+| Field | Type | Description | Label |
+|----------|--------|-------------------------------|--------|
+| `parts` | `string`| The partial path of the state path. | repeated |
+
+#### `aelf.Transaction`
+| Field | Type | Description | Label |
+|-------------------|-----------|--------------------------------|--------|
+| `from` | `Address` | The address of the sender of the transaction. | |
+| `to` | `Address` | The address of the contract when calling a contract. | |
+| `ref_block_number`| `int64` | The height of the referenced block hash. | |
+| `ref_block_prefix`| `bytes` | The first four bytes of the referenced block hash. | |
+| `method_name` | `string` | The name of a method in the smart contract at the To address. | |
+| `params` | `bytes` | The parameters to pass to the smart contract method. | |
+| `signature` | `bytes` | Subset of fields: from/to, target method, parameter, reference block number, prefix. | |
+
+#### `aelf.TransactionExecutingStateSet`
+| Field | Type | Description | Label |
+|-----------------|---------------------|------------------------------|--------|
+| `writes` | `TransactionExecutingStateSet.WritesEntry` | The changed states. | repeated |
+| `reads` | `TransactionExecutingStateSet.ReadsEntry` | The read states. | repeated |
+| `deletes` | `TransactionExecutingStateSet.DeletesEntry` | The deleted states. | repeated |
+
+##### `aelf.TransactionExecutingStateSet.DeletesEntry`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `key` | `string`| | |
+| `value`| `bool` | | |
+
+##### `aelf.TransactionExecutingStateSet.ReadsEntry`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `key` | `string`| | |
+| `value`| `bool` | | |
+
+##### `aelf.TransactionExecutingStateSet.WritesEntry`
+| Field | Type | Description | Label |
+|--------|--------|---------------------|--------|
+| `key` | `string`| | |
+| `value`| `bytes` | | |
+
+#### `aelf.TransactionResult`
+| Field | Type | Description | Label |
+|-------------------|-----------|--------------------------------|--------|
+| `transaction_id` | `Hash` | The transaction id. | |
+| `status` | `TransactionResultStatus` | The transaction result status. | |
+| `logs` | `LogEvent`| The log events. | repeated |
+| `bloom` | `bytes` | Bloom filter for transaction logs. | repeated |
+| `return_value` | `bytes` | The return value of the transaction execution. | |
+| `block_number` | `int64` | The height of the block that packages the transaction. | |
+| `block_hash` | `Hash` | The hash of the block that packages the transaction. | |
+| `error` | `string` | Failed execution error message. | |
+
+#### `aelf.TransactionResultStatus`
+| Name | Number | Description |
+|---------------------|--------|-------------------------------------------------------|
+| `NOT_EXISTED` | `0` | The execution result of the transaction does not exist. |
+| `PENDING` | `1` | The transaction is in the transaction pool waiting to be packaged. |
+| `FAILED` | `2` | Transaction execution failed. |
+| `MINED` | `3` | The transaction was successfully executed and packaged into a block. |
+| `CONFLICT` | `4` | When executed in parallel, there are conflicts with other transactions. |
+| `PENDING_VALIDATION`| `5` | The transaction is waiting for validation. |
+| `NODE_VALIDATION_FAILED` | `6`| Transaction validation failed. |
+
+### Example
+ACS11 defines methods for customizing consensus mechanisms for cross-chain scenarios. AElf provides an implementation of ACS11 through the AEDPoS contract. Developers can refer to the AEDPoS contract API for implementation details.
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md b/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md
new file mode 100644
index 0000000..927d5d4
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md
@@ -0,0 +1,16 @@
+# ACS12 - User Contract Standard
+ACS12 is a standard used to manage user contracts.
+
+## Types
+
+### `acs12.UserContractMethodFees`
+| Field | Type | Label | Description |
+|--------|-------------------------|-----------|----------------------------------------|
+| `fees` | `acs12.UserContractMethodFee` | repeated | List of fees to be charged. |
+| `is_size_fee_free` | `bool` | | Optional based on the implementation of `SetConfiguration` method. |
+
+### `acs12.UserContractMethodFee`
+| Field | Type | Label | Description |
+|-------------|---------|-----------|----------------------------------------|
+| `symbol` | `string`| | The token symbol of the method fee. |
+| `basic_fee` | `int64` | | The amount of fees to be charged. |
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard.md b/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard.md
new file mode 100644
index 0000000..a0bea4d
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard.md
@@ -0,0 +1,389 @@
+# ACS2 - Parallel Execution Standard
+ACS2 helps with parallel transaction execution.
+
+## Interface
+Contracts using ACS2 need to implement one method:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|------------------|-----------------------|----------------------|-----------------------------------------------------|
+| GetResourceInfo | `aelf.Transaction` | `acs2.ResourceInfo` | Gets the resource info that the transaction execution depends on. |
+
+### Types
+#### acs2.ResourceInfo
+| Field | Type | Description |
+|------------------|-------------------------|----------------------------------|
+| write_paths | aelf.ScopedStatePath | State paths for writing. |
+| read_paths | aelf.ScopedStatePath | State paths for reading. |
+| non_parallelizable| bool | If the transaction isn't parallel.|
+
+#### aelf.Address
+| Field | Type | Description |
+|-------|-------|--------------------------|
+| value | bytes | |
+
+#### aelf.BinaryMerkleTree
+| Field | Type | Description |
+|-------------|--------|--------------------|
+| nodes | Hash | Leaf nodes. |
+| root | Hash | Root node hash. |
+| leaf_count | int32 | Count of leaf nodes.|
+
+#### aelf.Hash
+| Field | Type | Description |
+|-------|-------|--------------------------|
+| value | bytes | |
+
+#### aelf.LogEvent
+| Field | Type | Description |
+|--------------|----------|---------------------|
+| address | Address | Contract address. |
+| name | string | Log event name. |
+| indexed | bytes | Indexed data. |
+| non_indexed | bytes | Non-indexed data. |
+
+#### aelf.MerklePath
+| Field | Type | Description |
+|-------------------|------------------|-------------------------|
+| merkle_path_nodes | MerklePathNode | Merkle path nodes. |
+
+#### aelf.MerklePathNode
+| Field | Type | Description |
+|-------------------|-------|-------------------------|
+| hash | Hash | Node hash. |
+| is_left_child_node| bool | If it's a left child node.|
+
+#### aelf.SInt32Value
+| Field | Type | Description |
+|-------|-------|------------------------|
+| value | sint32| |
+
+#### aelf.SInt64Value
+
+| Field | Type | Description |
+|-------|-------|------------------------|
+| value | sint64| |
+
+#### aelf.ScopedStatePath
+| Field | Type | Description |
+|----------|-------------|--------------------------------------|
+| address | Address | Contract address. |
+| path | StatePath | Path of contract state. |
+
+#### aelf.SmartContractRegistration
+| Field | Type | Description |
+|-------------------|---------|----------------------------------|
+| category | sint32 | Contract code category (0: C#). |
+| code | bytes | Contract code byte array. |
+| code_hash | Hash | Contract code hash. |
+| is_system_contract| bool | If it's a system contract. |
+| version | int32 | Current contract version. |
+
+#### aelf.StatePath
+| Field | Type | Description |
+|-------|--------|--------------------------|
+| parts | string | State path parts. |
+
+#### aelf.Transaction
+| Field | Type | Description |
+|------------------|--------|-----------------------------------|
+| from | Address| Sender address. |
+| to | Address| Contract address. |
+| ref_block_number | int64 | Referenced block height. |
+| ref_block_prefix | bytes | First 4 bytes of referenced block hash. |
+| method_name | string | Method name in the contract. |
+| params | bytes | Method parameters. |
+| signature | bytes | Signature of the transaction. |
+
+#### aelf.TransactionExecutingStateSet
+| Field | Type | Description |
+|----------|-------------------------------------------|---------------------|
+| writes | TransactionExecutingStateSet.WritesEntry | Changed states. |
+| reads | TransactionExecutingStateSet.ReadsEntry | Read states. |
+| deletes | TransactionExecutingStateSet.DeletesEntry | Deleted states. |
+
+#### aelf.TransactionExecutingStateSet.DeletesEntry
+| Field | Type | Description |
+|-------|--------|-------------------|
+| key | string | |
+| value | bool | |
+
+#### aelf.TransactionExecutingStateSet.ReadsEntry
+| Field | Type | Description |
+|-------|--------|-------------------|
+| key | string | |
+| value | bool | |
+
+#### aelf.TransactionExecutingStateSet.WritesEntry
+| Field | Type | Description |
+|-------|--------|-------------------|
+| key | string | |
+| value | bytes | |
+
+#### aelf.TransactionResult
+| Field | Type | Description |
+|----------------|-----------------------|-----------------------------------------------|
+| transaction_id | Hash | Transaction ID. |
+| status | TransactionResultStatus| Transaction result status. |
+| logs | LogEvent | Log events. |
+| bloom | bytes | Bloom filter for transaction logs. |
+| return_value | bytes | Return value of the transaction execution. |
+| block_number | int64 | Block height that packages the transaction. |
+| block_hash | Hash | Block hash that packages the transaction. |
+| error | string | Failed execution error message. |
+
+#### aelf.TransactionResultStatus
+
+| Name | Number | Description |
+|-----------------------|--------|-----------------------------------------------------------|
+| NOT_EXISTED | 0 | Transaction result does not exist. |
+| PENDING | 1 | Transaction is waiting to be packaged. |
+| FAILED | 2 | Transaction execution failed. |
+| MINED | 3 | Transaction was successfully executed and packaged. |
+| CONFLICT | 4 | Transaction has conflicts with other transactions. |
+| PENDING_VALIDATION | 5 | Transaction is waiting for validation. |
+| NODE_VALIDATION_FAILED| 6 | Transaction validation failed. |
+
+## Usage
+
+AElf uses a key-value database to store data. State Path determines the key for contract execution data.
+
+For example, a Token contract defines a balance property:
+```cs
+public MappedState Balances { get; set; }
+```
+
+To access the balance of an address (`2EM5uV6bSJh6xJfZTUa1pZpYsYcCUAdPvZvFUJzMDJEx3rbioz`) for a `Token contract` address (`Nmjj7noTpMqZ522j76SDsFLhiKkThv1u3d4TxqJMD8v89tWmE`), use its key in the database:
+```cs
+Nmjj7noTpMqZ522j76SDsFLhiKkThv1u3d4TxqJMD8v89tWmE/Balances/2EM5uV6bSJh6xJfZTUa1pZpYsYcCUAdPvZvFUJzMDJEx3rbioz/ELF
+```
+
+Parallel execution groups transactions by their State Paths. If two methods don’t access the same `StatePath`, they can be executed in parallel.
+
+If State Paths mismatch, the transaction is canceled and labeled as “cannot be grouped”.
+
+For more details, check the `ITransactionGrouper` and `IParallelTransactionExecutingService` code.
+
+## Implementation
+Example: Token Contract
+For the Transfer method, notify ITransactionGrouper via GetResourceInfo about the ELF balances of address A and B:
+```cs
+var args = TransferInput.Parser.ParseFrom(txn.Params);
+var resourceInfo = new ResourceInfo
+{
+ Paths =
+ {
+ GetPath(nameof(TokenContractState.Balances), txn.From.ToString(), args.Symbol),
+ GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol),
+ }
+};
+return resourceInfo;
+```
+
+The `GetPath` method forms a `ScopedStatePath` from key data:
+```cs
+private ScopedStatePath GetPath(params string[] parts)
+{
+ return new ScopedStatePath
+ {
+ Address = Context.Self,
+ Path = new StatePath
+ {
+ Parts =
+ {
+ parts
+ }
+ }
+ }
+}
+```
+
+## Testing
+Construct two transactions and pass them to `ITransactionGrouper` to test if they can run in parallel using `GroupAsync`.
+
+Prepare two stubs with different addresses:
+```cs
+var keyPair1 = SampleECKeyPairs.KeyPairs[0];
+var acs2DemoContractStub1 = GetACS2DemoContractStub(keyPair1);
+var keyPair2 = SampleECKeyPairs.KeyPairs[1];
+var acs2DemoContractStub2 = GetACS2DemoContractStub(keyPair2);
+```
+
+```cs
+var transactionGrouper = Application.ServiceProvider.GetRequiredService();
+var blockchainService = Application.ServiceProvider.GetRequiredService();
+var chain = await blockchainService.GetChainAsync();
+```
+
+Check with transactionGrouper:
+```cs
+// Situation can be parallel executed.
+{
+ var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext
+ {
+ BlockHash = chain.BestChainHash,
+ BlockHeight = chain.BestChainHeight
+ }, new List
+ {
+ acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[3].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ });
+ groupedTransactions.Parallelizables.Count.ShouldBe(2);
+}
+// Situation cannot.
+{
+ var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext
+ {
+ BlockHash = chain.BestChainHash,
+ BlockHeight = chain.BestChainHeight
+ }, new List
+ {
+ acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ });
+ groupedTransactions.Parallelizables.Count.ShouldBe(1);
+}
+```
+
+## Example
+Refer to the `MultiToken contract` implementation for `GetResourceInfo`. Note that `Transfer` method needs to handle transaction fees along with keys.
+
+
+
+
+
+
+ACS2 - Parallel Execution Standard
+
+ACS2 enables parallel execution of transactions by providing necessary resource information.
+
+### Interface
+
+A contract inheriting ACS2 must implement:
+
+#### Methods
+
+| Method Name | Request Type | Response Type | Description |
+|------------------|---------------------|---------------------|-------------------------------------------------------|
+| GetResourceInfo | aelf.Transaction | acs2.ResourceInfo | Retrieves resource dependencies for transaction exec. |
+
+### Types
+
+#### acs2.ResourceInfo
+
+| Field | Type | Description | Label |
+|-------------------|----------------------|------------------------------------|-----------|
+| write_paths | aelf.ScopedStatePath | State paths written during execution| repeated |
+| read_paths | aelf.ScopedStatePath | State paths read during execution | repeated |
+| non_parallelizable| bool | Indicates if transaction is non-parallelizable.| |
+
+#### Other Types (Omitted for brevity)
+
+Several other types like `aelf.Address`, `aelf.BinaryMerkleTree`, `aelf.LogEvent`, etc., are used within `acs2.ResourceInfo`.
+
+### Usage
+
+aelf uses State Paths to manage data storage, ensuring transaction grouping based on accessed paths for efficient parallel execution.
+
+### Implementation
+
+Token contract, for example, modifies balances through method Transfer. GetResourceInfo must notify ITransactionGrouper of accessed state paths.
+
+```cs
+var args = TransferInput.Parser.ParseFrom(txn.Params);
+var resourceInfo = new ResourceInfo
+{
+ Paths =
+ {
+ GetPath(nameof(TokenContractState.Balances), txn.From.ToString(), args.Symbol),
+ GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol),
+ }
+};
+return resourceInfo;
+```
+
+### Test
+Test transaction parallelizability using ITransactionGrouper's GroupAsync method with sample transactions.
+
+ ```cs
+ var keyPair1 = SampleECKeyPairs.KeyPairs[0];
+ var acs2DemoContractStub1 = GetACS2DemoContractStub(keyPair1);
+ var keyPair2 = SampleECKeyPairs.KeyPairs[1];
+ var acs2DemoContractStub2 = GetACS2DemoContractStub(keyPair2);
+
+ var transactionGrouper = Application.ServiceProvider.GetRequiredService();
+ var blockchainService = Application.ServiceProvider.GetRequiredService();
+ var chain = await blockchainService.GetChainAsync();
+
+ // Test parallel execution scenario
+ {
+ var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext
+ {
+ BlockHash = chain.BestChainHash,
+ BlockHeight = chain.BestChainHeight
+ }, new List
+ {
+ acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[3].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ });
+ groupedTransactions.Parallelizables.Count.ShouldBe(2);
+ }
+
+ // Test non-parallel execution scenario
+ {
+ var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext
+ {
+ BlockHash = chain.BestChainHash,
+ BlockHeight = chain.BestChainHeight
+ }, new List
+ {
+ acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput
+ {
+ To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey),
+ Symbol = "ELF",
+ Amount = 1
+ }),
+ });
+ groupedTransactions.Parallelizables.Count.ShouldBe(1);
+ }
+ ```
+
+### Example
+
+For an example of implementing GetResourceInfo, refer to the MultiToken contract, ensuring transaction fees are considered for the keys involved.
diff --git a/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md b/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md
new file mode 100644
index 0000000..79b5f66
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md
@@ -0,0 +1,357 @@
+# ACS3 - Contract Proposal Standard
+
+ACS3 is used when a method needs multiple approvals. Implement these methods for voting and approval:
+
+## Interface
+
+### Methods
+
+| Method Name | Request Type | Response Type | Description |
+| ---------------------------------- | ---------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------ |
+| **CreateProposal** | acs3.CreateProposalInput | aelf.Hash | Creates a proposal for voting and returns the proposal ID. |
+| **Approve** | aelf.Hash | google.protobuf.Empty | Approves a proposal by its ID. |
+| **Reject** | aelf.Hash | google.protobuf.Empty | Rejects a proposal by its ID. |
+| **Abstain** | aelf.Hash | google.protobuf.Empty | Abstains from voting on a proposal by its ID. |
+| **Release** | aelf.Hash | google.protobuf.Empty | Releases a proposal by its ID, triggering the specified contract call. |
+| **ChangeOrganizationThreshold** | acs3.ProposalReleaseThreshold | google.protobuf.Empty | Changes the proposal thresholds, affecting all current proposals. |
+| **ChangeOrganizationProposerWhiteList** | acs3.ProposerWhiteList | google.protobuf.Empty | Changes the proposer whitelist for the organization. |
+| **CreateProposalBySystemContract** | acs3.CreateProposalBySystemContractInput | aelf.Hash | Creates a proposal by system contracts and returns the proposal ID. |
+| **ClearProposal** | aelf.Hash | google.protobuf.Empty | Removes a specified proposal. If the proposal is active, removal fails. |
+| **GetProposal** | aelf.Hash | acs3.ProposalOutput | Retrieves a proposal by its ID. |
+| **ValidateOrganizationExist** | aelf.Address | google.protobuf.BoolValue | Checks if an organization exists. |
+| **ValidateProposerInWhiteList** | acs3.ValidateProposerInWhiteListInput | google.protobuf.BoolValue | Checks if the proposer is in the whitelist. |
+
+### Types
+
+#### acs3.CreateProposalBySystemContractInput
+| Field | Type | Description | Label |
+| --------------- | ---------------- | --------------------------------- | ------- |
+| proposal_input | CreateProposalInput | Parameters for creating the proposal | |
+| origin_proposer | aelf.Address | Address of the proposer | |
+
+#### acs3.CreateProposalInput
+| Field | Type | Description | Label |
+| -------------------- | -------------------------- | ------------------------------------- | ----- |
+| contract_method_name | string | Method name to call after release | |
+| to_address | aelf.Address | Contract address to call after release| |
+| params | bytes | Parameters for the method call | |
+| expired_time | google.protobuf.Timestamp | Proposal expiration time | |
+| organization_address | aelf.Address | Organization address | |
+| proposal_description_url | string | URL for proposal description | |
+| token | aelf.Hash | Token for proposal ID generation | |
+
+#### acs3.OrganizationCreated
+| Field | Type | Description | Label |
+| ------------------- | ------------- | ------------------------ | ----- |
+| organization_address| aelf.Address | Created organization address | |
+
+#### acs3.OrganizationHashAddressPair
+| Field | Type | Description | Label |
+| ------------------- | ------------- | ------------------------ | ----- |
+| organization_hash | aelf.Hash | Organization ID | |
+| organization_address| aelf.Address | Organization address | |
+
+#### acs3.OrganizationThresholdChanged
+| Field | Type | Description | Label |
+| ------------------------- | ------------------------ | ------------------------ | ----- |
+| organization_address | aelf.Address | Organization address | |
+| proposer_release_threshold| ProposalReleaseThreshold | New release threshold | |
+
+#### acs3.OrganizationWhiteListChanged
+| Field | Type | Description | Label |
+| ------------------- | ------------- | ------------------------ | ----- |
+| organization_address| aelf.Address | Organization address | |
+| proposer_white_list | ProposerWhiteList | New proposer whitelist | |
+
+#### acs3.ProposalCreated
+| Field | Type | Description | Label |
+| ------------------- | ------------- | ------------------------ | ----- |
+| proposal_id | aelf.Hash | Created proposal ID | |
+| organization_address| aelf.Address | Organization address | |
+
+#### acs3.ProposalOutput
+| Field | Type | Description | Label |
+| -------------------- | -------------------------- | ------------------------------------- | ----- |
+| proposal_id | aelf.Hash | Proposal ID | |
+| contract_method_name | string | Method name for release | |
+| to_address | aelf.Address | Target contract address | |
+| params | bytes | Release transaction parameters | |
+| expired_time | google.protobuf.Timestamp | Proposal expiration date | |
+| organization_address | aelf.Address | Organization address | |
+| proposer | aelf.Address | Proposer address | |
+| to_be_released | bool | Indicates if releasable | |
+| approval_count | int64 | Approval count | |
+| rejection_count | int64 | Rejection count | |
+| abstention_count | int64 | Abstention count | |
+
+#### acs3.ProposalReleaseThreshold
+| Field | Type | Description | Label |
+| -------------------------- | ----- | ------------------------------- | ----- |
+| minimal_approval_threshold | int64 | Minimum approval threshold | |
+| maximal_rejection_threshold| int64 | Maximum rejection threshold | |
+| maximal_abstention_threshold | int64 | Maximum abstention threshold | |
+| minimal_vote_threshold | int64 | Minimum vote threshold | |
+
+#### acs3.ProposalReleased
+| Field | Type | Description | Label |
+| ------------------- | ------------- | ------------------------ | ----- |
+| proposal_id | aelf.Hash | Released proposal ID | |
+| organization_address| aelf.Address | Organization address | |
+
+#### acs3.ProposerWhiteList
+| Field | Type | Description | Label |
+| ---------- | ------------- | ----------------- | -------- |
+| proposers | aelf.Address | Proposer addresses| repeated |
+
+#### acs3.ReceiptCreated
+| Field | Type | Description | Label |
+| ------------------- | ------------------------- | ------------------------ | ----- |
+| proposal_id | aelf.Hash | Proposal ID | |
+| address | aelf.Address | Sender address | |
+| receipt_type | string | Receipt type (Approve, Reject, Abstain) | |
+| time | google.protobuf.Timestamp | Timestamp | |
+| organization_address| aelf.Address | Organization address | |
+
+#### acs3.ValidateProposerInWhiteListInput
+| Field | Type | Description | Label |
+| ------------------- | ------------- | ------------------------ | ----- |
+| proposer | aelf.Address | Proposer address | |
+| organization_address| aelf.Address | Organization address | |
+
+## Implementation
+
+Assume there's only one organization in a contract, so no need to define the Organization type. Voters must use a token to vote. We'll focus on the core methods: CreateProposal, Approve, Reject, Abstain, and Release.
+
+### State Attributes
+```cs
+public MappedState Proposals { get; set; }
+public SingletonState ProposalReleaseThreshold { get; set; }
+```
+
+- `Proposals` stores all proposal info.
+- `ProposalReleaseThreshold` saves the requirements to release a proposal.
+
+### Initialization
+Set the proposal release requirements when the contract initializes:
+```cs
+public override Empty Initialize(Empty input)
+{
+ State.TokenContract.Value =
+ Context.GetContractAddressByName(SmartContractConstants.TokenContractSystemName);
+ State.ProposalReleaseThreshold.Value = new ProposalReleaseThreshold
+ {
+ MinimalApprovalThreshold = 1,
+ MinimalVoteThreshold = 1
+ };
+ return new Empty();
+}
+```
+
+Requires at least one vote and one approval.
+
+### Create Proposal
+Creates a proposal and stores it with its details.
+```cs
+public override Hash CreateProposal(CreateProposalInput input)
+{
+ var proposalId = Context.GenerateId(Context.Self, input.Token);
+ Assert(State.Proposals[proposalId] == null, "Proposal with same token already exists.");
+ State.Proposals[proposalId] = new ProposalInfo
+ {
+ ProposalId = proposalId,
+ Proposer = Context.Sender,
+ ContractMethodName = input.ContractMethodName,
+ Params = input.Params,
+ ExpiredTime = input.ExpiredTime,
+ ToAddress = input.ToAddress,
+ ProposalDescriptionUrl = input.ProposalDescriptionUrl
+ };
+ return proposalId;
+}
+```
+
+### Voting Methods
+
+#### Abstain
+```cs
+public override Empty Abstain(Hash input)
+{
+ Charge();
+ var proposal = State.Proposals[input];
+ if (proposal == null)
+ {
+ throw new AssertionException("Proposal not found.");
+ }
+ proposal.Abstentions.Add(Context.Sender);
+ State.Proposals[input] = proposal;
+ return new Empty();
+}
+```
+
+#### Approve
+```cs
+public override Empty Approve(Hash input)
+{
+ Charge();
+ var proposal = State.Proposals[input];
+ if (proposal == null)
+ {
+ throw new AssertionException("Proposal not found.");
+ }
+ proposal.Approvals.Add(Context.Sender);
+ State.Proposals[input] = proposal;
+ return new Empty();
+}
+```
+
+#### Reject
+```cs
+public override Empty Reject(Hash input)
+{
+ Charge();
+ var proposal = State.Proposals[input];
+ if (proposal == null)
+ {
+ throw new AssertionException("Proposal not found.");
+ }
+ proposal.Rejections.Add(Context.Sender);
+ State.Proposals[input] = proposal;
+ return new Empty();
+}
+```
+
+#### Charge
+```cs
+private void Charge()
+{
+ State.TokenContract.TransferFrom.Send(new TransferFromInput
+ {
+ From = Context.Sender,
+ To = Context.Self,
+ Symbol = Context.Variables.NativeSymbol,
+ Amount = 1_00000000
+ });
+}
+```
+
+### Release Proposal
+Releases a proposal if the vote count meets the threshold:
+```cs
+public override Empty Release(Hash input)
+{
+ var proposal = State.Proposals[input];
+ if (proposal == null)
+ {
+ throw new AssertionException("Proposal not found.");
+ }
+ Assert(IsReleaseThresholdReached(proposal), "Didn't reach release threshold.");
+ Context.SendInline(proposal.ToAddress, proposal.ContractMethodName, proposal.Params);
+ return new Empty();
+}
+private bool IsReleaseThresholdReached(ProposalInfo proposal)
+{
+ var isRejected = IsProposalRejected(proposal);
+ if (isRejected)
+ return false;
+ var isAbstained = IsProposalAbstained(proposal);
+ return !isAbstained && CheckEnoughVoteAndApprovals(proposal);
+}
+private bool IsProposalRejected(ProposalInfo proposal)
+{
+ var rejectionMemberCount = proposal.Rejections.Count;
+ return rejectionMemberCount > State.ProposalReleaseThreshold.Value.MaximalRejectionThreshold;
+}
+private bool IsProposalAbstained(ProposalInfo proposal)
+{
+ var abstentionMemberCount = proposal.Abstentions.Count;
+ return abstentionMemberCount > State.ProposalReleaseThreshold.Value.MaximalAbstentionThreshold;
+}
+private bool CheckEnoughVoteAndApprovals(ProposalInfo proposal)
+{
+ var approvedMemberCount = proposal.Approvals.Count;
+ var isApprovalEnough =
+ approvedMemberCount >= State.ProposalReleaseThreshold.Value.MinimalApprovalThreshold;
+ if (!isApprovalEnough)
+ return false;
+ var isVoteThresholdReached =
+ proposal.Abstentions.Concat(proposal.Approvals).Concat(proposal.Rejections).Count() >=
+ State.ProposalReleaseThreshold.Value.MinimalVoteThreshold;
+ return isVoteThresholdReached;
+}
+```
+
+## Test
+Add methods to a Dapp contract and test the proposal with these methods.
+
+### State Class
+```cs
+public StringState Slogan { get; set; }
+public SingletonState Organization { get; set; }
+```
+
+#### Set/Get Methods
+```cs
+public override StringValue GetSlogan(Empty input)
+{
+ return State.Slogan.Value == null ? new StringValue() : new StringValue {Value = State.Slogan.Value};
+}
+
+public override Empty SetSlogan(StringValue input)
+{
+ Assert(Context.Sender == State.Organization.Value, "No permission.");
+ State.Slogan.Value = input.Value;
+ return new Empty();
+}
+```
+
+#### Prepare a Stub
+```cs
+var keyPair = SampleECKeyPairs.KeyPairs[0];
+var acs3DemoContractStub =
+ GetTester(DAppContractAddress, keyPair);
+```
+
+#### Approve Token Transaction
+```cs
+var tokenContractStub =
+ GetTester(
+ GetAddress(TokenSmartContractAddressNameProvider.StringName), keyPair);
+await tokenContractStub.Approve.SendAsync(new ApproveInput
+{
+ Spender = DAppContractAddress,
+ Symbol = "ELF",
+ Amount = long.MaxValue
+});
+```
+
+#### Create and Test Proposal
+Create a proposal to change the Slogan to "AElf":
+```cs
+var proposalId = (await acs3DemoContractStub.CreateProposal.SendAsync(new CreateProposalInput
+{
+ OrganizationAddress = OrganizationAddress
+ ContractMethodName = nameof(acs3DemoContractStub.SetSlogan),
+ ToAddress = DAppContractAddress,
+ ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1),
+ Params = new StringValue {Value = "AElf"}.ToByteString(),
+ Token = HashHelper.ComputeFrom("AElf")
+})).Output;
+```
+
+#### Check that Slogan is empty, vote, and release:
+```cs
+// Check slogan
+{
+ var slogan = await acs3DemoContractStub.GetSlogan.CallAsync(new Empty());
+ slogan.Value.ShouldBeEmpty();
+}
+await acs3DemoContractStub.Approve.SendAsync(proposalId);
+```
+```cs
+await acs3DemoContractStub.Release.SendAsync(proposalId);
+// Check slogan
+{
+ var slogan = await acs3DemoContractStub.GetSlogan.CallAsync(new Empty());
+ slogan.Value.ShouldBe("AElf");
+}
+```
diff --git a/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md b/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md
new file mode 100644
index 0000000..806f0d0
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md
@@ -0,0 +1,175 @@
+# ACS4 - Consensus Standard
+ACS4 customizes consensus mechanisms.
+
+## Interface
+To customize, implement these five interfaces:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|--------------------------------|-------------------------------|-----------------------------|------------------------------------------------------------------------------------------------|
+| GetConsensusCommand | google.protobuf.BytesValue | acs4.ConsensusCommand | Generate a consensus command based on contract state and the input public key. |
+| GetConsensusExtraData | google.protobuf.BytesValue | google.protobuf.BytesValue | Generate extra data when a block is generated. |
+| GenerateConsensusTransactions | google.protobuf.BytesValue | acs4.TransactionList | Generate system transactions when a block is generated. Each block has one consensus transaction. |
+| ValidateConsensusBeforeExecution | google.protobuf.BytesValue | acs4.ValidationResult | Verify consensus info in the block header before execution. |
+| ValidateConsensusAfterExecution | google.protobuf.BytesValue | acs4.ValidationResult | Verify the state info written to consensus after execution. |
+
+## Types
+
+### acs4.ConsensusCommand
+| Field | Type | Description |
+|-------------------------------|--------------------------|------------------------------------------------------------------|
+| limit_milliseconds_of_mining_block | int32 | Time limit for mining the next block. |
+| hint | bytes | Diverse context according to the consensus protocol. |
+| arranged_mining_time | google.protobuf.Timestamp | The arranged mining time. |
+| mining_due_time | google.protobuf.Timestamp | The expiration time for mining. |
+
+### acs4.TransactionList
+| Field | Type | Description |
+|--------------|----------------|-----------------------------|
+| transactions | aelf.Transaction | Consensus system transactions. |
+
+### acs4.ValidationResult
+| Field | Type | Description |
+|--------------|--------|------------------------|
+| success | bool | Is successful. |
+| message | string | Error message. |
+| is_re_trigger| bool | Whether to re-trigger mining. |
+
+### aelf.Address
+| Field | Type | Description |
+|-------|-------|-------------|
+| value | bytes | |
+
+### aelf.BinaryMerkleTree
+| Field | Type | Description |
+|------------|-------|-------------------|
+| nodes | Hash | Leaf nodes. |
+| root | Hash | Root node hash. |
+| leaf_count | int32 | Leaf node count. |
+
+### aelf.Hash
+| Field | Type | Description |
+|-------|-------|-------------|
+| value | bytes | |
+
+### aelf.LogEvent
+| Field | Type | Description |
+|--------------|---------|--------------------------|
+| address | Address | Contract address. |
+| name | string | Name of the log event. |
+| indexed | bytes | Indexed data for bloom. |
+| non_indexed | bytes | Non-indexed data. |
+
+### aelf.MerklePath
+| Field | Type | Description |
+|--------------------|------------------|---------------------|
+| merkle_path_nodes | MerklePathNode | Merkle path nodes. |
+
+### aelf.MerklePathNode
+| Field | Type | Description |
+|--------------------|-------|--------------------------|
+| hash | Hash | Node hash. |
+| is_left_child_node | bool | Is it a left child node? |
+
+### aelf.SInt32Value
+| Field | Type | Description |
+|-------|-------|-------------|
+| value | sint32 | |
+
+### aelf.SInt64Value
+| Field | Type | Description |
+|-------|-------|-------------|
+| value | sint64 | |
+
+### aelf.ScopedStatePath
+| Field | Type | Description |
+|---------|---------|----------------------------------|
+| address | Address | Scope address (contract address) |
+| path | StatePath | Path of contract state |
+
+### aelf.SmartContractRegistration
+| Field | Type | Description |
+|------------------|-------|-----------------------------------|
+| category | sint32| Contract code category (0: C#). |
+| code | bytes | Byte array of the contract code. |
+| code_hash | Hash | Hash of the contract code. |
+| is_system_contract | bool | Is it a system contract? |
+| version | int32 | Current contract version. |
+
+### aelf.StatePath
+| Field | Type | Description |
+|-------|--------|----------------------|
+| parts | string | Partial state path. |
+
+### aelf.Transaction
+| Field | Type | Description |
+|-------------------|----------|----------------------------------------------------------------|
+| from | Address | Sender's address. |
+| to | Address | Contract address being called. |
+| ref_block_number | int64 | Referenced block number. |
+| ref_block_prefix | bytes | First four bytes of the referenced block hash. |
+| method_name | string | Method name in the smart contract. |
+| params | bytes | Parameters for the smart contract method. |
+| signature | bytes | Signature including sender, target method, parameters, and block reference. |
+
+### aelf.TransactionExecutingStateSet
+| Field | Type | Description |
+|---------|------------------------------------|-----------------|
+| writes | TransactionExecutingStateSet.WritesEntry | Changed states. |
+| reads | TransactionExecutingStateSet.ReadsEntry | Read states. |
+| deletes | TransactionExecutingStateSet.DeletesEntry | Deleted states. |
+
+### aelf.TransactionExecutingStateSet.DeletesEntry
+| Field | Type | Description |
+|-------|-------|-------------|
+| key | string| |
+| value | bool | |
+
+### aelf.TransactionExecutingStateSet.ReadsEntry
+| Field | Type | Description |
+|-------|-------|-------------|
+| key | string| |
+| value | bool | |
+
+### aelf.TransactionExecutingStateSet.WritesEntry
+| Field | Type | Description |
+|-------|-------|-------------|
+| key | string| |
+| value | bytes | |
+
+### aelf.TransactionResult
+| Field | Type | Description |
+|----------------|-------------------------|---------------------------------------------------------------------------|
+| transaction_id | Hash | Transaction ID. |
+| status | TransactionResultStatus | Transaction result status. |
+| logs | LogEvent | Log events. |
+| bloom | bytes | Bloom filter for transaction logs. |
+| return_value | bytes | Return value of the transaction execution. |
+| block_number | int64 | Block height that packages the transaction. |
+| block_hash | Hash | Block hash that packages the transaction. |
+| error | string | Failed execution error message. |
+
+### aelf.TransactionResultStatus
+| Name | Number | Description |
+|----------------------|--------|-------------------------------------------------------------------|
+| NOT_EXISTED | 0 | Transaction result does not exist. |
+| PENDING | 1 | Transaction is in the pool waiting to be packaged. |
+| FAILED | 2 | Transaction execution failed. |
+| MINED | 3 | Transaction executed successfully and packaged into a block. |
+| CONFLICT | 4 | Conflicts with other transactions when executed in parallel. |
+| PENDING_VALIDATION | 5 | Transaction is waiting for validation. |
+| NODE_VALIDATION_FAILED | 6 | Transaction validation failed. |
+
+## Usage
+ACS4 methods correspond to the IConsensusService interface in the AElf.Kernel.Consensus project:
+
+| ACS4 Method | IConsensusService Method | Methodology | Timing |
+|------------------------------------|-----------------------------------|--------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| GetConsensusCommand | Task TriggerConsensusAsync | When TriggerConsensusAsync is called, it will use the node's configured account to call the GetConsensusCommand method to obtain block information (ConsensusCommand) | When the node starts; When the BestChainFoundEventData event is thrown; When consensus data validation fails and needs to be triggered again (IsReTrigger field is true). |
+| GetConsensusExtraData | Task GetConsensusExtraDataAsync | When a node produces a block, it generates block header info via IBlockExtraDataService, which calls GetConsensusExtraData in the consensus contract | When a node produces a new block. |
+| GenerateConsensusTransactions | Task> GenerateConsensusTransactionsAsync | In the process of generating new blocks, a consensus transaction needs to be generated as one of the system transactions | When a node produces a new block. |
+| ValidateConsensusBeforeExecution | Task ValidateConsensusBeforeExecutionAsync | The IBlockValidationProvider interface allows adding a new block validator. The consensus validator, ConsensusValidationProvider, calls ValidateConsensusBeforeExecution | When a node produces a new block. |
+| ValidateConsensusAfterExecution | Task ValidateConsensusAfterExecutionAsync | The implementation of ValidateBlockAfterExecuteAsync in ConsensusValidationProvider calls ValidateConsensusAfterExecution in the consensus contract | When a node produces a new block. |
+
+### Example
+Refer to the AEDPoS contract implementation.
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md b/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md
new file mode 100644
index 0000000..40abe0f
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md
@@ -0,0 +1,192 @@
+# ACS5 - Contract Threshold Standard
+To raise the threshold for using a contract, consider implementing ACS5.
+
+## Interface
+To limit calling a method in a contract, implement these interfaces:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|----------------------------|---------------------------------------|-------------------------------|-----------------------------------|
+| SetMethodCallingThreshold | acs5.SetMethodCallingThresholdInput | google.protobuf.Empty | Set the threshold for method calling. |
+| GetMethodCallingThreshold | google.protobuf.StringValue | acs5.MethodCallingThreshold | Get the threshold for method calling. |
+
+### Types
+
+#### acs5.MethodCallingThreshold
+| Field | Type | Description | Label |
+|-----------------------|-----------------------------------------|-----------------------------------|------------|
+| symbol_to_amount | MethodCallingThreshold.SymbolToAmountEntry | The threshold for method calling, token symbol -> amount. | repeated |
+| threshold_check_type | ThresholdCheckType | The type of threshold check. | |
+
+#### acs5.MethodCallingThreshold.SymbolToAmountEntry
+| Field | Type | Description | Label |
+|-------|--------|-------------|-------|
+| key | string | | |
+| value | int64 | | |
+
+#### acs5.SetMethodCallingThresholdInput
+| Field | Type | Description | Label |
+|----------------------|---------------------------------------------|-------------|-------|
+| method | string | The method name to check. | |
+| symbol_to_amount | SetMethodCallingThresholdInput.SymbolToAmountEntry | The threshold for method calling, token symbol -> amount. | repeated |
+| threshold_check_type | ThresholdCheckType | The type of threshold check. | |
+
+#### acs5.SetMethodCallingThresholdInput.SymbolToAmountEntry
+| Field | Type | Description | Label |
+|-------|--------|-------------|-------|
+| key | string | | |
+| value | int64 | | |
+
+#### acs5.ThresholdCheckType
+| Name | Number | Description |
+|----------|--------|--------------------------------------|
+| BALANCE | 0 | Check balance only. |
+| ALLOWANCE| 1 | Check balance and allowance at the same time. |
+
+## Usage
+ACS5 works similarly to ACS1, which uses a pre-plugin transaction called `ChargeTransactionFees` to charge a transaction fee. ACS5 uses a pre-plugin transaction called `CheckThreshold` to ensure the account sending the transaction can invoke the method.
+
+### Implementation of `CheckThreshold`:
+
+```cs
+public override Empty CheckThreshold(CheckThresholdInput input)
+{
+ var meetThreshold = false;
+ var meetBalanceSymbolList = new List();
+ foreach (var symbolToThreshold in input.SymbolToThreshold)
+ {
+ if (GetBalance(input.Sender, symbolToThreshold.Key) < symbolToThreshold.Value)
+ continue;
+ meetBalanceSymbolList.Add(symbolToThreshold.Key);
+ }
+ if (meetBalanceSymbolList.Count > 0)
+ {
+ if (input.IsCheckAllowance)
+ {
+ foreach (var symbol in meetBalanceSymbolList)
+ {
+ if (State.Allowances[input.Sender][Context.Sender][symbol] <
+ input.SymbolToThreshold[symbol]) continue;
+ meetThreshold = true;
+ break;
+ }
+ }
+ else
+ {
+ meetThreshold = true;
+ }
+ }
+ if (input.SymbolToThreshold.Count == 0)
+ {
+ meetThreshold = true;
+ }
+ Assert(meetThreshold, "Cannot meet the calling threshold.");
+ return new Empty();
+}
+```
+
+If the sender's token balance or the authorized amount for the target contract doesn't meet the set limit, the pre-plugin transaction throws an exception and prevents the original transaction from executing.
+
+## Implementation
+Implement a single `GetMethodCallingThreshold` method like `GetMethodFee` in ACS1. Use `MappedState` in the State class:
+```cs
+public MappedState MethodCallingThresholds { get; set; }
+```
+
+Configure the call permission of SetMethodCallingThreshold, requiring an Admin in the State:
+```cs
+public SingletonState Admin { get; set; }
+```
+```cs
+public override Empty SetMethodCallingThreshold(SetMethodCallingThresholdInput input)
+{
+ Assert(State.Admin.Value == Context.Sender, "No permission.");
+ State.MethodCallingThresholds[input.Method] = new MethodCallingThreshold
+ {
+ SymbolToAmount = {input.SymbolToAmount}
+ };
+ return new Empty();
+}
+
+public override MethodCallingThreshold GetMethodCallingThreshold(StringValue input)
+{
+ return State.MethodCallingThresholds[input.Value];
+}
+
+public override Empty Foo(Empty input)
+{
+ return new Empty();
+}
+
+message SetMethodCallingThresholdInput {
+ string method = 1;
+ map symbol_to_amount = 2;// The order matters.
+ ThresholdCheckType threshold_check_type = 3;
+}
+```
+
+## Test
+Test the Foo method:
+
+1. Make a Stub
+```cs
+var keyPair = SampleECKeyPairs.KeyPairs[0];
+var acs5DemoContractStub =
+ GetTester(DAppContractAddress, keyPair);
+```
+
+2. Check the current threshold (should be 0):
+```cs
+var methodResult = await acs5DemoContractStub.GetMethodCallingThreshold.CallAsync(
+ new StringValue
+ {
+ Value = nameof(acs5DemoContractStub.Foo)
+ });
+methodResult.SymbolToAmount.Count.ShouldBe(0);
+```
+
+3. Ensure the caller's ELF balance is greater than 1 ELF:
+```cs
+await acs5DemoContractStub.SetMethodCallingThreshold.SendAsync(
+ new SetMethodCallingThresholdInput
+ {
+ Method = nameof(acs5DemoContractStub.Foo),
+ SymbolToAmount =
+ {
+ {"ELF", 1_0000_0000}
+ },
+ ThresholdCheckType = ThresholdCheckType.Balance
+ });
+```
+
+4. Check the threshold again:
+```cs
+methodResult = await acs5DemoContractStub.GetMethodCallingThreshold.CallAsync(
+ new StringValue
+ {
+ Value = nameof(acs5DemoContractStub.Foo)
+ });
+methodResult.SymbolToAmount.Count.ShouldBe(1);
+methodResult.ThresholdCheckType.ShouldBe(ThresholdCheckType.Balance);
+```
+
+5. Send the Foo transaction with an account that has enough balance:
+```cs
+// Call with enough balance.
+{
+ var executionResult = await acs5DemoContractStub.Foo.SendAsync(new Empty());
+ executionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+}
+```
+
+6. Send the Foo transaction with an account without ELF:
+```cs
+// Call without enough balance.
+{
+ var poorStub =
+ GetTester(DAppContractAddress,
+ SampleECKeyPairs.KeyPairs[1]);
+ var executionResult = await poorStub.Foo.SendWithExceptionAsync(new Empty());
+ executionResult.TransactionResult.Error.ShouldContain("Cannot meet the calling threshold.");
+}
+```
diff --git a/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md b/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md
new file mode 100644
index 0000000..54d7f4b
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md
@@ -0,0 +1,34 @@
+# ACS6 - Random Number Provider Standard
+To generate a random number in your contract, use ACS6.
+
+## Interface
+To provide a random number based on input, implement this interface:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|-----------------|----------------------------|----------------------------|-------------------------------------------|
+| GetRandomBytes | google.protobuf.BytesValue | google.protobuf.BytesValue | Get the random number provided by the contract. |
+
+## Usage
+Override the `GetRandomBytes` method to return a random number based on the given input. The logic for generating the random number is up to you. Ensure you return a `BytesValue` type so the caller can deserialize the output.
+
+## Implementation
+The simplest implementation:
+
+```cs
+public override BytesValue GetRandomBytes(BytesValue input)
+{
+ var serializedInput = new GetRandomBytesInput();
+ serializedInput.MergeFrom(input.Value);
+ var value = new Hash();
+ value.MergeFrom(serializedInput.Value);
+ var randomHashFromContext = Context.GetRandomHash(value);
+
+ return new BytesValue
+ {
+ Value = serializedInput.Kind == 1
+ ? new BytesValue {Value = randomHashFromContext.Value}.ToByteString()
+ : new Int64Value {Value = Context.ConvertHashToInt64(randomHashFromContext, 1, 10000)}.ToByteString()
+ };
+}
+```
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md b/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md
new file mode 100644
index 0000000..03f669f
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md
@@ -0,0 +1,95 @@
+# ACS7 - Contract CrossChain Standard
+
+ACS7 is for implementing cross-chain contracts.
+
+## Interface
+
+This involves methods for chain creation and indexing:
+
+### Methods
+
+| Method Name | Request Type | Response Type | Description |
+|-------------------------------------|---------------------------------------------|--------------------------------|---------------------------------------------------------------------|
+| ProposeCrossChainIndexing | acs7.CrossChainBlockData | google.protobuf.Empty | Propose a cross-chain indexing. |
+| ReleaseCrossChainIndexingProposal | acs7.ReleaseCrossChainIndexingProposalInput | google.protobuf.Empty | Release the proposed indexing if approved. |
+| RequestSideChainCreation | acs7.SideChainCreationRequest | google.protobuf.Empty | Request side chain creation. |
+| ReleaseSideChainCreation | acs7.ReleaseSideChainCreationInput | google.protobuf.Empty | Release the side chain creation request if approved. |
+| CreateSideChain | acs7.CreateSideChainInput | google.protobuf.Int32Value | Create the side chain and return its ID. Only authorized users. |
+| Recharge | acs7.RechargeInput | google.protobuf.Empty | Recharge a specified side chain. |
+| DisposeSideChain | google.protobuf.Int32Value | google.protobuf.Int32Value | Dispose a side chain by ID. Only authorized users. |
+| AdjustIndexingFeePrice | acs7.AdjustIndexingFeeInput | google.protobuf.Empty | Adjust side chain indexing fee. Only authorized users. |
+| VerifyTransaction | acs7.VerifyTransactionInput | google.protobuf.BoolValue | Verify a cross-chain transaction. |
+| GetSideChainIdAndHeight | google.protobuf.Empty | acs7.ChainIdAndHeightDict | Get all side chain IDs and heights. |
+| GetSideChainIndexingInformationList | google.protobuf.Empty | acs7.SideChainIndexingInformationList | Get indexing information of side chains. |
+| GetAllChainsIdAndHeight | google.protobuf.Empty | acs7.ChainIdAndHeightDict | Get IDs and heights of all chains. |
+| GetIndexedSideChainBlockDataByHeight| google.protobuf.Int64Value | acs7.IndexedSideChainBlockData | Get block data of indexed side chain by height. |
+| GetBoundParentChainHeightAndMerklePathByHeight | google.protobuf.Int64Value | acs7.CrossChainMerkleProofContext | Get Merkle path bound to side chain by height. |
+| GetChainInitializationData | google.protobuf.Int32Value | acs7.ChainInitializationData | Get initialization data for a specified side chain. |
+
+### Types
+
+#### acs7.AdjustIndexingFeeInput
+| Field | Description | Label |
+|--------------------|-------------------------|----------|
+| `side_chain_id` (int32) | The side chain ID | |
+| `indexing_fee` (int64) | The new indexing fee | |
+
+#### acs7.ChainIdAndHeightDict
+| Field | Description | Label |
+|--------------------------|-------------------------|-----------|
+| `id_height_dict` (map) | Chain IDs and heights | repeated |
+
+#### acs7.ChainInitializationData
+| Field | Description | Label |
+|----------------------------------------|------------------------------------|---------|
+| `chain_id` (int32) | Side chain ID | |
+| `creator` (aelf.Address) | Creator's address | |
+| `creation_timestamp` (google.protobuf.Timestamp) | Creation timestamp | |
+| `creation_height_on_parent_chain` (int64) | Height on parent chain | |
+| `chain_creator_privilege_preserved` (bool) | If privilege is preserved | |
+| `parent_chain_token_contract_address` (aelf.Address) | Token contract address | |
+| `chain_initialization_consensus_info` (ChainInitializationConsensusInfo) | Initial consensus info | |
+| `native_token_info_data` (bytes) | Native token info | |
+| `resource_token_info` (ResourceTokenInfo) | Resource token info | |
+| `chain_primary_token_info` (ChainPrimaryTokenInfo) | Primary token info | |
+
+#### acs7.CreateSideChainInput
+| Field | Description | Label |
+|------------------------------------|---------------------------------|----------|
+| `side_chain_creation_request` (SideChainCreationRequest) | Creation request info | |
+| `proposer` (aelf.Address) | Proposer's address | |
+
+#### acs7.CrossChainBlockData
+| Field | Description | Label |
+|-------------------------------------|---------------------------------|-----------|
+| `side_chain_block_data_list` (repeated SideChainBlockData) | List of side chain block data | repeated |
+| `parent_chain_block_data_list` (repeated ParentChainBlockData) | List of parent chain block data | repeated |
+
+#### acs7.RechargeInput
+| Field | Description | Label |
+|--------------------|-------------------------|----------|
+| `chain_id` (int32) | Side chain ID | |
+| `amount` (int64) | Amount to recharge | |
+
+#### acs7.ReleaseCrossChainIndexingProposalInput
+| Field | Description | Label |
+|----------------------------|-----------------------------|-----------|
+| `chain_id_list` (repeated int32) | List of chain IDs to release | repeated |
+
+#### acs7.ReleaseSideChainCreationInput
+| Field | Description | Label |
+|--------------------|-------------------------|----------|
+| `proposal_id` (aelf.Hash) | Proposal ID | |
+
+#### acs7.SideChainCreationRequest
+| Field | Description | Label |
+|------------------------------------------|------------------------------------|-----------|
+| `indexing_price` (int64) | Cross-chain indexing price | |
+| `locked_token_amount` (int64) | Initial locked balance | |
+| `is_privilege_preserved` (bool) | If privilege is preserved | |
+| `side_chain_token_creation_request` (SideChainTokenCreationRequest) | Token creation request | |
+| `side_chain_token_initial_issue_list` (repeated SideChainTokenInitialIssue) | Initial token issues list | repeated |
+| `initial_resource_amount` (repeated SideChainCreationRequest.InitialResourceAmountEntry) | Initial resource amounts | repeated |
+
+### Example
+ACS7 defines methods for cross-chain scenarios. AElf provides an implementation for ACS7 called `CrossChainContract`. Refer to this implementation for more details.
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md b/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md
new file mode 100644
index 0000000..ff99d54
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md
@@ -0,0 +1,74 @@
+# ACS8 - Transaction Resource Token Fee Standard
+ACS8 is a transaction fee standard similar to ACS1, but it charges the called contract rather than the user. The fee charged includes four specified tokens: WRITE, READ, NET, and TRAFFIC.
+
+When a contract inherits from ACS8, each transaction within this contract incurs charges in these four resource tokens.
+
+## Interface
+The acs8.proto file defines the following method:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|-------------------|-----------------------------|-------------------|--------------------------------------------------|
+| BuyResourceToken | acs8.BuyResourceTokenInput | google.protobuf.Empty | Buys one of the four resource tokens. Consumes ELF balance in the contract account. |
+
+### Types
+
+#### acs8.BuyResourceTokenInput
+| Field | Type | Description | Label |
+|------------|--------|-----------------------------------------------|-----------|
+| symbol | string | The symbol of the token to buy. | |
+| amount | int64 | The amount of token to buy. | |
+| pay_limit | int64 | Limit of cost; buying is abandoned if exceeded. 0 means no limit. | |
+
+## Usage
+Contracts inheriting ACS1 use a pre-plugin transaction called ChargeTransactionFees for transaction fee charging. ACS8 introduces a similar post-plugin transaction called ChargeResourceToken, which charges resource tokens based on actual transaction consumption.
+
+The ChargeResourceToken implementation involves calculating token amounts using polynomial coefficients stored in CalculateFeeCoefficients defined in token_contract.proto. Each resource token has a polynomial for fee calculation, which determines the cost based on transaction consumption.
+```cs
+public override Empty ChargeResourceToken(ChargeResourceTokenInput input)
+{
+ Context.LogDebug(() => string.Format("Start executing ChargeResourceToken.{0}", input));
+ if (input.Equals(new ChargeResourceTokenInput()))
+ {
+ return new Empty();
+ }
+ var bill = new TransactionFeeBill();
+ foreach (var pair in input.CostDic)
+ {
+ Context.LogDebug(() => string.Format("Charging {0} {1} tokens.", pair.Value, pair.Key));
+ var existingBalance = GetBalance(Context.Sender, pair.Key);
+ Assert(existingBalance >= pair.Value,
+ string.Format("Insufficient resource of {0}. Need balance: {1}; Current balance: {2}.", pair.Key, pair.Value, existingBalance));
+ bill.FeesMap.Add(pair.Key, pair.Value);
+ }
+ foreach (var pair in bill.FeesMap)
+ {
+ Context.Fire(new ResourceTokenCharged
+ {
+ Symbol = pair.Key,
+ Amount = pair.Value,
+ ContractAddress = Context.Sender
+ });
+ if (pair.Value == 0)
+ {
+ Context.LogDebug(() => string.Format("Maybe incorrect charged resource fee of {0}: it's 0.", pair.Key));
+ }
+ }
+ return new Empty();
+}
+```
+
+Additionally, contracts cannot execute methods if they lack sufficient resource token balance. To enforce this, a pre-plugin transaction CheckResourceToken, similar to ACS5, verifies the contract's resource token balance before method execution.
+```cs
+public override Empty CheckResourceToken(Empty input)
+{
+ foreach (var symbol in Context.Variables.GetStringArray(TokenContractConstants.PayTxFeeSymbolListName))
+ {
+ var balance = GetBalance(Context.Sender, symbol);
+ var owningBalance = State.OwningResourceToken[Context.Sender][symbol];
+ Assert(balance > owningBalance,
+ string.Format("Contract balance of {0} token is not enough. Owning {1}.", symbol, owningBalance));
+ }
+ return new Empty();
+}
+```
\ No newline at end of file
diff --git a/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md b/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md
new file mode 100644
index 0000000..08293b0
--- /dev/null
+++ b/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md
@@ -0,0 +1,483 @@
+# ACS9 - Contract Profit Dividend Standard
+ACS9 defines a standard for distributing profits on AElf's side chain contracts.
+
+## Interface
+ACS9 includes several methods given below:
+
+### Methods
+| Method Name | Request Type | Response Type | Description |
+|----------------------|-------------------------------|----------------------------|---------------------------------------------|
+| TakeContractProfits | acs9.TakeContractProfitsInput | google.protobuf.Empty | Allows developers to collect contract profits. |
+| GetProfitConfig | google.protobuf.Empty | acs9.ProfitConfig | Retrieves profit distribution configuration. |
+| GetProfitsAmount | google.protobuf.Empty | acs9.ProfitsMap | Queries total profits accumulated by the contract. |
+
+### Types
+
+#### acs9.ProfitConfig
+| Field | Type | Description | Label |
+|--------------------------------|----------|-----------------------------------------------|------------|
+| donation_parts_per_hundred | int32 | Percentage of profit donated to dividend pool. | |
+| profits_token_symbol_list | string | List of profit token symbols. | repeated |
+| staking_token_symbol | string | Token symbol users can lock to claim profits. | |
+
+#### acs9.ProfitsMap
+| Field | Type | Description | Label |
+|---------------|------------------------------------|------------------------------------------|-----------|
+| value | map | Profits accumulated, symbol -> amount. | repeated |
+
+#### acs9.TakeContractProfitsInput
+| Field | Type | Description | Label |
+|---------------|--------|-----------------------------------|-----------|
+| symbol | string | Token symbol to withdraw profits. | |
+| amount | int64 | Amount of token to withdraw. | |
+
+## Implementation
+The contract initializes by creating a token called APP and establishing a profit distribution scheme using the TokenHolder contract. Users receive 10 APP tokens upon signing up and can deposit ELF to receive APP tokens. The Use method consumes APP tokens.
+
+Upon initialization, ACS9 sets the profit configuration and enables profit distribution to the profit receiver and dividend pool.
+
+The contract allows users to interact by signing up, depositing and withdrawing tokens, and using APP tokens for transactions. Developers can configure profit distribution settings and monitor accumulated profits.
+
+1. Implementation of Initialize
+```cs
+public override Empty Initialize(InitializeInput input)
+{
+ State.TokenHolderContract.Value =
+ Context.GetContractAddressByName(SmartContractConstants.TokenHolderContractSystemName);
+ State.TokenContract.Value =
+ Context.GetContractAddressByName(SmartContractConstants.TokenContractSystemName);
+ State.DividendPoolContract.Value =
+ Context.GetContractAddressByName(input.DividendPoolContractName.Value.ToBase64());
+ State.Symbol.Value = input.Symbol == string.Empty ? "APP" : input.Symbol;
+ State.ProfitReceiver.Value = input.ProfitReceiver;
+ CreateToken(input.ProfitReceiver);
+ // To test TokenHolder Contract.
+ CreateTokenHolderProfitScheme();
+ // To test ACS9 workflow.
+ SetProfitConfig();
+ State.ProfitReceiver.Value = input.ProfitReceiver;
+ return new Empty();
+}
+private void CreateToken(Address profitReceiver, bool isLockWhiteListIncludingSelf = false)
+{
+ var lockWhiteList = new List
+ {Context.GetContractAddressByName(SmartContractConstants.TokenHolderContractSystemName)};
+ if (isLockWhiteListIncludingSelf)
+ lockWhiteList.Add(Context.Self);
+ State.TokenContract.Create.Send(new CreateInput
+ {
+ Symbol = State.Symbol.Value,
+ TokenName = "DApp Token",
+ Decimals = ACS9DemoContractConstants.Decimal,
+ Issuer = Context.Self,
+ IsBurnable = true,
+ IsProfitable = true,
+ TotalSupply = ACS9DemoContractConstants.TotalSupply,
+ LockWhiteList =
+ {
+ lockWhiteList
+ }
+ });
+ State.TokenContract.Issue.Send(new IssueInput
+ {
+ To = profitReceiver,
+ Amount = ACS9DemoContractConstants.TotalSupply / 5,
+ Symbol = State.Symbol.Value,
+ Memo = "Issue token for profit receiver"
+ });
+}
+private void CreateTokenHolderProfitScheme()
+{
+ State.TokenHolderContract.CreateScheme.Send(new CreateTokenHolderProfitSchemeInput
+ {
+ Symbol = State.Symbol.Value
+ });
+}
+private void SetProfitConfig()
+{
+ State.ProfitConfig.Value = new ProfitConfig
+ {
+ DonationPartsPerHundred = 1,
+ StakingTokenSymbol = "APP",
+ ProfitsTokenSymbolList = {"ELF"}
+ };
+}
+```
+
+2. The user can use the SighUp method to register and get the bonus
+```cs
+///
+/// When user sign up, give him 10 APP tokens, then initialize his profile.
+///
+///
+///
+public override Empty SignUp(Empty input)
+{
+ Assert(State.Profiles[Context.Sender] == null, "Already registered.");
+ var profile = new Profile
+ {
+ UserAddress = Context.Sender
+ };
+ State.TokenContract.Issue.Send(new IssueInput
+ {
+ Symbol = State.Symbol.Value,
+ Amount = ACS9DemoContractConstants.ForNewUser,
+ To = Context.Sender
+ });
+ // Update profile.
+ profile.Records.Add(new Record
+ {
+ Type = RecordType.SignUp,
+ Timestamp = Context.CurrentBlockTime,
+ Description = string.Format("{0} +{1}",State.Symbol.Value, ACS9DemoContractConstants.ForNewUser)
+ });
+ State.Profiles[Context.Sender] = profile;
+ return new Empty();
+}
+```
+
+3. Recharge and redemption:
+```cs
+public override Empty Deposit(DepositInput input)
+{
+ // User Address -> DApp Contract.
+ State.TokenContract.TransferFrom.Send(new TransferFromInput
+ {
+ From = Context.Sender,
+ To = Context.Self,
+ Symbol = "ELF",
+ Amount = input.Amount
+ });
+ State.TokenContract.Issue.Send(new IssueInput
+ {
+ Symbol = State.Symbol.Value,
+ Amount = input.Amount,
+ To = Context.Sender
+ });
+ // Update profile.
+ var profile = State.Profiles[Context.Sender];
+ profile.Records.Add(new Record
+ {
+ Type = RecordType.Deposit,
+ Timestamp = Context.CurrentBlockTime,
+ Description = string.Format("{0} +{1}", State.Symbol.Value, input.Amount)
+ });
+ State.Profiles[Context.Sender] = profile;
+ return new Empty();
+}
+public override Empty Withdraw(WithdrawInput input)
+{
+ State.TokenContract.TransferFrom.Send(new TransferFromInput
+ {
+ From = Context.Sender,
+ To = Context.Self,
+ Symbol = State.Symbol.Value,
+ Amount = input.Amount
+ });
+ State.TokenContract.Transfer.Send(new TransferInput
+ {
+ To = Context.Sender,
+ Symbol = input.Symbol,
+ Amount = input.Amount
+ });
+ State.TokenHolderContract.RemoveBeneficiary.Send(new RemoveTokenHolderBeneficiaryInput
+ {
+ Beneficiary = Context.Sender,
+ Amount = input.Amount
+ });
+ // Update profile.
+ var profile = State.Profiles[Context.Sender];
+ profile.Records.Add(new Record
+ {
+ Type = RecordType.Withdraw,
+ Timestamp = Context.CurrentBlockTime,
+ Description = string.Format("{0} -{1}", State.Symbol.Value, input.Amount)
+ });
+ State.Profiles[Context.Sender] = profile;
+ return new Empty();
+}
+```
+
+4. Implementation of Use directly transfers 1/3 profits into the token holder dividend scheme:
+```cs
+public override Empty Use(Record input)
+{
+ State.TokenContract.TransferFrom.Send(new TransferFromInput
+ {
+ From = Context.Sender,
+ To = Context.Self,
+ Symbol = State.Symbol.Value,
+ Amount = ACS9DemoContractConstants.UseFee
+ });
+ if (input.Symbol == string.Empty)
+ input.Symbol = State.TokenContract.GetPrimaryTokenSymbol.Call(new Empty()).Value;
+ var contributeAmount = ACS9DemoContractConstants.UseFee.Div(3);
+ State.TokenContract.Approve.Send(new ApproveInput
+ {
+ Spender = State.TokenHolderContract.Value,
+ Symbol = input.Symbol,
+ Amount = contributeAmount
+ });
+ // Contribute 1/3 profits (ELF) to profit scheme.
+ State.TokenHolderContract.ContributeProfits.Send(new ContributeProfitsInput
+ {
+ SchemeManager = Context.Self,
+ Amount = contributeAmount,
+ Symbol = input.Symbol
+ });
+ // Update profile.
+ var profile = State.Profiles[Context.Sender];
+ profile.Records.Add(new Record
+ {
+ Type = RecordType.Withdraw,
+ Timestamp = Context.CurrentBlockTime,
+ Description = string.Format("{0} -{1}", State.Symbol.Value, ACS9DemoContractConstants.UseFee),
+ Symbol = input.Symbol
+ });
+ State.Profiles[Context.Sender] = profile;
+ return new Empty();
+}
+```
+5. Implement ACS9 for the perfect profit distribution:
+```cs
+public override Empty TakeContractProfits(TakeContractProfitsInput input)
+{
+ var config = State.ProfitConfig.Value;
+ // For Side Chain Dividends Pool.
+ var amountForSideChainDividendsPool = input.Amount.Mul(config.DonationPartsPerHundred).Div(100);
+ State.TokenContract.Approve.Send(new ApproveInput
+ {
+ Symbol = input.Symbol,
+ Amount = amountForSideChainDividendsPool,
+ Spender = State.DividendPoolContract.Value
+ });
+ State.DividendPoolContract.Donate.Send(new DonateInput
+ {
+ Symbol = input.Symbol,
+ Amount = amountForSideChainDividendsPool
+ });
+ // For receiver.
+ var amountForReceiver = input.Amount.Sub(amountForSideChainDividendsPool);
+ State.TokenContract.Transfer.Send(new TransferInput
+ {
+ To = State.ProfitReceiver.Value,
+ Amount = amountForReceiver,
+ Symbol = input.Symbol
+ });
+ // For Token Holder Profit Scheme. (To distribute.)
+ State.TokenHolderContract.DistributeProfits.Send(new DistributeProfitsInput
+ {
+ SchemeManager = Context.Self
+ });
+ return new Empty();
+}
+public override ProfitConfig GetProfitConfig(Empty input)
+{
+ return State.ProfitConfig.Value;
+}
+public override ProfitsMap GetProfitsAmount(Empty input)
+{
+ var profitsMap = new ProfitsMap();
+ foreach (var symbol in State.ProfitConfig.Value.ProfitsTokenSymbolList)
+ {
+ var balance = State.TokenContract.GetBalance.Call(new GetBalanceInput
+ {
+ Owner = Context.Self,
+ Symbol = symbol
+ }).Balance;
+ profitsMap.Value[symbol] = balance;
+ }
+ return profitsMap;
+}
+```
+
+## Test
+
+Testing involves deploying contracts implementing ACS9 or ACS10, initializing the ACS9 contract using IContractInitializationProvider, and verifying profit distribution among stakeholders.
+
+- Before the testing begins, the contract implementing ACS9 can be initialized by interface IContractInitializationProvider
+```cs
+public class ACS9DemoContractInitializationProvider : IContractInitializationProvider
+{
+ public List GetInitializeMethodList(byte[] contractCode)
+ {
+ return new List
+ {
+ new InitializeMethod
+ {
+ MethodName = nameof(ACS9DemoContract.Initialize),
+ Params = new InitializeInput
+ {
+ ProfitReceiver = Address.FromPublicKey(SampleECKeyPairs.KeyPairs.Skip(3).First().PublicKey),
+ DividendPoolContractName = ACS10DemoSmartContractNameProvider.Name
+ }.ToByteString()
+ }
+ };
+ }
+ public Hash SystemSmartContractName { get; } = ACS9DemoSmartContractNameProvider.Name;
+ public string ContractCodeName { get; } = "AElf.Contracts.ACS9DemoContract";
+}
+```
+
+- Prepare a user account:
+```cs
+protected List UserKeyPairs => SampleECKeyPairs.KeyPairs.Skip(2).Take(3).ToList();
+```
+
+- Prepare some Stubs:
+```cs
+var keyPair = UserKeyPairs[0];
+var address = Address.FromPublicKey(keyPair.PublicKey);
+// Prepare stubs.
+var acs9DemoContractStub = GetACS9DemoContractStub(keyPair);
+var acs10DemoContractStub = GetACS10DemoContractStub(keyPair);
+var userTokenStub =
+ GetTester(TokenContractAddress, UserKeyPairs[0]);
+var userTokenHolderStub =
+ GetTester(TokenHolderContractAddress,
+ UserKeyPairs[0]);
+```
+
+- Then, transfer ELF to the user (TokenContractStub is the Stub of the initial bp who has much ELF) :
+```cs
+// Transfer some ELFs to user.
+await TokenContractStub.Transfer.SendAsync(new TransferInput
+{
+ To = address,
+ Symbol = "ELF",
+ Amount = 1000_00000000
+});
+```
+
+- User have to call SignUp to check if they got 10 APP tokens:
+```cs
+await acs9DemoContractStub.SignUp.SendAsync(new Empty());
+// User has 10 APP tokens because of signing up.
+(await GetFirstUserBalance("APP")).ShouldBe(10_00000000);
+```
+
+- Test the recharge method of the contract itself:
+```cs
+var elfBalanceBefore = await GetFirstUserBalance("ELF");
+// User has to Approve an amount of ELF tokens before deposit to the DApp.
+await userTokenStub.Approve.SendAsync(new ApproveInput
+{
+ Amount = 1000_00000000,
+ Spender = ACS9DemoContractAddress,
+ Symbol = "ELF"
+});
+await acs9DemoContractStub.Deposit.SendAsync(new DepositInput
+{
+ Amount = 100_00000000
+});
+// Check the change of balance of ELF.
+var elfBalanceAfter = await GetFirstUserBalance("ELF");
+elfBalanceAfter.ShouldBe(elfBalanceBefore - 100_00000000);
+// Now user has 110 APP tokens.
+(await GetFirstUserBalance("APP")).ShouldBe(110_00000000);
+```
+
+- The user locks up 57 APP via the TokenHolder contract in order to obtain profits from the contract:
+```cs
+// User lock some APP tokens for getting profits. (APP -57)
+await userTokenHolderStub.RegisterForProfits.SendAsync(new RegisterForProfitsInput
+{
+ SchemeManager = ACS9DemoContractAddress,
+ Amount = 57_00000000
+});
+```
+
+- The Use method is invoked 10 times and 0.3 APP is consumed each time, and finally the user have 50 APP left:
+```cs
+await userTokenStub.Approve.SendAsync(new ApproveInput
+{
+ Amount = long.MaxValue,
+ Spender = ACS9DemoContractAddress,
+ Symbol = "APP"
+});
+// User uses 10 times of this DApp. (APP -3)
+for (var i = 0; i < 10; i++)
+{
+ await acs9DemoContractStub.Use.SendAsync(new Record());
+}
+// Now user has 50 APP tokens.
+(await GetFirstUserBalance("APP")).ShouldBe(50_00000000);
+```
+
+- Using the TakeContractProfits method, the developer attempts to withdraw 10 ELF as profits. The 10 ELF will be transferred to the developer in this method:
+```cs
+const long baseBalance = 0;
+{
+ var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = UserAddresses[1], Symbol = "ELF"
+ });
+ balance.Balance.ShouldBe(baseBalance);
+}
+// Profits receiver claim 10 ELF profits.
+await acs9DemoContractStub.TakeContractProfits.SendAsync(new TakeContractProfitsInput
+{
+ Symbol = "ELF",
+ Amount = 10_0000_0000
+});
+// Then profits receiver should have 9.9 ELF tokens.
+{
+ var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = UserAddresses[1], Symbol = "ELF"
+ });
+ balance.Balance.ShouldBe(baseBalance + 9_9000_0000);
+}
+```
+
+- Next check the profit distribution results. The dividend pool should be allocated 0.1 ELF:
+```cs
+// And Side Chain Dividends Pool should have 0.1 ELF tokens.
+{
+ var scheme = await TokenHolderContractStub.GetScheme.CallAsync(ACS10DemoContractAddress);
+ var virtualAddress = await ProfitContractStub.GetSchemeAddress.CallAsync(new SchemePeriod
+ {
+ SchemeId = scheme.SchemeId,
+ Period = 0
+ });
+ var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Owner = virtualAddress,
+ Symbol = "ELF"
+ });
+ balance.Balance.ShouldBe(1000_0000);
+}
+```
+
+- The user receives 1 ELF from the token holder dividend scheme:
+```cs
+// Help user to claim profits from token holder profit scheme.
+await TokenHolderContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput
+{
+ Beneficiary = UserAddresses[0],
+ SchemeManager = ACS9DemoContractAddress,
+});
+// Profits should be 1 ELF.
+(await GetFirstUserBalance("ELF")).ShouldBe(elfBalanceAfter + 1_0000_0000);
+```
+
+- Finally, let’s test the Withdraw method.
+```cs
+// Withdraw
+var beforeBalance =
+ await userTokenStub.GetBalance.CallAsync(new GetBalanceInput
+ {
+ Symbol = "APP",
+ Owner = UserAddresses[0]
+ });
+var withDrawResult = await userTokenHolderStub.Withdraw.SendAsync(ACS9DemoContractAddress);
+withDrawResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined);
+var resultBalance = await userTokenStub.GetBalance.CallAsync(new GetBalanceInput
+{
+ Symbol = "APP",
+ Owner = UserAddresses[0]
+});
+resultBalance.Balance.ShouldBe(beforeBalance.Balance + 57_00000000);
+```
+
+This documentation provides a framework for implementing profit distribution and verifying its functionality through various test scenarios.
\ No newline at end of file