# User's Guide

Everything you need to know about MEYCOIN

## How to join MEYCOIN?

* Visit the website <https://meycoin.com/> and click the button "Join now"
* Download and install MEYCOIN app
  * for Android: <https://tinyurl.com/jfzexjp8>
  * for iOS: <https://apple.co/3xrRoq7>

## How to check transaction in MEYCOIN network&#x20;

Visit the website: <https://explorer.meycoin.com/>

## MEYCOIN Home

Crypto NEWS

Watch List

## MEYCOIN Wallet&#x20;

### How to Deposit Crypto Asset?

### How to Transfer Crypto Asset to Another Account?

### MEYCOIN wallet&#x20;

### How to Buy MEYCOIN?

You can buy MEY from within MEYCOIN wallet or quick button

{% tabs %}
{% tab title="From quick button" %}
![](/files/-McxKbnz-ws0_xQagag3)
{% endtab %}

{% tab title="From MEYCOIN wallet " %}
![](/files/-McxKkV-iKDWJoCKNFOy)
{% endtab %}
{% endtabs %}

1. Enter the amount you want to buy in USD or MEY. The system will convert the remaining amount according to the exchange rate at the time of purchase
2. Select the wallet you want to store MEY and click "Buy MEY"

{% hint style="info" %}
Please make sure your USD balance is greater than or equal to the amount you want to buy
{% endhint %}

![](/files/-McxHGaNSOJPPzl64iEG)

### How to Transfer MEYCOIN to Another Wallet?

## MEYCOIN Staking

MEYCOIN Staking is a tool to help investors increase digital assets and help creators develop the investment community and receive worthy rewards.

### Staking Main Screen

Staking Main screen displays the entire list of created pools, sorts newly created pools first, you can reorder by Creation date or % Complete

{% hint style="info" %}
% Complete decide that you will soon get your principal back ([see more](https://meycoin.gitbook.io/meycoin/meycoin-announcement/mey-staking))
{% endhint %}

![Staking Main screen](/files/-McwHwPZQBvzo5lPeAM1)

In addition, you can filter by pools you created or pool you already staked when clicking on the <img src="/files/-McwnDuFSghmBTQIMspF" alt="" data-size="line"> icon in the search box.

![Staking filter screen](/files/-McwI6ldHm5oVRHiFvIK)

### How to Create Pool?&#x20;

From the [Staking main screen](https://meycoin.gitbook.io/meycoin/#staking-main-screen), click the <img src="/files/-McwnCIzeftGTFFJWRm_" alt="" data-size="line"> sign in the upper right corner of the screen to open the screen to enter information to create a pool

1. Enter the name of the pool you want to create
2. Enter the pool value you want to create in USD or MEY. The system will convert the remaining pool value according to the exchange rate at the time of pool creation
3. Finally click "Create pool" after agreeing to the [MEYCOIN saving service agreement](https://meycoin.gitbook.io/meycoin/meycoin-saving-service-agreement)

{% hint style="info" %}
You will receive a **Development commission** up to 5% of the pool's value in USD provided the pool is filled ([see more](https://meycoin.gitbook.io/meycoin/meycoin-announcement/benefit-for-developers-on-june-16th-2021))

**Tips:** [Share ](https://meycoin.gitbook.io/meycoin/#how-to-sharing-our-pool)widely whenever to your investment community to get this reward soon&#x20;
{% endhint %}

![Creating Pool screen ](/files/-McwV1BUf6BUrWBFR3kP)

### How to Stake?

From the [Staking main screen](https://meycoin.gitbook.io/meycoin/#staking-main-screen), click the "Stake Now" button in the pool of your choice

1. Choose your MEY wallet&#x20;
2. Enter the number of MEY you want to stake
3. Finally click "Stake now" after agreeing to the [MEYCOIN saving service agreement](https://meycoin.gitbook.io/meycoin/meycoin-saving-service-agreement)

{% hint style="info" %}
**Interest** will be calculated daily so remember to get it every day for 365 days from staking ([see more](https://meycoin.gitbook.io/meycoin/meycoin-announcement/mey-staking))

**Tips:** Interests are not locked and can be used for profitable reinvestment in any available pool&#x20;
{% endhint %}

![Staking screen ](/files/-McwWn3q1W0ARoXxWqN0)

### How to Earn Interest?

Click "Earn" tab to check daily interest and click "Collect now" button to get it

{% hint style="info" %}
**The principal** will be automatically refunded once you have received full interest after 365 days and the pool has been filled.&#x20;

**Tips:** [Share ](https://meycoin.gitbook.io/meycoin/#how-to-sharing-our-pool)widely whenever to your investment community to fill up the pool soon
{% endhint %}

![Earning tab screen](/files/-McwcZRCtU-cuTLrBuCt)

If you want to enjoy the feeling of receiving daily interest, click on the pool card to collect interest day by day

![Pool Earning screen](/files/-McwfPTmkuRyULbYkUGD)

### How to Sharing Our Pool?&#x20;

1. Click the <img src="/files/-Mcwm90XnaFaFS1whhBL" alt="" data-size="line"> icon in the screen you want to share
2. Select the app like Facebook, Twitter... and share&#x20;

{% hint style="info" %}
Sharing your Earning will help the community realize its true potential and fill the pool with you to receive worthy benefits.
{% endhint %}

{% tabs %}
{% tab title="Share your Earning screen " %}
![Earning Pool screen ](/files/-McwkETQcPbkuXG04y62)
{% endtab %}

{% tab title="From Staking Main Screen " %}
![Staking main screen](/files/-Mcwjj1l3W-O5lnX91em)
{% endtab %}

{% tab title="From Earning tab " %}
![Earning tab screen ](/files/-McwjlW-oyqgpJ70UMmm)
{% endtab %}
{% endtabs %}

## MEYCOIN Bonus

Comming soon!

## MEYCOIN Profile Settings


# Change Logs

## 2021-06-20

### Fixed

* Overall system performance and stability improvements

### Changed

* Allow to buy MEY unlimited quantity&#x20;
* Stop developing fixed packages and pools&#x20;
* Developing a staking tool to increase MEY assets&#x20;
* Allows users to create and share staking pools for development rewards&#x20;

## 2021-03-04

### Changed

* No login required when entering the homepage
* Integrated TRC network
* Move Crypto NEWS to home page&#x20;
* Show locked USDT balance

## 2021-02-19

### Added

* Crypto NEWS

## 2021-02-02

### Changed

* Allow to deposit ETH
* Allow to transfer USD to another account&#x20;
* Allow to buy sharing package&#x20;
* Allow to enable/disable OTP email when logging in
* Enable/disable 2 factors authentication (2FA)

## 2020-01-15

### Added

* Top movers&#x20;
* Watchlist&#x20;
* USD Wallet management (desposit USDT, transaction history)
* MEYCOIN Wallet management (create multi wallet, deposit, transfer, transaction history)
* Buy Sharing package


# Announcement


# MEYCOIN Staking Is Now Live! (on June 20th, 2021)

We launched the new version of MEYCOIN app with the Staking feature

## Common Rule&#x20;

1. Everyone can create a pool to receive exclusive offers for market developers ([see more](https://meycoin.gitbook.io/meycoin/meycoin-announcement/benefit-for-developers-on-june-16th-2021))
2. Everyone can stake MEY to receive interest&#x20;
3. Unlimited origin of MEY to stake
4. Unlimited number of stakes

## Forms of Participation and Payment

Join stake with MEY and get daily interest in MEY

1. Interest rate: up to 18%/year
2. Interest calculation method: daily
3. Conditions of principal payment: meet the following conditions simultaneously

   a. Have received full interest after 365 days

   b. The pool has been filled

> *Interest rate and stake period may vary by pool*

## **Pool Initilization Rule**&#x20;

1. Pool value in USD must reach at least 10,000.00 USD
2. Initialization fee is equal to 0.25% of the pool value in USD and will be deducted from the creator's USD wallet
3. Development commission (from 3-5% of pool value in USD) will be paid automatically to creator's USD wallet when pool is filled ([see more](https://meycoin.gitbook.io/meycoin/meycoin-announcement/benefit-for-developers-on-june-16th-2021))


# MEYCOIN Launches the Staking Development Program (on June 18th, 2021)

By creating a pool and sharing the opportunity to increase digital assets up to 18%/year to your investment community, you have become a market maker of MEYCOIN Staking.

After all, your talent and hard work deserves to be rewarded with these exclusive benefits:

1. Give 100% of the pool initialization fee (convert to MEY) to the pool you created
2. Get development commission up to 5% of pool value (in USD) when pool is filled (see table below)

| **Total value of pool (X)** | **% Development Commission** |
| --------------------------- | ---------------------------- |
| 10000 <= X < 20000          | 3.00%                        |
| 20000 <= X < 30000          | 3.20%                        |
| 30000 <= X < 40000          | 3.40%                        |
| 40000 <= X < 50000          | 3.60%                        |
| 50000 <= X < 60000          | 4.00%                        |
| 60000 <= X < 70000          | 4.20%                        |
| 70000 <= X < 80000          | 4.40%                        |
| 80000 <= X < 90000          | 4.60%                        |
| 90000 <= X < 100000         | 4.80%                        |
| 100000 <= X <               | 5.00%                        |


# Saving Service Agreement

1. Meycoin.com launched for users to gain proceeds through idle cryptocurrency assets.
2. MEYCOIN will be specifically used in cryptocurrency for the Real estate industry.
3. When you use the MEYCOIN saving service, you will unconditionally authorize meycoin.com to distribute the asset according to the rules of the platform.
4. You shall abide by the relevant laws of the local Government to ensure that the sources of assets are legitimate and compliant when using the service.
5. When you use the MEYCOIN saving service, you should fully recognize the risks of investment in cryptocurrency and operate cautiously.
6. Meycoin.com keeps full rights in the distribution of rewards and reward paying time for each member participating in the pool.
7. You agree that all investment operations conducted on meycoin.com represent your true investment intentions and that unconditionally accept the potential risks and benefits of your investment decisions.
8. Meycoin.com reserves the right to suspend or terminate the MEYCOIN saving service. If necessary, meycoin.com can suspend and terminate the service at any time.
9. Due to network delay, computer system failures and other force majeure, which may lead to delay, suspension or deviation of MEYCOIN saving service execution, meycoin.com will use reasonable effort to ensure but not promise that the service execution system runs stably and effectively. Meycoin.com does not take any responsibility if the final execution doesn't match your expectations due to the above factors.

I have read and agreed to the MEYCOIN saving service Agreement and have agreed to use the MEYCOIN saving service. I am aware of these risks and confirm to use this service.


# Privacy Policy & Term of Use

By using the MEYCOIN service, we understand that you have read and agreed to the MEYCOIN Privacy Policy and Term of Use.

## **Privacy Policy**

### **General information**

This privacy policy will provide you with information about the collection, use and disclosure of personal data we receive from users of our websites (<https://meycoin.com/>). We use this data to better understand your usage of the site and to collect traffic statistics.

In case you provide us the information of the third person (such as family members, friends, or coworkers) you should make sure that these persons are familiar with this Privacy Policy and you should only share their data if you have permission to do so and ensure that his personal data is correct.

We may change this Privacy Policy from time to time, so please check this page to ensure that you are happy with any changes. By using the site, you agree to the collection and use of information in accordance with this policy.

### **How we collect information about you**

We obtain your personal information when you use our website, when you contact us via email or a web form or if you register to receive one of our regular newsletters. We may collect and process the following types of information about you:

When you visit our site we may collect data about your IP address, browsing activity and how you use our website. This data may be combined with other information you provide including your name, email address, phone number, language preference and information regarding the pages you access.

We may receive information about you if you use any other websites we, or our partners, operate. We also work with third parties (including, contractors, project partners, service providers, analytics providers) and may receive information about you from them. This may be combined with other information you provide to us.

### **How your information is used**

We may use your personal information for the following purposes:

* Send you personalized communications which you have requested and that may be of interest to you, which may be based on your activity on our website(s) or the website of our partners. These may include information about campaigns, activities and events.
* Understand and measure the effectiveness of how we serve you and others. to make suggestions and recommendations to you about services that may interest you.
* Seek your views or comments on the service we provide.
* Analytics and profiling to create aggregate trend reports, find out how visitors arrive at our website
* Provide you with related news and information.
* Notify you of changes to our policy or terms of service.

### **Responsible person**

For any issues, relating to data protection you may contact <contact@meycoin.com> in writing by e-mail or letter to the following address:

*MEY PIONEER PTE. LTD*

*66 Rangoon Road, 218356, Singapore*

***Contact us***

*If you have any questions about our privacy policy, please do not hesitate to contact us via e-mail address <contact@meycoin.com>*

## **Terms of Use**

Please read the Terms of Use carefully before using the Websites. By using the Websites or clicking to accept or agree to the Terms of Use when this option is made available to you, you accept and agree to be bound and abide by these Terms of Use in addition to our Privacy Policy (incorporated herein by reference).

### **Who May Use the Websites**

This website is offered and available to users who are 13 years of age or older. By using this Website, you represent and warrant that you (i) are 13 years of age or older, (ii) are not barred to use the Websites under any applicable law, and (iii) are using the Websites only for your own personal use. If you do not meet these requirements, you must not access or use the Websites.

### **Changes to the Terms of Use**

We may revise and update these Terms of Use from time to time in our sole discretion. Your continued use of the Websites following the posting of the revised version means that you accept and agree to the changes. You are expected to check this page frequently so you are aware of any changes, as they are binding on you.

### **Accessing the Websites and Account Security**

We reserve the right to withdraw or amend this Website, and any service or material we provide on the Website, in our sole discretion without notice. We do not guarantee that our site or any content on it, will always be available or be interrupted. We will not be liable if for any reason all or any part of the Websites is unavailable at any time or for any period. From time to time, we may restrict access to some parts of the Website, or the entire Website, to users.\
\
You are responsible for:

* Making all arrangements necessary for you to have access to the Websites.
* Ensuring that all persons who access the Websites through your internet connection are aware of these Terms of Use and comply with them.

To access the Websites or some of the resources it offers, you may be asked to provide certain registration details or other information. It is a condition of your use of the Websites that all the information you provide on the Websites is correct, current and complete. You agree that all information you provide to register using this website or otherwise, including, but not limited to, using any interactive features on the Website, is governed by our Privacy Policy, and you consent to all actions we take with respect to your information consistent with our Privacy Policy.

You should use particular caution when inputting personal information on to the Websites on a public or shared computer so that others are not able to view or record your personal information.

### **Intellectual Property Rights**

The Websites and its entire contents, features and functionality (including but not limited to all information, software, text, displays, images, video and audio, and the design, selection and arrangement thereof), are owned by the Foundation, its licensors or other providers of such material and are protected by copyright, trademark, patent, trade secret and other intellectual property or proprietary rights laws.

Unless otherwise marked: (a) all material, data, and information on the Websites, such as data files, text, music, audio files or other sounds, photographs, videos, or other images, but excluding any software or computer code (collectively, the “Non- Code Content”) is licensed under the Creative Commons Attribution 4.0 International License; and (b) all software or computer code (collectively, the “Code Content”) is licensed under the MIT License.

### **Trademarks**

The Mey logo and all related names, logos, product and service names, designs and slogans are trademarks of the Mey or its affiliates or licensors. You must not use such marks without the prior written permission of Mey. All other names, logos, product and service names, designs and slogans on this Website is the trademarks of their respective owners.

### **Prohibited Uses**

You may use the Websites only for lawful purposes and in accordance with these Terms of Use. You agree not to use the Website:

* In any way that violates any applicable federal, state, local or international law or regulation (including, without limitation, any laws regarding the export of data or software to and from the US or other countries).
* For the purpose of exploiting, harming or attempting to exploit or harm minors in any way by exposing them to inappropriate content, asking for personally identifiable information or otherwise.
* To send, knowingly receive, upload, download, use or re-use any material which does not comply with these Terms of Use.
* To transmit, or procure the sending of, any advertising or promotional material without our prior written consent, including any "junk mail", "chain letter" or "spam" or any other similar solicitation.
* To impersonate or attempt to impersonate the Foundation, a Foundation employee, another user or any other person or entity (including, without limitation, by using e-mail addresses or screen names associated with any of the foregoing).
* To engage in any other conduct that restricts or inhibits anyone's use or enjoyment of the Website, or which, as determined by us, may harm the Foundation or users of the Websites or expose them to liability.

Additionally, you agree not to:

* Use the Websites in any manner that could disable, overburden, damage, or impair the site or interfere with any other party's use of the Website, including their ability to engage in real-time activities through the Websites.
* Use any robot, spider or other automatic devices, process or means to access the Websites for any purpose, including monitoring or copying any of the material on the Websites.
* Use any manual process to monitor or copy any of the material on the Websites or for any other unauthorized purpose without our prior written consent.
* Use any device, software or routine that interferes with the proper working of the Websites.
* Introduce any viruses, trojan horses, worms, logic bombs or other material that is malicious or technologically harmful.
* Attempt to gain unauthorized access to, interfere with, damage or disrupt any parts of the Website, the server on which the Websites is stored, or any server, computer or database connected to the Websites.
* Attack the Websites via a denial-of-service attack or a distributed denial-of-service attack.
* Otherwise, attempt to interfere with the proper working of the Websites.

### **Reliance on Information Posted**

The information presented on or through the Websites is made available solely for general information purposes. We do not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. We disclaim all liability and responsibility arising from any reliance placed on such materials by you or any other visitor to the Website, or by anyone who may be informed of any of its contents.

This Website includes content provided by third parties, including materials provided by other users, bloggers and third-party licensors, syndicators, aggregators and/or reporting services. All statements and/or opinions expressed in these materials, and all articles and responses to questions and other content, other than the content provided by the Foundation, are solely the opinions and the responsibility of the person or entity providing those materials. These materials do not necessarily reflect the opinion of the Foundation. We are not responsible, or liable to you or any third party, for the content or accuracy of any materials provided by any third parties.

### **Changes to the Websites**

We may update the content on this Website from time to time, but its content is not necessarily complete or up-to-date. Any of the material on the Websites may be out of date at any given time, and we are under no obligation to update such material.

### **Information About You and Your Visits to the Websites**

All information we collect on this Website is subject to our Privacy Policy. By using the Website, you consent to all actions taken by us with respect to your information in compliance with the Privacy Policy.

### **Online Purchases and Other Terms and Conditions**

Additional terms and conditions may also apply to specific portions, services or features of the Website, including the registration and sponsorship for conference events. All such additional terms and conditions are hereby incorporated by this reference into these Terms of Use. In the event of terms that are directly conflicting between these Terms of Use and terms of conditions for the registration or sponsorship of a conference event, the terms and conditions for the event shall control.

### **Linking to the Websites and Social Media Features**

You may link to our homepage, provided you do so in a way that is fair and legal and does not damage our reputation or take advantage of it, but you must not establish a link in such a way as to suggest any form of association, approval or endorsement on our part without our express written consent.

### **Links from the Websites**

If the Websites contain links to other sites and resources provided by third parties, these links are provided for your convenience only. This includes links contained in advertisements, including banner advertisements and sponsored links. We have no control over the contents of those sites or resources and accept no responsibility for them or for any loss or damage that may arise from your use of them. If you decide to access any of the third party websites linked to this Website, you do so entirely at your own risk and subject to the terms and conditions of use for such websites. We reserve the right to withdraw linking permission without notice.

### **Geographic Restrictions**

The owner of the Websites is based in Singapore. We make no claims that the Websites or any of its content is accessible or appropriate outside of Singapore. Access to the Websites may not be legal by certain persons or in certain countries. If you access the Websites from outside Singapore, you do so on your own initiative and are responsible for compliance with local laws.

### **Disclaimers of Warranties**

This Terms of Use and any other documents published in association with it relate to the intended development and use of MEY. They are for information purposes only and may be subject to change.

* **Eligible purchasers**

The information in this document is provided privately to certain prospective purchasers and is not intended to be received or read by anyone else. Eligibility is not guaranteed and is likely to be subject to restrictions.

* **No offer of regulated products**

The MEY Blockchain, MEY Token or any token that operates on it is not intended to represent a security or any other regulated product in any jurisdiction.\
\
This document does not constitute an offer or solicitation of securities or any other regulated product, nor a promotion, invitation or solicitation for investment purposes. The terms of the purchase are not intended to be a financial service offering document or a prospectus of any sort.\
\
MEY Token does not represent equity, shares, units, royalties or rights to capital, profit, returns or income in the platform or software in any company or intellectual property associated with the platform or any other public, private enterprise, corporation, foundation or other entity in any jurisdiction.

* **This Terms of Use is not advice**

This document does not constitute advice to purchase MEY Token. It must not be relied upon in connection with any contract or purchasing decision.

* **Risk warning**

The purchase of MEY Token and participation in MEY Token sale carries with it significant risks.\
\
Before purchasing MEY Token, you should carefully assess and take into account the risks, including those listed in any other documentation.

* **Views expressed in this Terms of Use**

The views and opinions expressed in this Terms of Use are those of Block and do not reflect the official policy or position of any government, quasi-government, authority or public body (including but not limited to any regulatory body of any jurisdiction) in any jurisdiction.\
\
Information contained in this document is based on sources considered reliable but there is no assurance as to their accuracy or completeness.

* **No third party affiliation or endorsements**

References in this Terms of Use to specific companies and platforms are for illustrative purposes only. The use of any company and/or platform names and trademarks does not imply any affiliation with, or endorsement by, any of those parties.

* **You must obtain all necessary professional advice**

You must consult a lawyer, accountant, tax professional and/or any other professional advisors as necessary before determining whether to purchase MEY Blockchain or otherwise participate in the MEY project.\
\
This Terms of Use has not been reviewed by any regulatory authority in any jurisdiction. References in this document to specific companies, networks and/or potential use cases are for illustrative purposes only. Other than explicitly mentioned partners or providers such as MEY Pioneer, the use of any other company and/or platform names and trademarks does not imply any affiliation with, or endorsement by, any of those parties.\
\
Amounts are expressed in United States dollars (“USD”) unless expressly stated otherwise.\ <br>


# Technical Specifications


# Addresses

### Client-side

Account and contract addresses are Base58-check encoded strings that look like this:

```
AmQA7dHJFiA4mXXxTV5sAniLpxMrankdW4Cow3ykj1UM5G14QKL5
```

InternalThe prefix used for encoding Meey addresses in base58-check is **0x42**

[Technical explanation of Base58-check encoding](https://en.bitcoin.it/wiki/Base58Check_encoding)

### Internal

Internally (in the server and over the wire, i.e. in GRPC requests) addresses are byte arrays with a length of 33. They represent the compressed public key of an account.

[Technical explanation of public keys](https://learnmeabitcoin.com/technical/public-key)

In the case of smart contracts, the address is generated from a hash of the creator’s account and the creating transaction’s nonce, prefixed with the byte **0x0C** to arrive at a compatible length of 33 bytes. As a developer, you don’t have to worry about this: smart contract addresses can be used just the same as account addresses.


# Token Units

**1 meey&#x20;*****= 1*****&#x20; 10^9 mgas = 1 &#x20;*****10^18 gas***

Note that amounts in the base unit gas exceed the range of 64-bit integers. You need some implementation of Big Integer to deal with these numbers. Meey SDKs come bundled with a recommended way to do that. In most cases, you can just use strings instead of numbers. For example, when creating a JSON transaction, set

```
{
    "amount": "1000000000000000000"
}
```


# Consensus Algorithm

The objective of all blockchain protocols is to replicate a blockchain and its associated state across participating nodes. To achieve such an agreement, each blockchain protocol deploys a consensus algorithm.

The public Meey network uses [BFT-DPoS](https://medium.com/@wesoha/bft-dpos-consensus-in-meey-chain-b748d22d1271) for blockchain consensus.

### BP Election

In DPoS, blocks are generated only by a limited number of nodes called Block Producers (BPs). BPs are elected via voting, where the voting power is weighted by staked tokens.

BPs are re-elected round by round (blocks per round = 100). In each round, time is split into slots and each slot is assigned to one of the elected BPs. Only the permitted BP can produce a block in a time slot.

### Staking & Voting

Staking means locking up one’s tokens for a minimum period of time. Any user wanting to vote must stake their tokens since the voting power is weighted by the number of staked tokens, as remarked above.

All of these requests are performed via a transaction. Therefore, all processes are transparently recorded in the blockchain and can be verified by anyone.

After the voting transaction is included in the block, the results are calculated immediately. But there is a slight delay until it is applied. The current BPs are elected based on the voting result gathered at the block number: (\<current block number> / 100 - 1) \* \<the total number of BPs>.

In other words, the voting results gathered in the past (approximately 1 round before) are used for stability (recent blocks may be roll-backed via a reorganization).

Votes are locked for a certain period of time to prevent users from spamming votes. On the public Meey network, this is currently approx. 1 day (after 60 \* 60 \* 24 block number). That means, after casting a vote, a user can only change their vote after 1 day has passed.Last Irreversible Block (LIB)

In some blockchain protocols, a blockchain may branch into two or more, which is called a fork. Later, only one of them is chosen as the main branch via a set of rules defined by the protocol. Such reorganizations limit each block’s finality and, in turn, transaction’s finality. For example, a transaction, included in a block at one time, might be rejected later.

DPoS also allows blockchain forks. However, a block becomes a last irreversible block (LIB) when it is (double time) confirmed by a majority (2/3+) of BPs. Once a block is determined as a LIB, it cannot be rolled back, i.e. it achieves finality.


# Transactions

### Tx

| Field       | Type   | Description                                                                                            |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------ |
| Nonce       | uint64 | Increasing number used only once per sender account                                                    |
| Recipient   | bytes  | Decoded sender account address                                                                         |
| Amount      | bytes  | Amount of transfer                                                                                     |
| Payload     | bytes  | Smart contract data                                                                                    |
| Limit       | uint64 | Maximum limit of gas to be used (0 = no limit)                                                         |
| Price       | bytes  | Reserved                                                                                               |
| Type        | int    | 0 : Normal \| 1: Governance \| 4: Transfer \| 5 : Call \| 3: FeeDelegation \| 6: Deploy \| 2: Redeploy |
| ChainIDHash | bytes  | Hash of chain ID                                                                                       |
| Sign        | bytes  | ECDSA signature with secp256k1                                                                         |

### Transaction types

#### Normal type (0)

Normal transactions are used to transfer tokens and calling smart contracts.&#x20;

#### Governance type (1)

Governance transactions are used for calling system contracts, such as staking and voting. Transactions of this type have a special payload format and recipient. See below for details.

#### Transfer type (4)

Transactions that only transfer value. For backwards compatibility, the Normal type can also be used.

#### Call type (5)

Smart contract calls should be denoted using the Call transaction type. For backwards compatibility, the Normal type can also be used.

#### FeeDelegation type (3)

FeeDelegation transactions are used for calling smart contract while charging fees to the contract. This only works if the contract supports the fee delegation interface.

#### Deploy type (6)

Used to deploy contracts. For backwards compatibility, the Normal type can also be used.

#### Redeploy type (2)

Used to re-deploy a contract.

### Governance transaction details

The following table shows the specification for each field of the transaction body of a governance transaction.

| Action              | Recipient         | Amount            | Payload                                                                                                                    |
| ------------------- | ----------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------- |
| staking             | `meey.system`     | amount to stake   | `{"Name":"v1stake"}`                                                                                                       |
| unstaking           | `meey.system`     | amount to unstake | `{"Name":"v1unstake"}`                                                                                                     |
| voting              | `meey.system`     | 0                 | `{"Name":"v1voteBP","Args":[<peer IDs>]}`                                                                                  |
| voting DAO          | `meey.system`     | 0                 | `{"Name":"v1voteDAO","Args":[<DAO ID>,<candidate>]}`                                                                       |
| create name         | `meey.name`       | 20 meey \*        | `{"Name":"v1createName","Args":[<a name string>]}`                                                                         |
| update name         | `meey.name`       | 20 meey \*        | `{"Name":"v1updateName","Args":[<a name string>, <new owner address>]}`                                                    |
| add admin           | `meey.enterprise` | 0 meey            | `{"Name":"appendAdmin","Args":[<new admin address>]}`                                                                      |
| remove admin        | `meey.enterprise` | 0 meey            | `{"Name":"removeAdmin","Args":[<admin address>]}`                                                                          |
| change raft cluster | `meey.enterprise` | 0 meey            | `{"Name":"changeCluster","Args":[{"command":"add","name":"[node name]","address":"[peer address]","peerid":"[peer id]"}]}` |
| add config          | `meey.enterprise` | 0 meey            | `{"Name":"appendConf","Args":[<config key>,<config value>]}`                                                               |
| enable config       | `meey.enterprise` | 0 meey            | `{"Name":"enableConf","Args":[<config key>,<true\|false>]}`                                                                |
| remove config       | `meey.enterprise` | 0 meey            | `{"Name":"removeConf","Args":[<config key>,<config value>]}`                                                               |

### Transaction receipts

Every transaction generates a receipt upon successful execution which contains the result and metadata such as fee and gas used. The `status` can be one of three values:

**SUCCESS**

Simple value transfer transactions and successful contract executions. For contract calls, the result is available in `ret`.

**ERROR**

Failed contract execution. The error message can be found in `ret`.

**CREATED**

Succesful contract deployment transaction. The created address can be found in `contractAddress`.


# Transaction Fees

The Meey protocol includes transaction fees that need to be paid according to the configuration of the network.

Gas is a numerical representation of execution and storage costs in the transaction and contract. But gas is not a fee. To calculate the fee, we need the gas price.

### Gas Price

Gas price is the GAS value corresponding to 1 gas. All transactions in a block have the same gas price. Gas price is determined by a DAO vote.

### Gas Limit

The gas limit allows the user to specify the maximum amount of gas used for transactions and contracts.&#x20;

### Gas Table

#### Transaction

Transactions other than governance transactions consume `100,000 gas` by default. If you have a payload, additional gas will be used depending on the size.

**Payload gas**: (*Bytes of a payload* - 200) \* 5

#### Instructions

The table below shows gas usage for Lua bytecode.

| Name                                                                           | GAS |
| ------------------------------------------------------------------------------ | --- |
| ISLT, ISGE, ISLE, ISGT, ISEQV, ISNEV, ISEQS, ISNES, ISEQN, ISNEN, ISEQP, ISNEP | 2   |
| ISTC, ISFC, IST, ISF, ISTYPE, ISNUM                                            | 1   |
| MOV                                                                            | 2   |
| NOT, UNM                                                                       | 1   |
| LEN                                                                            | 3   |
| ADDVN, SUBVN                                                                   | 2   |
| MULVN, DIVVN, MODVN                                                            | 3   |
| ADDNV, SUBVN                                                                   | 2   |
| MULNV, DIVNV, MODNV                                                            | 3   |
| ADDVV, SUBVV                                                                   | 2   |
| MULVV, DIVVV, MODVV                                                            | 3   |
| POW                                                                            | 3   |
| CAT                                                                            | 3   |
| KSTR, KCDATGA, KSHORT, KNUM, KPRI, KNIL                                        | 1   |
| UGET, USETV, USETS, USETN, USETP, UCLO, FNEW                                   | 2   |
| TNEW                                                                           | 2   |
| TDUP                                                                           | 5   |
| GGET, GSET                                                                     | 3   |
| TGETV, TGETS, TGETB, TGETR, TSETV, TSETS, TSETB, TSETM, TSETR                  | 2   |
| CALLM, CALL, CALLMT, CALLT, ITERC, ITERN                                       | 10  |
| VARG                                                                           | 5   |
| ISNEXT                                                                         | 2   |
| RETM                                                                           | 5   |
| RET, RET0, RET1                                                                | 3   |
| FORI, FORL, ITERL, LOOP, JMP                                                   | 2   |

#### Built-in Functions

Gas usage for built-in functions provided by the Lua VM

| Name                                                  | GAS                                             |
| ----------------------------------------------------- | ----------------------------------------------- |
| assert                                                | 3                                               |
| error                                                 | 5                                               |
| getfenv                                               | 5                                               |
| getmetable                                            | 3                                               |
| ipairs                                                | 3                                               |
| next                                                  | 3                                               |
| pairs                                                 | 3                                               |
| pcall                                                 | 10                                              |
| rawequal                                              | 5                                               |
| rawget                                                | 3                                               |
| rawset                                                | 5                                               |
| select                                                | 3 (length), 5 (get an element)                  |
| setfenv                                               | 5                                               |
| setmetatable                                          | 3                                               |
| tonumber                                              | 5                                               |
| tostring                                              | 5                                               |
| type                                                  | 2                                               |
| unpack                                                | 5 + (2 \* *number of arguments*)                |
| xpcall                                                | 10                                              |
| string.byte, string.char                              | 3 + (1 \* *number of string units (arguments)*) |
| string.dump                                           | 10                                              |
| string.find, string.gmatch, string.gsub, string.match | 3 + (5 \* *number of matching strings*)         |
| string.format                                         | 3 + (2 \* *number of format modifiers*)         |
| string.lower                                          | 3 + (1 \* *number of string units (argument)*)  |
| string.rep                                            | 3 + (2 \* *number of concatenation*)            |
| string.reverse                                        | 3 + (1 \* *number of string units (argument)*)  |
| string.sub                                            | 3 + (1 \* *number of string units (argument)*)  |
| string.upper                                          | 3 + (1 \* *number of string units (argument)*)  |
| table.concat                                          | 3 + (3 \* *number of arguments*)                |
| table.insert                                          | 3 + (3 \* *number of cells to move*)            |
| table.maxn, table.minn                                | 3 + (3 \* *comparison count*)                   |
| table.sort                                            | 3 + (5 \* *comparison count*)                   |
| math.abs, math.ceil, math.floor, math.pow             | 3                                               |
| math.max, math.min                                    | 3 + (1 \* *number of arguments*)                |
| bit.tobit                                             | 3                                               |
| bit.tohex                                             | 5                                               |
| bit.bnot                                              | 2                                               |
| bit.bor, bit.band, bit.xor                            | 3 + (2 \* *number of arguments*)                |
| bit.lshift, bit.rshift, bit.ashift, bit.rol, bit.ror  | 3                                               |
| bit.bswap                                             | 2                                               |


# Keystore

{% hint style="info" %}
Securing private keys is the responsibility of client software, but Meey has a recommended storage format for increased portability. This storage format is also used internally when storing accounts in meeycli.
{% endhint %}

This so-called Keystore format defines a file format (json) and encryption scheme.

### File format

Filename: `{address}__keystore.txt`

```
{
  "meey_address": "Amdxxxx",
  "ks_version": "1",
  "kdf": {
    "algorithm": "algorithm_name",
    "params": {
      "some_param": "some_value"
    },
    "mac": "mesasge_authentication_code"
  },
  "cipher": {
    "algorithm": "algorithm_name",
    "params": {
      "some_param": "some_value"
    },
    "ciphertext": "dxxxx",
  }
}
```

### Rules

* Version field is for choosing cipher algorithm. If version updates, cipher algorithm would be updated (also format can change).
* Every file has its own algorithm and parameters per version. If any of the parameters break, an error should be thrown.
* File name is ‘{address}\_\_keystore.txt’ or ‘{alias}\_\_keystore.txt’
* File name is used to identify keystore file. Duplicates are not allowed.
* For the alias file, you can have same keystore file representing same account using different alias. That’s fine.
* Address must be a valid base58-check encoded address. Alias must be form of `[a-zA-Z0-9]+`

### Examples

**Encrypt**

```
cipherText = AES_CTR.encrypt(rawPrivateKey, encryptionKey[0:16], nonce)
mac = Sha256(encryptionKey[16:32] + cipherText)

keystore = {
  "meey_address": "Amdxxxx",
  "ks_version": "1",
  "kdf": {
    "algorithm": "scrypt",
    "params": scryptParams,
    "mac": mac
  },
  "cipher": {
    "algorithm": "aes-128-ctr",
    "params": {
      "iv": nonce
    },
    "ciphertext": cipherText
  }
}
```

**Decrypt**

```
encryptionKey = Scrypt(rawPassword, keystore.kdf.params)
mac = Sha256(encryptionKey[16:32] + json.cipher.ciphertext)
if keystore.kdf.mac != mac {
  throw "invalid mac"
}
rawPrivateKey = AES_CTR.decrypt(json.cipher.ciphertext, encryptionKey[0:16], json.cipher.params.iv)
```

**Recommended parameters**

```
{
    kdfAlgorithm: 'scrypt',
    cipherAlgorithm: 'aes-128-ctr',
    kdfParams: {
        dklen: 32,
        n: 1 << 18,
        p: 1,
        r: 8,
    },
}
```


# Peer Connect

### Node Discovery

When the Meey server starts running, you need a way to connect to the network. To do this, you need to know and connect to other Meey server nodes already connected to the chain. Meey does this using several methods.

#### Query wezen

Wezen keep list of meey server nodes, such like DNS. Meey server connect and query to official Meey Wezen automatically, if the chain is Official MeeyMainNet or MeeyTestNet.

You can build and run custom Wezen for your private chain or custom public chain. You should configure to use custom Wezen by modifying config file.

#### Designate Peer

You can add a list of designated known peers to connect to at boot time in configuration file using the option ‘npaddpeers’.

#### Dynamic peer discovery

Meey server requests peer list from other connected peers as well as Wezen if it cannot find enough peers.

### Peer connect process

The network communication of Meey server operates on libp2p basis, and libp2p is responsible for encryption and node distinction at transmission level. After a tcp session is created, both peers start the handshake operation.

#### Peer Handshake

In the Handshake phase, peers exchanges each other’s version, chain ID and state to determine whether to connect. If the other node version is not supported by the current server or the operating chain ID is different, the connection is stopped. Once the handshake is successful, the difference in block height is compared and synchronization started.

#### Keep Alive

Meey server maintains a connection-based communication. Both peers disconnect when the internally defined retention score increases beyond a certain level. This score decreases to a low level when a query is requested, and increases when a bad block or TX notification is sent.

#### Peer blacklist

When an internally defined ban score exceeds a certain level, the Meey server blocks the peer’s connection. This score increases due to the connection being disconnected due to exceeding the connection maintenance score, etc., and the blocking period is also changed by calculating the score or the number of blocking times. You can also permanently block by specifying a block address in the configuration file.


# Block Management

This article describes implementation details of management of blocks in the Meey server. It is aimed at blockchain server developers.

### Block generation

The block factory is responsible for generating blocks and part of the consensus engine.

The consensus engine manages when blocks are created on which nodes. Meey uses dPOS by default. A new block producer is selected every second.

The process for creating blocks in the block factory is as follows.

1. Select transactions from from mempool
2. Perform a transaction one by one. If the execution is successful, the transaction is included in the block.
3. If the block size and time limit are exceeded, the transaction is no longer included.
4. Create blocks that contain executed transactions and add signatures to blocks.

The block factory sends the generated blocks to the chain service for propagation and storage.

### Notify block

Blocks passed to the chain service are propagated to the connected peer nodes and stored in the database.

The chain service of a node that received the block verifies the block, executes the transactions, and adds the block to its own database.

### Save block

The chain service stores the generated blocks in the DB for permanent storage. It also stores additional meta information to store connection information about the chain.

Meey uses the Badger database as its permanent storage. Badger stores data in key/value form and supports the concept of transactions similar to a typical database.

**Information stored in the DB is as follows.**

The DB is managed in two separate categories, ChainDB and StateDB. This article describes the ChainDB used to store chain information.

#### Block info

This information is used to search for blocks in a chain using a hash. Typically, when a block is requested as a hash from another node, the Hash is searched for and responded to the block with a key.

| Key           | Value                    |
| ------------- | ------------------------ |
| Hash of Block | serialized data of Block |

#### Chain info

Chain info is the information that indicates when a block is connected to the main branch.

If the main branch is not connected, that is, only block info is saved and the chain info is not stored.

You can search the blocks of every height of the main branch using the chain info. You can know the height of the top block of the chain.

Chain info is also used to determine whether the block belongs to the main branch or the sub branch.

| Key              | Value                              |
| ---------------- | ---------------------------------- |
| Number of Block  | block hash                         |
| Latest block Key | latest block number of main branch |

#### Transaction Info

TX info is meta information of the transaction that was performed in the main branch. If you search the DB with transaction hash, you can see which block the transaction is stored in and where the transaction is stored in the block.

The contents of the transaction are not saved separately. Therefore, in order to know the contents of the actual transaction, you must search Block info using Block hash and index found in TX info.

| Key              | Value                                       |
| ---------------- | ------------------------------------------- |
| Transaction hash | (Block Hash, index of transaction in block) |


# Chain Management

This article describes implementation details of chain management in the Meey server. It is aimed at blockchain server developers.

The chain service is responsible for managing the chain. It performs the following tasks in large part:

1. Validation
2. Insert block to chain
3. Reorganization
4. Synchronization

### Block validation <a href="#block-validation" id="block-validation"></a>

The blocks received in the network may not be valid, so a number of checks are made.

#### Pre-execution execution <a href="#pre-execution-execution" id="pre-execution-execution"></a>

The validator module ensures that the block was generated from a valid BP and the transaction contained in the block was not forged.

* **Consensus validation:** Validate the block generated by the valid BP through block creation time and signature.
* **Transaction merkle validation:** Validate that the transactions were not forged. The verifier module generates a merkle tree with the transactions and checks if it is the same as the transaction merkle root stored in the block header.

#### Post-execution validation <a href="#post-execution-validation" id="post-execution-validation"></a>

These checks ensure that the results of the transaction contained in the block are the same as the results of the BP node that generated the block.

* **State root validation:** Checks if the changed state root node hash is the same as the blocksRootHash stored in the block head.
* **Receipt merkle validation:** Generates a merkle tree with the receipts generated as a result of the transactions and checks if they are identical to the receipts stored in the block header.

### Insert block into chain <a href="#insert-block-into-chain" id="insert-block-into-chain"></a>

There are two cases in which the chain service adds blocks:

**1.Block generated by block factory**

When it is a BP node’s turn, it generates new blocks in the block factory.

The block factory performs all transactions and forwards the block to the chain service. The execution results are included with the block.

The execution results include the results of the transaction, receipt, and state changed entry indicating the change to the account.

The chain service stores information related to blocks in the ChainDB and information about accounts in the StateDB.

**2. Block received from another peer node**

For blocks received from other peer nodes, there are three main cases:

* **Orphan block:** This is the case if the parent block has not yet been stored in the DB. Orphan blocks are stored in the orphan block cache on memory. Then, when the parent block is received, it is removed from the organ block cache and reprocessed.
* **Side branch block:** In case the parent block is stored but is not part of the main branch. In this case, the block is not performed and only the block info{hash, block} is stored.
* **Main branch block:** In case the head of the main branch is the next block. In this case, the blocks are stored after performing the transactions.

The process for storing blocks in the main branch is as follows:

1. Validation before execution
2. Execute transactions
3. Apply changed account entries state merkle tree
4. Validate after execution
5. Save state merkle tree to StateDB
6. Save chain meta data to ChainDB

### Reorganization <a href="#reorganization" id="reorganization"></a>

The chain service selects and maintains the longest chain as the main branch. The side branches are not executed and only the block info is stored in the DB. If the side branch received from another peer is longer than the main branch held by the node, the side branch is changed to the main branch. This is called the reorganize process.

The reorganization is performed as follows.

1. **Find common ancestor:** Syncer finds the last common ancestor block of the main branch and side branch.
2. **Rollback master branch:** State is reset to the point at which the common ancestor block was executed
3. **Rollforward side branch:** Syncer runs from the next number of the common ancestor block to the head block of the side branch. At this time, only StateDB is changed and Chain info and Tx info are not changed.
4. **Swap chain meta:** Syncer do not change the chain info during rollback and rollforward to atomically change the chain. Change the chain meta information after the previous process has been successfully completed. At this time, chain info and transaction info are deleted for the rollbacked block, and new chain info and transaction info are added for the rollforwarded block.

Transactions belonging to rollbacked blocks but not included in rollforwarded blocks are returned to mempool. This is to prevent transaction loss.

### Synchronization <a href="#synchronization" id="synchronization"></a>

When you add a new node or restart a node that was temporarily stopped, you need to get the latest chain information from existing nodes. This is called the synchronization process.

The situation that causes sync is as follows:

* When the peer goes through a handshake process to connect, the height of the chain of the remote peer is higher than the current node
* If the height of the block notified in the peer is higher than the head of the current main branch

The syncer specifies the node that sent the block that caused the sync to the target node and synchronizes with the chain of that node.

For synchronize a long chain, a large amount of block information must be received from the peer node. This is likely to cause a performance degrade at the peer node. Therefore, it gets information from as many peers as possible to distribute the load.

#### Synchronize step <a href="#synchronize-step" id="synchronize-step"></a>

1. **Find common ancestor:** Syncer finds the last common ancestor of the current node chain and the target node chain.
2. **Get hashes:** It gets the hashes of the block after the common ancestor from the target node.
3. **Get blocks:** N blocks are requested from all valid peers connected to the current node.
4. **Insert blocks to chain:** The received block is added to the chain using the chain service.

2, 3, and 4 are performed in parallel. Most of the time is spent in the insert part of the chain.


# Technical Details


# Network Architect

![](https://gblobscdn.gitbook.com/assets%2F-MFiDsBg9CTnV83GlnkS%2F-MHZrBHkPa-CC8L_u9DI%2F-MHZy2uMCBrXoWJA9sm-%2Fmeey-network.png?alt=media\&token=70b5d48f-5a1d-4ec0-a16b-ba0dd23084f1)

The peer role of the MEEY Network distinguishes its external network from the internal network. In this way, we can save network costs between nodes more effectively than through the traditional way

#### Internal Network <a href="#caf1" id="caf1"></a>

* Block Producers (BP): The BP uploads blocks and broadcasts those blocks to other BPs and Agents within the same internal network.
* Agents: The Agent is the BP’s representative and communicates with other nodes in the external network and broadcasts the block information to other BPs as soon as possible.

#### External Network <a href="#fa4c" id="fa4c"></a>

* Watchers: The Watcher syncs and provides the API service.

### The objective of Agents <a href="#id-67f4" id="id-67f4"></a>

Basically their role is to maximize time efficiency in block broadcasting. The Agents actively connect with other Agents and BPs in the open network after verifying their identities.

Agents will propagate the blocks produced by BPs to Agents and other BPs in a manner that focuses on speed and latency, and immediately sends new block notifications sent by those Agents and BPs to the representative BP. On the other hand, Agents propagate notifications to the Watcher in ways that make efficient use of the network.

### Identity verification function <a href="#f07a" id="f07a"></a>

Each node confirms the qualification of a BP based on BP information and result of voting. Agents also confirm the qualification of Agents based on certification issued by BPs.


# Config Network

### Genesis block configuration

The genesis block is the first block created on a new chain according to a predefined specification. If you want to bootstrap your own Meey blockchain, you will need to configure and create the genesis block. All nodes producing blocks and syncing with the network need to use the same genesis block.

**Example genesis**

```
{
    "chain_id":{
        "magic": "[insert an identifier string for your network]",
        "public": false,
        "mainnet": false,
        "coinbasefee": "1000000000",
        "consensus": "dpos"
    },
    "timestamp": 1548918000000000000,
    "balance": {
        "[insert address from genesis]": "470000000000000000000000000",
        "[insert address from bp01]": "10000000000000000000000000",
        "[insert address from bp02]": "10000000000000000000000000",
        "[insert address from bp03]": "10000000000000000000000000"
    },
    "bps": [
        "[insert text from bp01.id]",
        "[insert text from bp02.id]",
        "[insert text from bp03.id]"
    ]
}
```

| Key           | Type   | Explanation                                                                                          |
| ------------- | ------ | ---------------------------------------------------------------------------------------------------- |
| chain\_id     | obj    |                                                                                                      |
| – magic       | string | <p>A name identifier used to distinguish different chains.<br>Example: yourchain.network</p>         |
| – public      | bool   | <p>If this chain is for a public (true) or private network.<br>This may affect certain features.</p> |
| – mainnet     | bool   | If this is the main network (true) or a sidechain for another network.                               |
| – consensus   | string | This blockchain’s consensus type (dpos)                                                              |
| – coinbasefee | string | The default transaction fee amount                                                                   |
| timestamp     | number | The genesis block’s creation timestamp in nanoseconds                                                |
| balance       | obj    | A mapping of addresses and allocated balances                                                        |
| bps           | list   | A list of fallback block producer peer ids.                                                          |

### Creating peer identification (Optional Step)

Every peer (i.e. instance of meeysvr) is identified by a peer id, derived from its public key. If unspecified, meeysvr creates these automatically, but you may want to do it manually to control the generation of keys and make backups. You can use the CLI to do that:

```
meeycli keygen your-keyname

# Using Docker:
docker run --rm -v $(pwd):/tools/ meey/tools meeycli keygen your-keyname
```

You then need to specify the path to the generated your-keyname.key file in the Meey configuration:

```
...
[p2p]
npkey = "/meey/your-keyname.key"
...
```

### Internal Zones

There may be several BPs in one private network; these BPs can be connected directly to spread the blocks without having to pass through Agents. And these BPs can be more efficient in resource use by sharing Agents than by each BP having Agents.

For efficient use of network and computing resources, Agent categorizes networks to internal and external, delivering only internal to external, or vise versa.

The Agent node connects the client BPs in the internal network with other BPs or Agents in the external network. The Agent passes blocks generated by a client to the BPs or Agents of the external network as quickly as possible, while the blocks notified by the external BPs or Agents are passed to the client BPs.\
\
**Config Example**

NOTE: Configuring BP and Agent are advanced topic, and wrong configuration can cause performance degradation or abnormal operation. So this configurations are more strictly checked than other settings; read the document carefully and set it up.

Suppose there is a foundation named Wesoha, and the foundation decided to participate in the Meey network. The foundation establishes three BP nodes, one Agent node, and one node for TX registration and monitoring in the private network. The private address and peer ID of each node are as follows.

```
BP1    : 192.168.25.21 / 16Uiu2HAmH1Eup6qLSQg3Bk7B5QbrVPk6Bzw7upHhZ74ZTS8kM
BP2    : 192.168.25.22 / 16Uiu2HAkzW5j6c6w9BhRnuudHuYc3Kqk4aNi4KbuoaYwVDx3HkS
BP3    : 192.168.25.23 / 16Uiu2HAkvwrouZCrCSG8BqMM1v9GRj11jfjfjfhby5fAXgbCg
Agent  : 192.168.25.31 / 16Uiu2HAm7P7quSBCxPHe89wNUYwCki1M8F45kMMRjw5M6bQdVWEv
Watcher: 192.168.25.32 / 16Uiu2HAkvQYs1e6jVbpAeMfTNpDgUYhxry6gMRQnMAqymVL2Z45
```

The foundation registered the mainnet.wesoha.io domain to join the chain network and forwarded the IP address of the domain to the agent machine.

BPs and Watcher allow access only from the Foundation’s internal network and are linked to the public network only through Agent.

The connection between Agent and client BP is built on the secured environment that the network manager cares about; BP and Agent must specify each other correctly in configuration.

**Configuration of BP Node**

BP disables npexposeself, npdiscoverpeers, and npusewezen settings so that they are not exposed to the outside and do not automatically connect to external nodes. BP node also set agent field to peer id of agent node.

```
# MEEY TOML Configration File (https://github.com/toml-lang/toml)
# base configurations
datadir = "./data"
enableprofile = false
personal = false

[p2p]
npkey = "bp01.key"  # Name of key file of node
npaddpeers = [
    "/ip4/192.168.25.22/tcp/7846/p2p/16Uiu2HAkzW5j6c6w9BhRnuudHuYc3Kqk4aNi4KbuoaYwVDx3HkS",
    "/ip4/192.168.25.23/tcp/7846/p2p/16Uiu2HAkvwrouZCrCSG8BqMM1v9GRj11jfjfjfhby5fAXgbCg",
    "/ip4/192.168.25.31/tcp/7846/p2p/16Uiu2HAm7P7quSBCxPHe89wNUYwCki1M8F45kMMRjw5M6bQdVWEv",
    "/ip4/192.168.25.32/tcp/7846/p2p/16Uiu2HAkvQYs1e6jVbpAeMfTNpDgUYhxry6gMRQnMAqymVL2Z45"
]
npusewezen = false
npexposeself = false    # peer is advertised by wezen or other peers 
npdiscoverpeers = false # peer will not try to discover and connect other peers except for peers listed in npaddpeers
peerrole = "producer"
agent = "16Uiu2HAm7P7quSBCxPHe89wNUYwCki1M8F45kMMRjw5M6bQdVWEv"

[blockchain]
blockchainplaceholder = false
coinbaseaccount = "[ADDRESS OF CONBASE ACCOUNT]"

[mempool]
showmetrics = true
dumpfilepath = "./data/mempool.dump"

[consensus]
enablebp = true
```

**Configuration of Agent Node**

Agent activates npexposeself, npdiscoverpeers, npusewezen settings, and also sets addresses that can be accessed from the outside, so that they can connect to other nodes in the public network. Also set producers field to a list of the client BP’s peer ids and internal zones.

```
# MEEY TOML Configration File (https://github.com/toml-lang/toml)
# base configurations
datadir = "./data"
enableprofile = false
personal = false

[p2p]
netprotocoladdr = "agent.wesoha.com"
npkey = "agent01.key"  # Name of key file of node
npaddpeers = [
    "/ip4/192.168.25.21/tcp/7846/p2p/16Uiu2HAmH1Eup6qLSQg3Bk7B5QbrVPk6Bzw7upHhZ74ZTS8kM",
    "/ip4/192.168.25.22/tcp/7846/p2p/16Uiu2HAkzW5j6c6w9BhRnuudHuYc3Kqk4aNi4KbuoaYwVDx3HkS",
    "/ip4/192.168.25.23/tcp/7846/p2p/16Uiu2HAkvwrouZCrCSG8BqMM1v9GRj11jfjfjfhby5fAXgbCg",
    "/ip4/192.168.25.32/tcp/7846/p2p/16Uiu2HAkvQYs1e6jVbpAeMfTNpDgUYhxry6gMRQnMAqymVL2Z45"
]

npusewezen = true
npexposeself = true    # peer is advertised by wezen or other peers 
npdiscoverpeers = true # peer will not try to discover and connect other peers except for peers listed in npaddpeers
peerrole = "agent"
producers = [
    "16Uiu2HAmH1Eup6qLSQg3Bk7B5QbrVPk6Bzw7upHhZ74ZTS8kM",
    "16Uiu2HAkzW5j6c6w9BhRnuudHuYc3Kqk4aNi4KbuoaYwVDx3HkS",
    "16Uiu2HAkvwrouZCrCSG8BqMM1v9GRj11jfjfjfhby5fAXgbCg"
]
internalzones = ["192.168.25.1/24"]

[blockchain]

[mempool]
showmetrics = true
dumpfilepath = "./data/mempool.dump"

[consensus]
enablebp = false
```

### NTP

Timing is critical in a blockchain, so it’s better to configure the machines’ time setup manually:

```
sudo bash
apt-get install chrony
nano /etc/chrony/chrony.conf
```

```

server time1.google.com iburst
server time2.google.com iburst
server time3.google.com iburst
server time4.google.com iburst
```

```
systemctl restart chronyd
chronyc makestep
```

**Create genesis block**

```
./bin/meeysvr init --genesis /root/.meey/genesis.json --home /root/.
```


# DAO Voting

Decentralized Autonomous Organizations

With Meey network certain parameters of the public mainnet are now subject to a DAO vote. Everyone who has a stake can participate in the voting process, making Meey on-chain governance much more decentralized. What’s more, the Meey foundation decided to sponsor a reward for voting! For every block, one of the voters is chosen, with a probability according to their contribution.

In order to vote, you need to stake at least 10000 Meey.

### 1. System Voting <a href="#id-1-system-voting" id="id-1-system-voting"></a>

1. **BP - Block producers:** This vote determines the block producers that will be assigned in the DPOS consensus algorithm.
2. **BPCOUNT - Block producer count:** This vote determines the number of block producers that will be assigned in the DPOS consensus algorithm
3. **STACKINGMIN - Staking Minimum:** This vote determines the minimum amount (in gas) required for staking.
4. **GASPRICE - Gas Price:** This vote determines the gas price (in gas) used to calculate transaction fees
5. **NAMEPRICE - Name Transaction Price:** This vote determines the amount (in gas) required for name transactions (create and update). Governance transactions are otherwise free, so this fee prevents spam and name squatting.

### 2. Governance Voting <a href="#id-2-governance-voting" id="id-2-governance-voting"></a>

Governance Voting is the new on-chain governance system that aims to be a business-minded DAO and decentralized decision-making framework.

MEEY token holders can participate and contribute in making governing decisions for the MEEY ecosystem through Governance Voting. Governance Voting will be accelerating MEEY to become a democratic, fully self-sustaining and open ecosystem.

### 3. FAQs <a href="#id-3-faqs" id="id-3-faqs"></a>

#### What are the time restrictions for staking and voting? <a href="#what-are-the-time-restrictions-for-staking-and-voting" id="what-are-the-time-restrictions-for-staking-and-voting"></a>

After every action (both staking and voting), you need to wait for 24 hours before being able to do the next action. The only exception is the very first time: one time, you can conduct all of the actions at once. The diagram at the bottom of this page shows an example daily schedule and how it affects your current totals.

#### What is voting power? <a href="#what-is-voting-power" id="what-is-voting-power"></a>

When you cast a vote, it is weighed by your currently staked amount. This is called the power of your vote, or voting power. Your total voting power is the sum of all your votes' power.

#### If I can only do one action per 24 hours, is it better to stake first or vote first? <a href="#if-i-can-only-do-one-action-per-24-hours-is-it-better-to-stake-first-or-vote-first" id="if-i-can-only-do-one-action-per-24-hours-is-it-better-to-stake-first-or-vote-first"></a>

If you want to change your stake, you should do that first to maximize your reward. Your votes are weighed based on your currently staked amount.

#### How are rewards calculated? <a href="#how-are-rewards-calculated" id="how-are-rewards-calculated"></a>

A reward (currently 0.16 meey) is paid out with every block (block rate: 1 second). The winner is selected randomly, with the chance depending on your total voting power in relation to everybody's voting power. Over a longer time period (e.g. 24 hours), your total received reward will be very close to the statistically expected one. In mathematical terms, your expected daily reward is (myTotalVotePower / allVotePower) \* (0.16) \* (60 \* 60 \* 24).

#### When should I increase my stake? <a href="#when-should-i-increase-my-stake" id="when-should-i-increase-my-stake"></a>

If you have additional meey to stake (for example because you received some rewards), it makes sense to increase your stake and vote again to increase your chances of receiving rewards. Your chance will increase roughly by the same percentage that your voting power increased, so you can calculate if it is worth your while.

#### What happens when I decrease my stake (unstake)? <a href="#what-happens-when-i-decrease-my-stake-unstake" id="what-happens-when-i-decrease-my-stake-unstake"></a>

When your stake is decreased, your voting power of your current votes is automatically adjusted. You don't need to vote again.

#### Should I vote for the same vote more than once? <a href="#should-i-vote-for-the-same-vote-more-than-once" id="should-i-vote-for-the-same-vote-more-than-once"></a>

You only need to vote again if you increased your stake or if you changed your mind about the candidate you voted for. If your stake is unchanged, voting again has no effect on your reward.

#### Should I vote for all votes? <a href="#should-i-vote-for-all-votes" id="should-i-vote-for-all-votes"></a>

Yes, your reward is based on your total voting power, which is the sum of all your current votes.

#### How can I know which vote I haven't voted for yet? <a href="#how-can-i-know-which-vote-i-havent-voted-for-yet" id="how-can-i-know-which-vote-i-havent-voted-for-yet"></a>

Check the Votes overview table on your account detail page. The voting power for each vote is the same as your staked balance at the time of voting. If you increased your stake, you can tell from the difference for which votes you already voted again and which you have yet to vote for.

#### What's an example schedule for staking and voting? <a href="#whats-an-example-schedule-for-staking-and-voting" id="whats-an-example-schedule-for-staking-and-voting"></a>

In this example, someone staked 10000 meey on the first day and voted in all votes. Ten days later, they increased their stake by 5000 meey. For the next five days, they update their votes. With every updated vote, the total voting power increases, and thus their chance to win the reward.

![Stacking & Voting Example Schedule](https://gblobscdn.gitbook.com/assets%2F-MFiDsBg9CTnV83GlnkS%2F-MHZmWmuBWlZKWPVa3Mg%2F-MHZnPZeNPoe6pWKh04o%2Fvoting-diagram.png?alt=media\&token=1403decc-274f-4169-a9d0-0eb6e6b8c9dc)


# Platform


# MeyCoin Server

## Using Docker

The easiest way to run a local MeyCoin server is using Docker. An up-to-date Docker image is always available on Docker Hub.

```
$ docker run -p 7845:7845 meycoin/node
```

You can pass arguments to the server like this:

```bash
$ docker run -p 7845:7845 meycoin/node meycoinsvr --testmode
```

To supply your own config file, use:

```bash
$ docker run -p 7845:7845 -v $(pwd)/config.toml:/meycoin/config.toml meycoin/node meycoinsvr --config /meycoin/config.toml
```

## Building from source

*Prerequisites*

* Go1.12.5+ - <https://golang.org/dl>
* CMake 3.0.0 or higher - <https://cmake.org>
* Optional: Protobuffer - <https://github.com/google/protobuf>

### Linux

1.Install dependencies

```bash
sudo apt update
sudo apt upgrade

sudo apt install build-essential libssl-dev m4 -y
```

2.Install CMake

```bash
wget https://github.com/Kitware/CMake/releases/download/v3.17.3/cmake-3.17.3.tar.gz
tar -zxvf cmake-3.17.3.tar.gz
cd cmake-3.17.3
sudo ./bootstrap
sudo make
sudo make install
cmake --version
```

3.Install Go

```bash
wget https://golang.org/dl/go1.15.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.15.linux-amd64.tar.gz

nano ~/.profile

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GOPATH}/src/github.com/meeypioneer/meycoin/libtool/lib

source ~/.profile
```

4.Install MeyCoin Server

```bash
go get -d github.com/meeypioneer/meycoin
cd ${GOPATH}/src/github.com/meeypioneer/meycoin
git submodule init && git submodule update
make
```

### MacOS

1.If you haven’t already, install [homebrew](https://brew.sh/).

2.Install dependencies

```bash
brew install go
brew install cmake  # optional
brew install protobuf  # optional

nano ~/.zshrc

export GOPATH=$HOME/go
export GOROOT="$(brew --prefix golang)/libexec"
export PATH="$PATH:${GOPATH}/bin:${GOROOT}/bin"

source ~/.zshrc
```

3.Set environment

```bash
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GOPATH}/src/github.com/meeypioneer/meycoin/libtool/lib
```

4.Install MeyCoin Server

```bash
go get -d github.com/meeypioneer/meycoin
cd ${GOPATH}/src/github.com/meeypioneer/meycoin
git submodule init && git submodule update
make
```

## Run Server

```bash
./bin/meycoinsvr
```


# Wezen Server

Wezen is a server that provides node discovery for Wezen server.

## Features

* MeyServer nodes can query addresses of other MeyServer nodes. In this case, the chain of the MeyServer node and the chain of Wezen must be the same.
* MeyServer nodes can register itself with Wezen. Wezen checks to see if it can connect to the MeyServer node and adds it to the node list.
* One Wezen server per designated block chain

## Building WEZEN Server

This section describes how to build Wezen from source without using the Docker. Wezen is available as a sub-module in the MEYCOIN project.

1. Get the source from github.com/meeypioneer/meycoin.
2. Build the wezen executable with `make wezen`.

## Configuration

Four files are used to set Wezen behavior.

1. Private key file: PK file to use for Wezen communication. It uses the same format as meycoinsvr private key file.
2. Genesis file: Contains the chain information of nodes to be provided by Wezen. Use the same format as the genesis file used to initialize meycoinsvr.
3. Wezen configuration file: Determines the overall operation of Wezen. It also specifies the path to other configuration related files.
4. Log configuration file: The file name is meeylog.toml, and it uses the same format as the file used by meycoinsvr.

#### Create private key file

It can be generated by meycoincli using the keygen command

```
meycoinocli keygen mychain-wezen
Wrote files mychain-wezen.{key,pub,id}.
```

#### Create genesis file

```
{
    "chain_id":{
        "magic": "mychain.test",
        "public": false,
        "mainnet": false,
        "coinbasefee": "1000000000",
        "consensus": "dpos"
    },
    "timestamp": 1548918000000000000,
    "balance": {
    },
    "bps": [
    ]
}
```

**Wezen configuration file**

```
authdir = "/blockchain/wezen/auth"              # base directory for files about authentication and authorization

[rpc]
netserviceaddr = "127.0.0.1"                # RPC access address. The default setting is 127.0.0.1, which allows RPC access only on the local machine and blocks RPC connections remotely.
netserviceport = 8915

[p2p]
netprotocoladdr = "[real IP address]"      # An externally accessible IP address or domain name
netprotocolport = 8916
npbindaddr = ""
npkey = "mychain-wezen.key"              # Location of private key file

[wezen]
allowprivate = true                        # Whether to allow the private address of the node's access address. Used when building Wezen for private chains operated within a test or private network.
genesisfile = "[location of genesis file]" # Genesis file location
enableblacklist = false                    # Whether to turn on blacklist or not. blacklist entries will be saved in <authdir>
```

**Logging options**

It is possible to customize the log output format of all Meey CLI tools using a file called meeylog.toml placed in the current working directory

```
level = "info"  # default log level
formatter = "json"  # format: console, console_no_color, json
caller = true  # enabling source file and line printer
timefieldformat = "RFC3339"

[chain]
level = "info"  # optional, log level for 'chain' module

[dpos]
level = "info"

[p2p]
level = "info"

[consensus]
level = "info"

[mempool]
level = "info"

[contract]
level = "info"

[syncer]
level = "info"

[bp]
level = "info"
```

## Running Wezen

**Using Docker**

```
docker run -d -w /tools -v /blockchain/wezen:/tools -p 8916:8916 -p 8915:8915 --restart="always" --name wezen-node meey/wezen wezen --home /tools --config /tools/wezen-conf.toml
```

**Manually**

```
./wezen --config wezen-conf.toml
```


# Smart Contracts

Meey provides its own smart contract platform for implementing various business logic on the blockchain.

To create smart contracts for Meey, you can use the [Lua scripting language](http://www.lua.org/about.html).

Lua is a powerful, efficient, lightweight, embeddable scripting language. It has a simple procedural syntax with a powerful data description structure. Lua supports a variety of programming methods: procedural programming, object-oriented programming, functional programming.

We use [LuaJIT 2.1.0](http://luajit.org/luajit.html) as the VM. LuaJIT is a Just-In-Time Compiler (JIT) for the Lua programming language.

You can learn the Lua programming language through the following documents:

* [Lua 5.1 Reference Manual](http://www.lua.org/manual/5.1/)
* [Programming in Lua](http://www.lua.org/pil/) (The second edition was aimed at Lua 5.1)


# Hello World

This is the most basic lua smart contract to store and retrieve states in Meey. You can save a name on the blockchain with the contract call function. And you can print ‘hello …’ with the query function.

```
-- Define global state variables
state.var {
  Name = state.value(),
  My_map = state.map()
}

-- Initialize the state variables
function constructor()
  -- a constructor is called only once at the contract deployment
  Name:set("world")
  My_map["key"] = "value"
end

-- Update the name
-- @call
-- @param name          string: new name
function set_name(name)
  Name:set(name)
end

-- Say hello
-- @query
-- @return              string: 'hello ' + name
function hello()
  return "hello " .. Name:get()
end

-- register functions to expose
abi.register(set_name, hello)
```

This is explained based on using cli. Variables used in this example are

* Account to deploy and execute a contract: AmPPCH5aMeHnaBPJ782UynpdFa612d8runz2zY83P4AcPHqTrhqL
* Cli commands in this page need a meeysvr with enable personal feature

### Check Account and Balance

First, you need an account with enough balance to deploy and execute smart contracts. (If you don’t) Import or Unlock Account to meey server.

### Compile Contract

Copy above code and save it to a file (e.g. helloword.lua). And Compile using the `meeyluac` compiler

```
./bin/meeyluac --payload lua_file_location.lua
```

```
./bin/meeycli contract deploy AmPPCH5aMeHnaBPJ782UynpdFa612d8runz2zY83P4AcPHqTrhqL --payload 37mGLDoCPNDQw7HbCG5WPfcM3E3cLhqhgE2V2UJK
```

### Get receipt of contract

Look up the actual contract address with the transaction ID above.

```
./bin/meeycli receipt get DyJg7jkw7AUT9ZNWyBUhwkR56V2E2HhZMGRSexamsUcJ
{
 "BlockNo": 1745,
 "BlockHash": "9NifJDJSTU9ibXsabRbr1VNxs2YeU6gC6ZMeNbAmCw8Z",
 "contractAddress": "AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB",
 "status": "CREATED",
 "ret": {},
 "txHash": "DyJg7jkw7AUT9ZNWyBUhwkR56V2E2HhZMGRSexamsUcJ",
 "txIndex": 0,
 "from": "AmPPCH5aMeHnaBPJ782UynpdFa612d8runz2zY83P4AcPHqTrhqL",
 "to": "",
 "feeUsed": 4080000000000000,
 "gasUsed": 0,
 "feeDelegation": false,
 "events": []
}
```

If the status is not ‘CREATED’, it may not be included in the block yet, or there may be an error. Wait a while until the transaction is included in the block. Or check the server’s error log.

### Get ABI of contract

Look up ABI of contract with the contract address above.

```
./bin/meeycli contract abi AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB
{
 "version": "0.2",
 "language": "lua",
 "functions": [
  {
   "name": "hello"
  },
  {
   "name": "set_name",
   "arguments": [
    {
     "name": "name"
    }
   ]
  },
  {
   "name": "constructor"
  }
 ],
 "state_variables": [
  {
   "name": "Name",
   "type": "value"
  },
  {
   "name": "My_map",
   "type": "map"
  }
 ]
}
```

### Query Initial State

You can query the generated contract in the following way.

```
./bin/meeycli contract query AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB hello
```

You can see that the name ‘world’ assigned by the constructor is output.

### Call Contract

You can change the name recorded in the block chain as follows:

```
./bin/meeycli contract call AmPPCH5aMeHnaBPJ782UynpdFa612d8runz2zY83P4AcPHqTrhqL AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB set_name '["meeychain"]'
```

### Query Changed State

If you look at the results again, it has changed.

```
./bin/meeycli contract query AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB hello
```

### Query contract variable with merkle proof

#### Value

```
./bin/meeycli contract statequery AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB Name --compressed
```

#### Map

```
./bin/meeycli contract statequery AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB My_map key --compressed
```

#### Array

```
./bin/meeycli contract statequery AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB array_name array_index --compressed
```

By default, the returned state is the one at the latest block, but you may specify any past block’s state root.

```
./bin/meeycli contract statequery AmhTVMdngSCs3xJ5XLAZHm8MGfAdnsNEvWvtpBhRnVky4fbnLZFB var_name --root "9NBSjkcNTdE5ciBxfb52RmsVW7vgX5voRsv6KcosiNjE"
```


# Token Issue

This is an example for token system. It show how to build dApp

```
------------------------------------------------------------------------------
-- Safe maths
------------------------------------------------------------------------------
local M = {}

function M.add(a, b)
    if a == nil then a = 0 end
    if b == nil then b = 0 end

    local c = a + b
    assert(c >= a, "number overflow")

    return c
end

function M.sub(a, b)
    if a == nil then a = 0 end
    if b == nil then b = 0 end

    assert(b <= a, "first value must be bigger than second one")
    local c = a - b

    return c
end

function M.mul(a, b)
    if a == nil then a = 0 end
    if b == nil then b = 0 end

    local c = a * b
    assert(a == 0 or c/a == b, "number overflow")

    return c
end

function M.div(a, b)
    if a == nil then a = 0 end
    if b == nil then b = 0 end

    assert(b > 0, "second value must be bigger than 0")
    c = a / b

    return c
end


Mixer = {}
MixerMetatable = { __index = Mixer }
setmetatable(Mixer, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function Mixer.new(...)
    local r = {}
    for k, v in ipairs{...} do
        r = v.new(r)
    end
    return r
end


Sequence = {}
SequenceMetatable = { __index = Sequence }
setmetatable(Sequence, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function Sequence.new(name)
    return setmetatable({name = 'sequence-' .. name}, SequenceMetatable)
end

function Sequence:next()
    local currentSequence = system.getItem(self.name)
    if (nil == currentSequence) then
        currentSequence = 0
    end
    local nextSequence = currentSequence + 1
    system.setItem(self.name, nextSequence)
    return nextSequence;
end

--- mint.lua
MintService = { }
MintServiceMetatable = { __index = MintService }
setmetatable(MintService, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function MintService.new(parent)
    return setmetatable({ parent = parent },
        MintServiceMetatable)
end

function MintService:totalAmount(assetSymbol)
    if AssetTypes.exists(assetSymbol) then
        local mintInfo = system.getItem('mint-' .. assetSymbol)
        return mintInfo.amount or -1
    else
        return -1
    end
end

function MintService:issue(assetSymbol, amount)
    amount = tonumber(amount)
    assert(0 < amount)
    if not AssetTypes.exists(assetSymbol) then
        AssetTypes.register(assetSymbol)
    end
    local issuer = system.getSender()
    local mintInfo = system.getItem('mint-' .. assetSymbol) or { issuer = issuer, amount = 0 }
    assert(mintInfo.issuer == issuer, 'no authority')

    mintInfo.amount = M.add(mintInfo.amount, amount)
    system.setItem('mint-' .. assetSymbol, mintInfo)

    if self.parent and self.parent.balanceService then
        self.parent.balanceService:receiveFromExternal(issuer, assetSymbol, amount)
    end

end

MintServiceComponent = {}
MintServiceComponentMetatable = { __index = MintServiceComponent }
setmetatable(MintServiceComponent, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function MintServiceComponent.new(o)
    local data = o or {}
    data.mintService = MintService(data)
    return setmetatable(data, MintServiceMetatable)
end

--- balance.lua

BalanceService = { }
BalanceServiceMetatable = { __index = BalanceService }
setmetatable(BalanceService, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function BalanceService.new(parent)
    return setmetatable({ parent = parent }, BalanceServiceMetatable)
end

function BalanceService:getAmount(address, assetSymbol)
    assert(nil ~= address)
    local account = system.getItem('account-' .. address)
    if nil == account then
        return 0
    else
        return account[assetSymbol] or 0
    end
end

function BalanceService:receiveFromExternal(receiverAddress, assetSymbol, amount)
    amount = tonumber(amount)
    local receiverAccount = system.getItem('account-' .. receiverAddress) or { balance = 0 }
    assert(0 < amount)
    assert(nil ~= receiverAddress)
    local key = assetSymbol
    receiverAccount[key] = M.add(receiverAccount[key] or 0, amount)

    system.setItem('account-' .. receiverAddress, receiverAccount)

    if nil ~= self.parent and nil ~= self.parent.historyService then
        local tx = Transaction(2, nil, receiverAddress, assetSymbol, amount)
        self.parent.historyService:record(tx)
    end
end

function BalanceService:transfer(receiverAddress, assetSymbol, amount)
    amount = tonumber(amount)
    local senderAddress = system.getSender()
    local senderAccount = system.getItem('account-' .. senderAddress)
    local receiverAccount = system.getItem('account-' .. receiverAddress) or { balance = 0 }

    assert(0 < amount)
    assert(nil ~= receiverAddress)
    assert(nil ~= senderAccount)
    local key = assetSymbol
    assert(amount <= senderAccount[key], 'insufficient balance')
    senderAccount[key] = M.sub(senderAccount[key] or 0, amount)
    receiverAccount[key] = M.add(receiverAccount[key] or 0, amount)

    system.setItem('account-' .. senderAddress, senderAccount)
    system.setItem('account-' .. receiverAddress, receiverAccount)

    if nil ~= self.parent and nil ~= self.parent.historyService then
        local tx = Transaction(1, senderAddress, receiverAddress, assetSymbol, amount)
        self.parent.historyService:record(tx)
    end
end


BalanceServiceComponent = {}
BalanceServiceComponentMetatable = { __index = BalanceServiceMetatable }
setmetatable(BalanceServiceComponent, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function BalanceServiceComponent.new(o)
    local data = o or {}
    data.balanceService = BalanceService(data)
    return setmetatable(data, BalanceServiceComponentMetatable)
end


Transaction = { }
TransactionMetatable = { __index = Transaction }
setmetatable(Transaction, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function Transaction.new(type, sender, receiver, assetType, amount)
    setmetatable({
        type = type,
        sender = sender,
        receiver = receiver,
        assetType = assetType,
        amount = amount
    }, TransactionMetatable)
end


HistoryService = {}
HistoryServiceMetatable = { __index = HistoryService }
setmetatable(HistoryService, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})
function HistoryService.new(parent)
    return setmetatable(
        { parent = parent, sequence = Sequence('history') },
        HistoryServiceMetatable)
end

function HistoryService:record(transaction)
    system.setItem('history-' .. self.sequence:next(), transaction)
end

HistoryServiceComponent = {}
HistoryServiceComponentMetatable = { __index = HistoryServiceComponent }
setmetatable(HistoryServiceComponent, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

function HistoryServiceComponent.new(o)
    local data = o or {}
    data.historyService = HistoryService(data)
    return setmetatable(data, HistoryServiceComponentMetatable)
end
--- asset.lua
AssetType = { }
AssetTypeMetatable = { __index = AssetType }
setmetatable(AssetType, {
    __call = function(cls, ...)
        return cls.new(...)
    end
})

AssetTypes = {}

function AssetTypes.exists(symbol)
  return nil ~= system.getItem('symbol-' .. symbol)
end

function AssetTypes.register(symbol)
    assert(not AssetTypes.exists(symbol))
    system.setItem('symbol-' .. symbol, symbol)
end




local tokenSystem = Mixer(MintServiceComponent, BalanceServiceComponent, HistoryServiceComponent)

function constructor()
	tokenSystem.mintService:issue('bds1-token', 300000000)
end

function transfer(receiver, amount)
	tokenSystem.balanceService:transfer(receiver, 'bds1-token', amount)
end

function getAmount(address)
	return tokenSystem.balanceService:getAmount(address, 'bds1-token')
end

abi.register(transfer, getAmount)
```


