├── .gitignore
├── BankofStaked-logo.png
├── LICENSE
├── Order-Process-of-BankofStaked.svg
├── README-CN.md
├── README-KR.md
├── README.md
├── _config.yml
├── build.sh
├── cpu-emergency
├── Centralized-CPU-Emergency.svg
├── README.md
├── eoslive.png
└── meetone.jpeg
├── doc
├── BankofStaked-Creditor-Resource-Guide.md
├── BankofStaked-Creditor-Term-CN.md
└── BankofStaked-Creditor-Term-EN.md
├── include
└── bankofstaked
│ └── bankofstaked.hpp
├── rc
└── bankofstaked.ricardian.clauses.md
├── scripts
├── add_creditor.sh
├── bank_perm.sh
├── creditor_perm.sh
├── dev.sh
├── dev
│ ├── check.sh
│ ├── deploy.sh
│ └── spammer.sh
├── empty.sh
├── get_table.sh
├── order_perm.sh
└── set_plan.sh
├── src
├── bankofstaked.cpp
├── lock.cpp
├── safedelegatebw.hpp
├── utils.cpp
└── validation.cpp
├── stats
├── fetch.py
└── requirements.txt
├── tests
├── CMakeLists.txt
├── LICENSE
├── README.md
├── UnitTestsExternalProject.txt
├── build.sh
├── clean-build.sh
├── faketransfer
│ ├── build.sh
│ └── faketransfer.cpp
└── tests
│ ├── CMakeLists.txt
│ ├── bankofstaked_tester.hpp
│ ├── bankofstaked_tests.cpp
│ ├── contracts.hpp.in
│ ├── eosio.system_tester.hpp
│ ├── main.cpp
│ ├── test_contracts
│ ├── eosio.msig
│ │ ├── eosio.msig.abi
│ │ └── eosio.msig.wasm
│ ├── eosio.system
│ │ ├── eosio.system.abi
│ │ └── eosio.system.wasm
│ └── eosio.token
│ │ ├── eosio.token.abi
│ │ └── eosio.token.wasm
│ └── test_symbol.hpp
└── unittest.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | *.wasm
2 | *.wast
3 | *.abi
4 | build
5 | tests/build
6 |
--------------------------------------------------------------------------------
/BankofStaked-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EOSLaoMao/BankofStaked-CE/3b764debe9bad8047c0cf28930b91b7a736a09d6/BankofStaked-logo.png
--------------------------------------------------------------------------------
/README-CN.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Bank of Staked
7 | CPU&NET 自助租赁合约
8 |
9 |
10 |
11 | English README
12 |
13 | 한국의 README
14 |
15 | ### 关于
16 | BankofStaked 智能合约旨在向 EOS 用户和开发者提供便捷的 CPU 和 NET 资源租赁服务。
17 |
18 | 该合约由 `EOSLaoMao` 团队开发。
19 |
20 | ### 设计思路
21 |
22 |
23 | BankofStaked 的设计初衷,是希望提供便捷的 CPU 和 NET 自助租赁体验。用户只需要向 BankofStaked 合约发送一笔符合要求的 EOS 转账,即可完成 CPU 和 NET 资源的租赁,并且,在租赁到期之后,合约也将自动取消 CPU 和 NET 的抵押,实现完全的自动化。你可以把它视为一台 CPU & NET 资源的自动贩卖机。
24 |
25 | BankofStaked 合约的主要业务逻辑由下面 3 张数据表(table)构成:
26 |
27 | #### 1. Plan 表
28 |
29 | Plan 用于存储 BankofStaked 合约目前可用的价格方案,其主要字段如下:
30 |
31 | ```
32 | price asset; // 价格(单位为 EOS)
33 | cpu asset; // 该价格下提供的 CPU(单位为 EOS)
34 | net asset; // 该价格下提供的 NET(单位为 EOS)
35 | duration unit64; // 服务有效期(单位为分钟)
36 | is_free uint64; // 服务是否免费,如果 is_free 字段为 1, 用户转入 BankofStaked 合约的 EOS 将瞬间自动返还
37 | ...
38 | ```
39 |
40 | #### 2. Creditor 表
41 |
42 |
43 |
44 | `Creditor` 表存储的是真正给用户提供 CPU 和 NET 抵押的账户。
45 |
46 | 当合约收到符合条件的 EOS 转账的时候,合约将从 `Creditor` 表中查找符合条件的“贷出人”账户,该账户将自动为用户抵押相应的 CPU 和 NET 资源。在服务到期之后,“贷出人”账户也将自动解除这笔抵押。
47 |
48 | ```
49 | account account_name;
50 | is_active uint64;
51 | ...
52 | ```
53 |
54 | `is_active` 字段表示该“贷出人”账户是否提供租赁服务。
55 |
56 | 在生产环境中,`Creditor` 表中应该提供多位“贷出人”,并采用合适的轮换策略,以保证非活跃的贷出人账户中解除抵押尚未到账的 EOS 及时到账。
57 |
58 | #### 3. Order 表
59 |
60 | Order 表存储的,是服务还在有效期内的订单。其主要字段如下:
61 |
62 | ```
63 | buyer account_name;
64 | creditor account_name;
65 | beneficiary account_name;
66 | cpu_staked asset;
67 | net_staked asset;
68 | expire_at uint64;
69 | ...
70 | ```
71 |
72 | `buyer` 存储的是下单账户,也就是向 BankofStaked 合约转账 EOS 购买租赁服务的账户。(如果有退款发生,退款也将返还给 `buyer` 账户)
73 |
74 | `beneficiary` 存储的是该订单真正的受益账户,`buyer` 可以在转账的 memo 中指定受益账户,未指定的话,`beneficiary` 跟 `buyer` 相同。
75 |
76 | `creditor` 存储的是真正给 `beneficiary` 做抵押的“贷出人”账户。
77 |
78 | `cpu_staked` 和 `net_staked` 记录了抵押的 CPU 和 NET 的多少。
79 |
80 | `expire_at` 表示租赁服务的过期时间,到期后,订单记录将被自动删除。
81 |
82 |
83 | 除了上述的 3 张主要的数据表以外,还有一些辅助的数据表,比如:
84 |
85 | `freelock` 表,用来给免费的 Plan 加锁,防止单一用户滥用。
86 |
87 | `history` 表,用来记录过期之后被删除的历史订单。
88 |
89 | `blacklist` 表,用于管理黑名单,禁止特定用户使用租赁服务。
90 |
91 | 
92 |
93 |
94 | # EOS 主网上的 BankofStaked 合约
95 |
96 | ### 如何使用
97 |
98 | 我们已经将 BankofStaked 合约部署在了 EOS 主网,以及 Kylin 和 Jungle 测试网络:
99 |
100 | EOS 主网:https://www.myeoskit.com/#/tx/bankofstaked
101 |
102 | Jungle 测试网:https://jungle.bloks.io/account/bankofstaked
103 |
104 | Kylin 测试网:https://kylin.bloks.io/account/bankofstaked
105 |
106 |
107 |
108 | #### 第一步:查询可用的价格方案
109 |
110 | 查询 `Plan` 表,获取当前可用的价格方案:
111 |
112 |
113 | ```
114 | cleos -u https://api1.eosasia.one get table bankofstaked bankofstaked plan
115 |
116 | {
117 | "rows": [{
118 | "id": 0,
119 | "price": "0.1000 EOS",
120 | "is_free": "1",
121 | "cpu": "1.0000 EOS",
122 | "net": "0.0000 EOS",
123 | "duration": 60,
124 | "created_at": 1535965927,
125 | "updated_at": 1535965927
126 | },
127 | ],
128 | "more": false
129 | }
130 | ```
131 |
132 | `price` 表示你需要转给 `bankofstaked` 的 EOS,`cpu` and `net` 表示该价格下,你将获得的 CPU 和 NET 资源,`duration` 表示租赁期限,单位为分钟。
133 |
134 | `is_free` 表示该价格计划是否免费(用户成功购买免费的价格计划之后,会立即获得全额的退款)
135 |
136 | 我们将很快提供更多的价格方案。
137 |
138 | #### 第二步:转账购买 CPU&NET 资源
139 |
140 |
141 | 目前 BankofStaked 在 EOS 主网上暂只提供 1 个免费计划。你可以向 `bankofstaked` 账户转账 `0.1 EOS` 立即获得 `1 EOS` 的 CPU 抵押一小时服务。并且 `0.1 EOS` 的转账也将被合约瞬间返还。
142 |
143 | 你可以直接通过 EOS 钱包进行转账,也可以使用命令行的方式:
144 |
145 | ```
146 | cleos -u https://api1.eosasia.one transfer 你的账户 bankofstaked "0.1 EOS" -p 你的账户@active
147 | ```
148 |
149 |
150 | 转账成功后,你将立即获得全额的返还,并且立即获得 `1 EOS` CPU 的抵押。一个小时之后,该抵押将自动解除。(注:同一个账户每 24 个小时,只能购买一次免费服务)
151 |
152 |
153 |
154 | ---
155 |
156 | 如果你是 BP 或者 EOS 持有者,想要跟我们一起向用户提供免费的救急抵押服务,或者向开发者提供租赁服务,欢迎联系我们:contact@eoslaomao.com
157 |
158 |
159 | built with love by EOSLaoMao Team. :)
160 |
161 | Icon made by Freepik from www.flaticon.com, special thanks~
162 |
--------------------------------------------------------------------------------
/README-KR.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Bank of Staked
7 | a self-serve CPU&NET Vending Machine
8 |
9 |
10 | English README
11 |
12 | 中文版 README
13 |
14 |
15 | ### Bank of Staked 에 대해서
16 | 뱅크 오브 스테이크 (Bank of Staked)는 EOS 사용자와 개발자 모두에게 값싼 CPU 및 NET 리스를 제공하기 위해 EOSLaoMao 팀이 작성한 EOS 스마트 컨트랙트입니다.
17 |
18 |
19 | ### Design
20 |
21 | Bank of Staked의 UX는 모든 계정이 간단한 과정을 통해 CPU 와 NET을 자동으로 위임 받을 수 있게 하는 목표를 달성하고자 합니다. 이러한 목표에는 취소 프로세스의 자동실행도 포함됩니다.
22 |
23 | 스테이크 뱅크의 주요 로직은 다음 세 테이블을 통해 실현됩니다:
24 |
25 | #### 1. Plan Table(계획 테이블)
26 |
27 | 계획 테이블은 사용자가 선택할 수 있는 모든 사용가능한 계획을 보유하고 있으며, 주요 필드는 다음과 같습니다:
28 |
29 | ```
30 | price asset; //plan price
31 | cpu asset; // delegated cpu this plan offers.
32 | net asset; // delegated net this plan offers.
33 | duration unit64; //the period of time service gonna last, in minutes.
34 | is_free uint64; //free plan or not, if is_free is 1, order will be auto refunded.
35 | ...
36 | ```
37 |
38 | #### 2. Creditor Table (채권자 테이블)
39 |
40 | 채권자는 CPU 와 NET을 위임해주고 위임 받는 실제 주인들입니다. 유효한 양도 거래가 이루어지면 스마트 컨트랙트는 `is _active` 채권자를 찾아 해당 채권자의 계좌를 통해 자동으로 자원을 위임합니다.
41 |
42 |
43 | ```
44 | account account_name;
45 | is_active uint64;
46 | ...
47 | ```
48 |
49 | `is_active`는 채권자가 위임을 할 준비가 되어있는지 알려줍니다.
50 |
51 | 프로덕션 환경에서는 채권자가 항상 3일 기준으로 바뀌게 하여 비활성화 상태인 채권자에게도 토큰을 돌려줄 수 있도록 합니다.
52 |
53 | #### 3. Order Table (주문 테이블)
54 |
55 | 주문 테이블은 활성 주문 기록으로 구성되며, 활성이라는 것은 만료되지 않은 주문을 말합니다.
56 |
57 | ```
58 | buyer account_name;
59 | creditor account_name;
60 | beneficiary account_name;
61 | cpu_staked asset;
62 | net_staked asset;
63 | expire_at uint64;
64 | ...
65 | ```
66 |
67 | 구매자는 처음에 이체를 실제로 실행한 계정입니다. 환불 거래가 발생하면 토큰도 구매자 계정으로 환급됩니다.
68 |
69 | 수혜자는 CPU 와 NET을 실제로 위임받는 계정입니다. 구매자는 원하는 경우에 이 계좌를 송금 메모에 지정할 수 있습니다.
70 |
71 | 채권자는 토큰을 위임한 계좌입니다.
72 |
73 | `cpu_staked` 와 `net_staked`는 이 순서대로 위임된 CPU 와 NET을 말합니다.
74 |
75 | `expire_at` 은 주문이 만료되는 시기입니다. 주문이 만료되면 주문 기록이 주문 표에서 삭제됩니다.
76 |
77 |
78 | 이 계약을 용이하게 하는 다른 몇 가지 표가 더 있습니다. 예를 들어,
79 |
80 | 24시간 동안 각 계정의 무료 계획을 잠그는 데 사용되는 `freelock` table 이 있고,
81 |
82 | 이미 삭제된 만료된 주문의 메타 데이터를 저장하는 데 사용되는 `history` table,
83 |
84 | Bank of Staked에 특정 계정을 블랙리스트 할 수 있는 `blacklist`가 있습니다.
85 |
86 |
87 | 
88 |
89 |
90 | # Bank of Staked on Mainnet
91 |
92 | ### How to use it
93 |
94 | 저희는 Banked of Staked를 메인넷에 올렸고, 아래의 링크에서 확인하실 수 있습니다:
95 |
96 | https://www.myeoskit.com/#/tx/bankofstaked
97 |
98 |
99 | #### 1.Check available price plan
100 |
101 | 계획 테이블 쿼리를 통해 이용 가능한 계획 확인:
102 |
103 | ```
104 | cleos -u https://api1.eosasia.one get table bankofstaked bankofstaked plan
105 |
106 | {
107 | "rows": [{
108 | "id": 0,
109 | "price": "0.1000 EOS",
110 | "is_free": "1",
111 | "cpu": "1.0000 EOS",
112 | "net": "0.0000 EOS",
113 | "duration": 60,
114 | "created_at": 1535965927,
115 | "updated_at": 1535965927
116 | },
117 | ],
118 | "more": false
119 | }
120 | ```
121 |
122 | 가격은 `duration`(특정 기간/분)동안 특정 `CPU`와 `NET`을 얻기 위해 `bankofstaked`로 전송해야 하는 EOS를 나타냅니다.
123 |
124 | `is_free` 는 환불을 받을 수 있는지 알려줍니다 (환불이 적용되었다면 바로 진행됩니다).
125 |
126 | 현재 우리는 1개의 무료 계획(plan)을 제공하고 있습니다: `0.1 EOS`를 `60 min of 1 EOS CPU`에 스테이킹하면, 전송 후 0.1 EOS를 바로 환불받으실 수 있습니다.
127 |
128 | 다른 계획들이 빠른 시일 내에 추가될 것입니다.
129 |
130 | #### 2.EOS를 전송하고 위임받으세요!
131 |
132 | `bankofstaked`에 `0.1 EOS`를 전송하면, 스테이크된 `1 EOS`의 `cpu`를 `60 minutes`(60 분) 동안 이용하실 수 있습니다.
133 |
134 | 노트: `bankofstaked`는 시간이 되면 자동으로 토큰을 환급합니다.
135 |
136 |
137 |
138 | ```
139 | cleos -u https://api1.eosasia.one transfer YOUR_ACCOUNT bankofstaked "0.1 EOS" -p YOUR_ACCOUNT@active
140 | ```
141 |
142 | 0.1EOS를 전송하면, 1 EOS의 CPU를 위임받을 수 있고, 60분 후에 지연 거래를 사용하여 자동으로 환급이 진행됩니다.
143 | 토큰을 전송한 후, `1 EOS of CPU`를 위임받을 수 있고, 60분 후에, 지연 거래(deferred transaction)를 사용하여 자동으로 환급이 진행됩니다.
144 |
145 | ---
146 |
147 | 당신이 EOS 채권자 기금에 기부하고자 하는 경우 (위임, 양도는 필요하지 않음), 또는 BP와 사용자들과 개발자들을 도울 의사가 있다면 contact@eoslaomao.com으로 문의해주세요.
148 |
149 | EOSLaoMao 팀이 사랑으로 개발했습니다. :)
150 |
151 | 아이콘은 www.flaticon.com의 Freepik이 만들었습니다, 감사의 말씀 전합니다~
152 |
153 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Bank of Staked
7 | a self-serve CPU&NET Vending Machine
8 |
9 |
10 | 中文版 README
11 |
12 | 한국의 README
13 |
14 | ### About
15 | Bank of Staked is an EOS smart contract aiming to provide cheap CPU&NET lease to both EOS users and developers. This contract is build by `EOSLaoMao Team`.
16 |
17 | Bank of Staked is now live on EOS Mainnet providing 1 free emergency plan and 3 paid plans. With 20+ block producers providing free creditors, free emergency plan is now able to servce 20K EOS accounts simultaneously.
18 |
19 | Check it out: https://eoslaomao.com/bankofstaked
20 |
21 | For more details, check announcement here: https://steemit.com/eos/@eoslaomao/announcing-bankofstaked-a-self-serve-cpu-and-net-resource-vending-machine-supported-by-block-producers
22 |
23 | ### Design
24 |
25 | The user experience Bank of Staked wants to achieve is that any account could get CPU&NET delegated automatically through a simple transfer, no more action needed. And the undelegate process will also be triggered automatically.
26 |
27 | The main logic of Bank of Staked are realized through the following three tables:
28 |
29 | #### 1. Plan Table
30 |
31 | Plan table holds all available plans user can choose, main fields are:
32 |
33 | ```
34 | price asset; //plan price
35 | cpu asset; // delegated cpu this plan offers.
36 | net asset; // delegated net this plan offers.
37 | duration unit64; //the period of time service gonna last, in minutes.
38 | is_free uint64; //free plan or not, if is_free is 1, order will be auto refunded.
39 | ...
40 | ```
41 |
42 | #### 2. Creditor Table
43 |
44 | `Creditors` are the actual accounts who delegate and undelegate. When a valid transfer happens, the contract will try to find `active` creditor to do an auto delegation using that creditor account.
45 |
46 | ```
47 | account account_name;
48 | is_active uint64;
49 | ...
50 | ```
51 |
52 | `is_active` indicates if this creditor is ready to serve new orders.
53 |
54 | in production, you should always have creditors shifting like X days in a roll(X depends on plans it provide), so that non-active creditors have enough time to get their undelegated token back.
55 |
56 | #### 3. Order Table
57 |
58 | Order table consists of active order records, by active, it means these orders are not expired.
59 |
60 | ```
61 | buyer account_name;
62 | creditor account_name;
63 | beneficiary account_name;
64 | cpu_staked asset;
65 | net_staked asset;
66 | expire_at uint64;
67 | ...
68 | ```
69 |
70 | `buyer` is the account who did the actual transfer in the first place, if any refund happens, token will be refunded to `buyer` account also.
71 |
72 | `beneficiary` is the actual account who get cpu and net delegated. `buyer` can specify this account in transfer memo if he/she like.
73 |
74 | `creditor` is the account who did delegation.
75 |
76 | `cpu_staked` and `net_staked` is CPU&NET delegated in this order.
77 |
78 | `expire_at` is when this order will expire. After order expired, order record will be deleted from Order Table.
79 |
80 |
81 | There are also several other tables facilitating this contract. such as,
82 |
83 | `freelock` table, used to lock free plan for each account for 24 hours.
84 |
85 | `history` table, used to store meta data of deleted expired order.
86 |
87 | `blacklist`, used to blacklist certain account from using `bankofstaked` contract.
88 |
89 |
90 | 
91 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | IMAGE=eoslaomao/eos-dev:1.4.0
3 | NAME=bankofstaked
4 | FOLDER=bankofstaked
5 |
6 | docker ps | grep $NAME-eos-dev
7 | if [ $? -ne 0 ]; then
8 | echo "Run eos dev env "
9 | docker run --name $NAME-eos-dev -dit --rm -v `(pwd)`:/$NAME $IMAGE
10 | fi
11 |
12 | docker exec $NAME-eos-dev eosio-cpp --contract bankofstaked \
13 | -abigen /$NAME/src/$NAME.cpp -o $NAME.wasm \
14 | -I /contracts/eosio.token/include \
15 | -I /contracts/eosio.system/include \
16 | -R /$NAME/rc/bankofstaked.ricardian.clauses.md
17 | docker exec $NAME-eos-dev cp /$NAME.abi /$NAME.wasm /$NAME/
18 |
19 | if [ -d build ]; then
20 | rm -rf build
21 | fi
22 |
23 | mkdir build
24 | echo "Create build dir!!"
25 |
26 | mv $NAME.abi ./build
27 | mv $NAME.wasm ./build
28 | echo "Build SUCCESS!!!"
29 |
30 | # For test and debug
31 | docker exec nodeosd mkdir /$NAME
32 | docker cp ./build/$NAME.abi nodeosd:/$NAME/
33 | docker cp ./build/$NAME.wasm nodeosd:/$NAME/
34 | docker cp scripts nodeosd:/
35 |
36 | #run unit test
37 | docker exec $NAME-eos-dev /bankofstaked/unittest.sh
38 |
--------------------------------------------------------------------------------
/cpu-emergency/Centralized-CPU-Emergency.svg:
--------------------------------------------------------------------------------
1 | Centralized Server Users run out of CPU CPU run out? END Call BankofStaked User got free CPU END AVOID SPAMMING Determine CPU of submitted account ran out or not YES use account in WHITELIST to claim free plan using BankofStaked for qualified account. 0.8 EOS staked for CPU 0.2 EOS staked for NET for 8 hours Centralized CPU emergency using Bank of Staked NO
--------------------------------------------------------------------------------
/cpu-emergency/README.md:
--------------------------------------------------------------------------------
1 | # CPU Emergency Document
2 |
3 | BankofStaked provides a mechanism called `whitelist` to enable centralized CPU emergency service. MEET.ONE and EOS.LIVE wallet have already developed CPU emergency services using this feature.
4 |
5 | This document is a guide to develop a centralized CPU emergency service for wallets/tools.
6 |
7 | # How it works
8 |
9 | Here is a diagram showing how it works:
10 |
11 | 
12 |
13 | The grey part of the diagram should be provided by wallets/tools who wants to provide centralized CPU emergency service.
14 |
15 | details of the requirements are:
16 |
17 |
18 | 1. a frontend for users in your wallet/tool for users to submit accounts.
19 | 2. an API to submit account with proper anti-spamming setup.
20 | 3. an EOS account provided to `bankofstaked` which will be added to `whitelist` with a proper `capacity`. you can reach out to contact@eoslaomao.com for details.
21 |
22 | for part one, here are frontend examples provided by MEET.ONE and EOS.LIVE:
23 |
24 | 
25 |
26 | 
27 |
--------------------------------------------------------------------------------
/cpu-emergency/eoslive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EOSLaoMao/BankofStaked-CE/3b764debe9bad8047c0cf28930b91b7a736a09d6/cpu-emergency/eoslive.png
--------------------------------------------------------------------------------
/cpu-emergency/meetone.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EOSLaoMao/BankofStaked-CE/3b764debe9bad8047c0cf28930b91b7a736a09d6/cpu-emergency/meetone.jpeg
--------------------------------------------------------------------------------
/doc/BankofStaked-Creditor-Resource-Guide.md:
--------------------------------------------------------------------------------
1 | # BankofStaked Creditor Resource Guide
2 |
3 |
4 |
5 | ## RAM
6 |
7 | ### free creditor
8 |
9 | `
10 | RAM = (liquid_balance) * 0.16 (kb)
11 | `
12 |
13 | eg. creditor account with 1000 liquid EOS should also have 160kb unused RAM in this account initially.
14 |
15 |
16 | ### paid creditor
17 |
18 | `
19 | RAM = (liquid_balance) * 0.12 / 30 (kb)
20 | `
21 |
22 | *30 is the minimum EOS quanity for each paid order.
23 |
24 | eg. creditor account with 10000 liquid EOS should also have 40kb unused RAM in this account initially.
25 |
26 |
27 | # CPU
28 |
29 | This is a tricky one. You have to make sure your creditor account has enough CPU for auto-undelegation, otherwise auto-undelegation will not be executed. Good news is BankofStaked has a built-in passive check to make sure to trigger undelegation again and again.
30 |
31 |
32 |
33 | # Current creditor resource status
34 |
35 | Here is the creditor RAM resource summary, please purchase enough ram for your account according to this chart if your account has no enough RAM.
36 |
37 |
38 | ## FREE CREDITORS
39 |
40 | | Account | Balance | RAM Owned(kb) | RAM Requird(kb) | Enough RAM? |
41 | | ------- | ------- | --------- | ----------- | ----------- |
42 | | acroeosrndev | 500.0023 EOS | 42.54 | 80.00 | ❌ |
43 | | bankofeosys2 | 300.1019 EOS | 4.83 | 48.02 | ❌ |
44 | | bankofstkarg | 500.0024 EOS | 86.75 | 80.00 | ✅ |
45 | | bosauthority | 89.0118 EOS | 11.03 | 14.24 | ❌ |
46 | | cannonstaked | 200.0020 EOS | 32.30 | 32.00 | ✅ |
47 | | charity.bank | 10100.0026 EOS | 200.82 | 1616.00 | ❌ |
48 | | dublinstaked | 506.0017 EOS | 79.02 | 80.96 | ❌ |
49 | | eos42reserve | 8520.0052 EOS | 7.96 | 1363.20 | ❌ |
50 | | eosasia.bp | 498.0027 EOS | 88.40 | 79.68 | ✅ |
51 | | eosbeijinghp | 100.0028 EOS | 58.34 | 16.00 | ✅ |
52 | | eosbixinbank | 500.0025 EOS | 89.23 | 80.00 | ✅ |
53 | | eoscafestake | 994.8943 EOS | 168.52 | 159.18 | ✅ |
54 | | eoseco.bp | 951.0023 EOS | 635.15 | 152.16 | ✅ |
55 | | eosgravitygo | 100.0024 EOS | 9.32 | 16.00 | ❌ |
56 | | eospacestake | 100.2025 EOS | 16.90 | 16.03 | ✅ |
57 | | eosriobrfree | 405.0016 EOS | 7.51 | 64.80 | ❌ |
58 | | eostribefree | 102.0017 EOS | 11.32 | 16.32 | ❌ |
59 | | freestakeswe | 1004.0016 EOS | 319.76 | 160.64 | ✅ |
60 | | fundstostake | 12.9024 EOS | 71.78 | 2.06 | ✅ |
61 | | jedaaastaked | 367.3101 EOS | 84.05 | 58.77 | ✅ |
62 | | meetone1free | 500.0010 EOS | 103.89 | 80.00 | ✅ |
63 |
64 |
65 | ## PAID CREDITORS
66 | | Account | Balance | RAM Owned(kb) | RAM Requird(kb) | Enough RAM? |
67 | | ------- | ------- | --------- | ----------- | ----------- |
68 | | bankofeosys1 | 1026.2817 EOS | 10.53 | 4.11 | ✅ |
69 | | cyberneticsx | 4470.5650 EOS | 24.30 | 17.88 | ✅ |
70 | | dublinsaving | 20000.9284 EOS | 4865.03 | 80.00 | ✅ |
71 | | eosbeijingbk | 1062.1522 EOS | 13.17 | 4.25 | ✅ |
72 | | eosriostaked | 14159.9581 EOS | 10.20 | 56.64 | ❌ |
73 | | eostribecred | 1014.1014 EOS | 11.32 | 4.06 | ✅ |
74 | | jedacreditor | 40021.5302 EOS | 113.82 | 160.09 | ❌ |
75 | | paidstakeswe | 13161.7804 EOS | 319.76 | 52.65 | ✅ |
76 | | serenityhome | 13247.9882 EOS | 108.11 | 52.99 | ✅ |
77 | | staking.bank | 34551.5327 EOS | 173.50 | 138.21 | ✅ |
78 | | stakingfunda | 19195.5208 EOS | 129.28 | 76.78 | ✅ |
79 | | stakingfundb | 10195.8706 EOS | 119.57 | 40.78 | ✅ |
80 | | stakingfundc | 10167.2706 EOS | 119.57 | 40.67 | ✅ |
81 | | stakingfundd | 30172.1106 EOS | 119.57 | 120.69 | ❌ |
82 | | stakingfunde | 10189.1007 EOS | 119.57 | 40.76 | ✅ |
83 | | stakingfundf | 20432.8848 EOS | 119.57 | 81.73 | ✅ |
84 | | stakingfundg | 10248.2183 EOS | 119.57 | 40.99 | ✅ |
85 | | stakingfundh | 10174.4407 EOS | 119.57 | 40.70 | ✅ |
86 | | stakingfundi | 17153.0407 EOS | 119.57 | 68.61 | ✅ |
87 | | sxzzsxzzsxz1 | 151002.7887 EOS | 116.50 | 604.01 | ❌ |
88 | | sxzzsxzzsxzz | 101917.5803 EOS | 110.92 | 407.67 | ❌ |
89 |
--------------------------------------------------------------------------------
/doc/BankofStaked-Creditor-Term-CN.md:
--------------------------------------------------------------------------------
1 | # BankofStaked Creditor 公开计划
2 |
3 | ## 关于 BankofStaked
4 |
5 | BankofStaked 是由 EOSLaoMao 团队开发并维护的一款 EOS 资源自助租赁智能合约([https://eoslaomao.com/bankofstaked](https://eoslaomao.com/bankofstaked))。
6 | 该合约巧妙地利用 EOS 权限系统,实现了无需转币,零资金风险,且不影响投票权的自动租赁功能。
7 |
8 | BankofStaked 上线两个月以来(2018 年 10 月正式上线),已经累计自动完成了 40,000 多笔订单,累计自动贷出 3,000,000 EOS。同时,BankofStaked 还联合了 EOS 社区的 27 个 BP 向用户提供免费的 CPU 救急计划。截至目前,BankofStaked 已经给超过 30,000 个 EOS 账户提供了免费救急服务。MEET.ONE, imToken, EOS.LIVE 等钱包工具也已经接入该功能。
9 |
10 | ### Creditor 开放计划
11 |
12 | 随着 EOS 生态的发展,BankofStaked 的业务量迅速增长,BankofStaked 目前的存量 EOS 已经无法满足日益增长的业务需求。为此我们现将 BankofStaked 的 Creditor 功能向 EOS 社区限量开放。
13 |
14 | 第一期开放额度为 100 万 EOS,满额即止。由于 Creditor 账户的设置需要一定的 cleos 命令行工具基础,请务必评估风险后,自行决定是否参与。由于自己操作或设置不当导致的问题,BankofStaked 概不负责。
15 |
16 | Creditor 定义: 经 BankofStaked 团队审核通过,加入到 BankofStaked 出租池,通过 BankofStaked 智能合约自动出租 EOS 获取收益的 EOS 账户。
17 |
18 |  友情提醒:BankofStaked 不会以任何名义让 Creditor 向我方进行转账,请知悉。
19 |
20 | ### Creditor 要求
21 |
22 | 1. 有一个独立的 EOS 账户用做 Creditor,且账户余额大于 20,000 EOS。
23 | 2. 该 Creditor 账户需部署 BankofStaked 提供的安全抵押合约(详情参见:[SafeDelegatebw](https://github.com/EOSLaoMao/SafeDelegatebw))。
24 | 3. 该 Creditor 账户需授权安全抵押合约的抵押和解抵押权限给 BankofStaked(详情参见:[SafeDelegatebw](https://github.com/EOSLaoMao/SafeDelegatebw))。
25 | 4. 该 Creditor 账户需确保账户自身具有足够的 RAM/CPU/NET 资源(详情参见:[Creditor 资源指引](./BankofStaked-Creditor-Resource-Guide.md))。
26 |
27 | ### Creditor 义务
28 |
29 | 1. 加入时,需满足上述 Creditor 要求,且需要通过 BankofStaked 团队的审核。
30 | 2. 在提供服务期间,Creditor 不可以私自将正在出租的 EOS 提前解除抵押。
31 | 3. 在提供服务期间,Creditor 不可以私自将抵押和解抵押权限从 BankofStaked 智能合约撤除。
32 | 4. 退出 Creditor 需提前申请,并需等待正在出租的 EOS 到期自动解除抵押之后,方可退出。
33 |
34 | ### Creditor 权利
35 |
36 | 1. 在遵守上述 Creditor 义务的前提下,享有 EOS 租金收益的 90%。租金收益会在每笔订单到期之后自动分配至 Cerditor 账户。
37 | 2. 监督 BankofStaked 团队的开发进度。
38 |
39 | ### BankofStaked 权利
40 |
41 | 1. 享有出租方案的定价权。
42 | 2. 享有将违反规则的 Creditor 踢除的权利。
43 |
44 | ### BankofStaked 义务
45 |
46 | 1. 维护 BankofStaked 项目的发展。
47 | 2. 开发 BankofStaked 新功能,修复可能的问题。
48 |
49 | 其他未尽事宜,以 [BankofStaked Ricardian Contract](../rc/bankofstaked-ricardian-clauses.md) 为准。
50 |
51 | 有意参与者,请加入 Telegram 群聊:[https://t.me/BOSCreditor](https://t.me/BOSCreditor)
52 |
53 |  友情提醒:BankofStaked 不会以任何名义让 Creditor 向我方进行转账,请知悉。
54 |
--------------------------------------------------------------------------------
/doc/BankofStaked-Creditor-Term-EN.md:
--------------------------------------------------------------------------------
1 | # BankofStaked Open Creditor Program
2 |
3 | ## About BankofStaked
4 |
5 | BankofStaked is an EOS resource automatic leasing DAPP developed by EOSLaoMao team ([https://eoslaomao.com/bankofstaked](https://eoslaomao.com/bankofstaked)).
6 |
7 | BankofStaked has been online for more than two months since it was launched in October 2018, and has leased out more than 3,000,000 EOS automatically. At the same time, BankofStaked has been providing free emergency plan to the EOS community from day one with supports from 27 Block Producers. To date, BankofStaked has provided free emergency services to more than 30,000 EOS accounts. Wallets such as MEET.ONE, imToken, EOS.LIVE have also integrited free emergency plan into their wallets.
8 |
9 | BankofStaked has acheived a ZERO-fund-loss-risk while leasing creditors' EOS out by using EOS permission system cleverly.
10 |
11 | Comparing to other platforms, the benefits of being creditor of BankofStaked are as follows:
12 |
13 | 1. NO EOS transfer needed. Your EOS sits in your account, under your control all the time, which means there's ZERO risk of fund loss.
14 | 2. ALL airdrops will be recieved automatically, again, because your EOS sits in your account.
15 | 3. Voting right is under your control, too! As a DPOS blockchain, the importance of voting right is self-evident in EOS. You should always control your voting right fully.
16 |
17 |
18 | ## Open Creditor Program
19 | With the development of the EOS ecosystem, BankofStaked's business volume has grown rapidly, and BankofStaked's current creditors have been unable to meet the growing business needs. To this end, we now open a limited amount of BankofStaked's Creditor to qualified EOS token holders.
20 |
21 | Since setting up the Creditor account requires a certain knowledge of cleos command line tool, it is important for token holders to decide whether or not to participate after evaluating the risk. BankofStaked is not responsible for problems caused by improper operation or improper settings operated by token holders themselves.
22 |
23 | ### Creditor Requirements
24 | 1. An independent EOS account for creditor use and the account balance should be greater than 20,000 EOS.
25 | 2. The creditor account is required to deploy SafeDelegatebw smart contract provided by BankofStaked ([SafeDelegatebw](https://github.com/EOSLaoMao/SafeDelegatebw)).
26 | 3. The creditor account is required to authorize the delegate/undelagete permission to BankofStaked ([SafeDelegatebw](https://github.com/EOSLaoMao/SafeDelegatebw)).
27 | 4. The creditor account needs to ensure that the account itself has sufficient RAM/CPU/NET resources ([Creditor Resource Guide](./BankofStaked-Creditor-Resource-Guide.md)).
28 |
29 | ### Creditor Obligation
30 | 1. When you join, you need to meet the above creditor requirements and need to be reviewed and approved by the BankofStaked team.
31 | 2. During the service period, creditor may not arbitrarily revoke the EOS being leased to others in advance.
32 | 3. During the service period, creditor may not revoke the delegate/undelegate permission from the BankofStaked Smart Contract.
33 | 4. To quit being a creditor, you must apply in advance and wait for the EOS that is being leased to expire automatically before you can get a fully quit.
34 |
35 | ### Creditor Rights
36 | 1. Subject to the above Creditor obligations, creditor will get 90% of EOS lease income that happened in their account. Lease income is automatically allocated to the Cerditor account after each order expires.
37 | 2. Oversee the development of the BankofStaked team.
38 |
39 | ### BankofStaked Rights
40 | 1. Full control of the leasing price.
41 | 2. Have the right to kick off Creditor who violates the rules.
42 |
43 | ### BankofStaked Obligation
44 | 1. Maintainance and future development of the BankofStaked project.
45 | 2. Develop new BankofStaked features.
46 | 3. Fix possible bug and vulnarabilities.
47 | 4. Any other matters are subject to the [BankofStaked Ricardian Contract](../rc/bankofstaked-ricardian-clauses.md).
48 |
49 | Interested? Feel free to join the Telegram group chat: [https://t.me/BOSCreditor](https://t.me/BOSCreditor)
50 |
51 |  Friendly reminder: BankofStaked will not ask any creditor to transfer any token to us, please be aware.
52 |
--------------------------------------------------------------------------------
/include/bankofstaked/bankofstaked.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file bankofstaked.hpp
3 | */
4 | #include
5 | #include
6 | #include
7 |
8 | #define EOS_SYMBOL symbol("EOS", 4)
9 |
10 | using namespace eosio;
11 |
12 | namespace bank
13 | {
14 | static const name CODE_ACCOUNT = "bankofstaked"_n;
15 | static const name RAM_PAYER = "bankofstaked"_n;
16 | static const name MASK_TRANSFER = "masktransfer"_n;
17 | static const name STAKED_INCOME = "stakedincome"_n;
18 | static const name EOSIO = "eosio"_n;
19 | static const uint64_t FREE_PLAN_AMOUNT = 1000;
20 | static const uint64_t SECONDS_PER_MIN = 60;
21 | static const uint64_t SECONDS_PER_DAY = 24 * 3600;
22 | static const uint64_t MAX_FREE_ORDERS = 5;
23 | static const uint64_t MAX_PAID_ORDERS = 20;
24 | static const uint64_t TRUE = 1;
25 | static const uint64_t FALSE = 0;
26 | static const uint64_t CHECK_MAX_DEPTH = 3;
27 | static const uint64_t MAX_EOS_BALANCE = 500 * 10000; // 500 EOS at most
28 | static const uint64_t MIN_FREE_CREDITOR_BALANCE = 10 * 10000; // 10 EOS at least
29 | static const uint64_t DEFAULT_DIVIDEND_PERCENTAGE = 90; // 90% income will be allocated to creditor
30 |
31 | // To protect your table, you can specify different scope as random numbers
32 | static const uint64_t SCOPE = 921459758687;
33 |
34 | struct [[eosio::table, eosio::contract("bankofstaked")]] freelock
35 | {
36 | name beneficiary; // account who received CPU&NET
37 | uint64_t created_at; // unix time, in seconds
38 | uint64_t expire_at; // unix time, in seconds
39 |
40 | uint64_t primary_key() const { return beneficiary.value; }
41 | uint64_t get_expire_at() const { return expire_at; }
42 |
43 | EOSLIB_SERIALIZE(freelock, (beneficiary)(created_at)(expire_at));
44 | };
45 |
46 | typedef multi_index<"freelock"_n, freelock,
47 | indexed_by<"expire.at"_n, const_mem_fun>>
48 | freelock_table;
49 |
50 | struct [[eosio::table, eosio::contract("bankofstaked")]] order
51 | {
52 | uint64_t id;
53 | name buyer;
54 | asset price{0, EOS_SYMBOL}; // amount of EOS paied
55 | uint64_t is_free; // default is FALSE, for free plan, when service expired, it will do a auto refund
56 | name creditor; // account who delegated CPU&NET
57 | name beneficiary; // account who received CPU&NET
58 | uint64_t plan_id; // foreignkey of table plan
59 | asset cpu_staked{0, EOS_SYMBOL}; // amount of EOS staked for cpu
60 | asset net_staked{0, EOS_SYMBOL}; // amount of EOS staked for net
61 | uint64_t created_at; // unix time, in seconds
62 | uint64_t expire_at; // unix time, in seconds
63 |
64 | auto primary_key() const { return id; }
65 | uint64_t get_buyer() const { return buyer.value; }
66 | uint64_t get_beneficiary() const { return beneficiary.value; }
67 | uint64_t get_expire_at() const { return expire_at; }
68 |
69 | EOSLIB_SERIALIZE(order, (id)(buyer)(price)(is_free)(creditor)(beneficiary)(plan_id)(cpu_staked)(net_staked)(created_at)(expire_at));
70 | };
71 |
72 | typedef multi_index<"order"_n, order,
73 | indexed_by<"buyer"_n, const_mem_fun>,
74 | indexed_by<"expire.at"_n, const_mem_fun>,
75 | indexed_by<"beneficiary"_n, const_mem_fun>>
76 | order_table;
77 |
78 | struct [[eosio::table, eosio::contract("bankofstaked")]] history
79 | {
80 | uint64_t id;
81 | string content; // content
82 | uint64_t created_at; // unix time, in seconds
83 |
84 | auto primary_key() const { return id; }
85 | EOSLIB_SERIALIZE(history, (id)(content)(created_at));
86 | };
87 | typedef multi_index<"history"_n, history> history_table;
88 |
89 | struct [[eosio::table, eosio::contract("bankofstaked")]] plan
90 | {
91 | uint64_t id;
92 | asset price{0, EOS_SYMBOL}; // amount of EOS paied
93 | asset cpu{0, EOS_SYMBOL}; // amount of EOS staked for cpu
94 | asset net{0, EOS_SYMBOL}; // amount of EOS staked for net
95 | uint64_t duration; // affective time, in minutes
96 | uint64_t is_free; // default is FALSE, for free plan, when service expired, it will do a auto refund
97 | uint64_t is_active; // on active plan could be choosen
98 | uint64_t created_at; // unix time, in seconds
99 | uint64_t updated_at; // unix time, in seconds
100 |
101 | auto primary_key() const { return id; }
102 | uint64_t get_price() const { return (uint64_t)price.amount; }
103 | EOSLIB_SERIALIZE(plan, (id)(price)(cpu)(net)(duration)(is_free)(is_active)(created_at)(updated_at));
104 | };
105 | typedef multi_index<"plan"_n, plan,
106 | indexed_by<"price"_n, const_mem_fun>>
107 | plan_table;
108 |
109 | struct [[eosio::table, eosio::contract("bankofstaked")]] safecreditor
110 | {
111 | name account;
112 | uint64_t created_at; // unix time, in seconds
113 | uint64_t updated_at; // unix time, in seconds
114 |
115 | uint64_t primary_key() const { return account.value; }
116 |
117 | EOSLIB_SERIALIZE(safecreditor, (account)(created_at)(updated_at));
118 | };
119 | typedef multi_index<"safecreditor"_n, safecreditor> safecreditor_table;
120 |
121 | struct [[eosio::table, eosio::contract("bankofstaked")]] dividend
122 | {
123 | name account;
124 | uint64_t percentage; // percentage of income allocating to creditor
125 |
126 | uint64_t primary_key() const { return account.value; }
127 |
128 | EOSLIB_SERIALIZE(dividend, (account)(percentage));
129 | };
130 | typedef multi_index<"dividend"_n, dividend> dividend_table;
131 |
132 | struct [[eosio::table, eosio::contract("bankofstaked")]] creditor
133 | {
134 | name account;
135 | uint64_t is_active;
136 | uint64_t for_free; // default is FALSE, for_free means if this creditor provide free staking or not
137 | string free_memo; // memo for refund transaction
138 | asset balance{0, EOS_SYMBOL}; // amount of EOS paied
139 | asset cpu_staked{0, EOS_SYMBOL}; // amount of EOS paied
140 | asset net_staked{0, EOS_SYMBOL}; // amount of EOS paied
141 | asset cpu_unstaked{0, EOS_SYMBOL}; // amount of EOS paied
142 | asset net_unstaked{0, EOS_SYMBOL}; // amount of EOS paied
143 | uint64_t created_at; // unix time, in seconds
144 | uint64_t updated_at; // unix time, in seconds
145 |
146 | uint64_t primary_key() const { return account.value; }
147 | uint64_t get_is_active() const { return is_active; }
148 | uint64_t get_updated_at() const { return updated_at; }
149 |
150 | EOSLIB_SERIALIZE(creditor, (account)(is_active)(for_free)(free_memo)(balance)(cpu_staked)(net_staked)(cpu_unstaked)(net_unstaked)(created_at)(updated_at));
151 | };
152 |
153 | typedef multi_index<"creditor"_n, creditor,
154 | indexed_by<"is.active"_n, const_mem_fun>,
155 | indexed_by<"updated.at"_n, const_mem_fun>>
156 | creditor_table;
157 |
158 | struct [[eosio::table, eosio::contract("bankofstaked")]] blacklist
159 | {
160 | name account;
161 | uint64_t created_at; // unix time, in seconds
162 |
163 | uint64_t primary_key() const { return account.value; }
164 | EOSLIB_SERIALIZE(blacklist, (account)(created_at));
165 | };
166 | typedef multi_index<"blacklist"_n, blacklist> blacklist_table;
167 |
168 | struct [[eosio::table, eosio::contract("bankofstaked")]] whitelist
169 | {
170 | name account;
171 | uint64_t capacity; // max in-use free orders
172 | uint64_t updated_at; // unix time, in seconds
173 | uint64_t created_at; // unix time, in seconds
174 |
175 | uint64_t primary_key() const { return account.value; }
176 | EOSLIB_SERIALIZE(whitelist, (account)(capacity)(updated_at)(created_at));
177 | };
178 | typedef multi_index<"whitelist"_n, whitelist> whitelist_table;
179 |
180 | }// namespace bank
181 |
182 | struct [[eosio::table, eosio::contract("bankofstaked")]] recipient
183 | {
184 | name creditor;
185 | name recipient_account;
186 | uint64_t created_at; // unix time, in seconds
187 | uint64_t updated_at; // unix time, in seconds
188 |
189 | uint64_t primary_key() const { return creditor.value; }
190 |
191 | EOSLIB_SERIALIZE(recipient, (creditor)(recipient_account)(created_at)(updated_at));
192 | };
193 | typedef multi_index<"recipient"_n, recipient> recipient_table;
194 |
--------------------------------------------------------------------------------
/rc/bankofstaked.ricardian.clauses.md:
--------------------------------------------------------------------------------
1 | # Ricardian Clauses for **BankofStaked**
2 |
3 | ## Preamble
4 |
5 | EOS is a wonderful tool for the world to use in commercial applications; there are however some complications that may arise from its resource allocation and planning.
6 |
7 | BankofStaked aims to help by providing an automated service for resource allocation within EOS in exchange for fixed costs over a predefined duration.
8 |
9 | ## Executive Summary
10 |
11 | BankofStaked provides the workflow to arrange Creditor to temporarily delegate resources to Beneficiary in exchange for a Fee.
12 |
13 | ## Language and Interpretation
14 |
15 | The operative language is English.
16 |
17 | ## Definitions
18 |
19 | * Beneficiary: the person who is recipient of delegation.
20 | * Chain: the chain with the ID `aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906`.
21 | * Creditor: the person who makes resources available for delegation.
22 | * Delegation: the assignment of resources from Creditor to Beneficiary.
23 | * Fee: tokens transfered into BankofStaked that exactly correspond to a fee schedule amount.
24 | * Fee Schedule: the list of services provided with their corresponding amount, which can be fetched from pricing table of BankofStaked smart contract.
25 |
26 | ## Roles
27 |
28 | This smart contract defines the following roles:
29 | 1. Code: the account that manages this contract
30 | 1. Creditor: any account that grants Code delegate/undelegate permission on some of its token
31 | 1. Beneficiary: any account that pays fee in order to receive delegation
32 |
33 | ## Scope
34 |
35 | This contract applies to Chain, with the ID as defined above. Each chain may have its own operative version of this contract. Each chain's contract is severable and independent.
36 |
37 | ## Acceptance
38 |
39 | Any party making use or taking benefit from this contract is considered to agree to the terms set forth herein, as per their role as defined in Roles section.
40 |
41 | ## Role: Code
42 |
43 | ### Obligations
44 |
45 | On a best effort basis, Code aims to:
46 | 1. maintain this contract's operational status.
47 | 1. grant delegation to beneficiary resources as per Fee Schedule.
48 | 1. return funds transfered to this contract which does not match Fee Schedule.
49 | 1. release delegation upon expiry.
50 | 1. to distribute 90% of the fee to Creditor whose token was invovled in a delegation.
51 |
52 | ### Rights
53 |
54 | Code reserves the right to:
55 | 1. update the terms of Fee Schedule without notice nor justification.
56 | 1. revoke delegation to any beneficiary for violation of terms set forth herein.
57 | 1. decline service to any beneficiary without notice nor justification.
58 |
59 | ## Role: Creditor
60 |
61 | ### Obligations
62 |
63 | 1. Creditor agrees to refrain from revoking delegate/undelegate permission without submitting Code 3 days' prior notice, as per Communications Protocols defined herein.
64 | 1. Failure to provide proper notice before revoking delegate/undelegate permission, resulting in interruption of service for Beneficiary, Creditor forfeits his right to proceeds from the fees.
65 | 1. All communications intended for Code are to be sent as per Communications Protocol prescribed below.
66 |
67 | ### Rights
68 |
69 | 1. Creditor has a right to 90% of proceeds from the fees accrued by a delegation at the time of release.
70 |
71 | ## Role: Beneficiary
72 |
73 | ### Obligations
74 |
75 | 1. To refrain from submitting an unreasonable amount of requests.
76 | 1. All communications intended for Code are to be sent as per Communications Protocol prescribed below.
77 |
78 | ### Rights
79 |
80 | 1. For duly submitted fees resulting in a delegation order, Beneficiary may have an expectation of maintenance of delegation.
81 | 1. Beneficiaries who suffer an interruption of delegation may claim either: (i) a refund, or (ii) credit toward a delegation of equal value.
82 |
83 | ## Communications Protocol
84 |
85 | All notices under this contract intended for Code, must be sent by email to the following address: `bos@eoslaomao.com`
86 |
87 | ## Force Majeure
88 |
89 | In any event outside of BankofStaked's ability to control or influence, BankofStaked is not liable for any failure to perform as a result of said event.
90 |
91 | This may include--without limitation:
92 | * an interruption of service of the EOS Chain;
93 | * hacking/compromise of BankofStaked or Code account;
94 | * natural disater or act of God.
95 |
--------------------------------------------------------------------------------
/scripts/add_creditor.sh:
--------------------------------------------------------------------------------
1 | API=${1:-http://localhost:8888}
2 | cleos -u $API push action bankofstaked addcreditor '{"account": "charity.bank", "for_free": 1, "free_memo": "A gift from EOSLaoMao team"}' -p bankofstaked
3 | cleos -u $API push action bankofstaked addcreditor '{"account": "staking.bank", "for_free": 0, "free_memo": ""}' -p bankofstaked
4 | cleos -u $API push action bankofstaked addcreditor '{"account": "eosbeijinghp", "for_free": 1, "free_memo": "gift from EOS Beijing, EOS Navigation: https://www.shensi.com"}' -p bankofstaked
5 | cleos -u $API push action bankofstaked addcreditor '{"account": "eosbeijingbk", "for_free": 0, "free_memo": ""}' -p bankofstaked
6 | cleos -u $API push action bankofstaked addcreditor '{"account": "meetone1free", "for_free": 1, "free_memo": "A gift from MEET.ONE team"}' -p bankofstaked
7 | cleos -u $API push action bankofstaked addcreditor '{"account": "eosbixinbank", "for_free": 1, "free_memo": "A gift from EOSBIXIN team"}' -p bankofstaked
8 | cleos -u $API push action bankofstaked addcreditor '{"account": "jedaaastaked", "for_free": 1, "free_memo": "A gift from JEDA team with love"}' -p bankofstaked
9 | cleos -u $API push action bankofstaked addcreditor '{"account": "cannonstaked", "for_free": 1, "free_memo": "A gift from EOSCannon team"}' -p bankofstaked
10 | cleos -u $API push action bankofstaked addcreditor '{"account": "acroeosrndev", "for_free": 1, "free_memo": "A gift from AcroEOS"}' -p bankofstaked
11 | cleos -u $API push action bankofstaked addcreditor '{"account": "bankofeosys2", "for_free": 1, "free_memo": "A gift from EOSYS"}' -p bankofstaked
12 | cleos -u $API push action bankofstaked addcreditor '{"account": "bankofeosys1", "for_free": 0, "free_memo": ""}' -p bankofstaked
13 | cleos -u $API push action bankofstaked addcreditor '{"account": "eosasia.bp", "for_free": 1, "free_memo": "A gift from block producer eosasia11111"}' -p bankofstaked
14 | cleos -u $API push action bankofstaked addcreditor '{"account": "eoseco.bp", "for_free": 1, "free_memo": "A gift from EOSeco"}' -p bankofstaked
15 | cleos -u $API push action bankofstaked addcreditor '{"account": "eospacestake", "for_free": 1, "free_memo": "A gift from EOSpace"}' -p bankofstaked
16 | cleos -u $API push action bankofstaked addcreditor '{"account": "bankofstkarg", "for_free": 1, "free_memo": "A gift from EOS Argentina"}' -p bankofstaked
17 | cleos -u $API push action bankofstaked addcreditor '{"account": "eoscafestake", "for_free": 1, "free_memo": "A gift from EOS Cafe Block"}' -p bankofstaked
18 | cleos -u $API push action bankofstaked addcreditor '{"account": "eosgravitygo", "for_free": 1, "free_memo": "A gift from EOS Gravity"}' -p bankofstaked
19 | cleos -u $API push action bankofstaked addcreditor '{"account": "eosriobrfree", "for_free": 1, "free_memo": "A gift from EOS Rio"}' -p bankofstaked
20 | cleos -u $API push action bankofstaked addcreditor '{"account": "eosriostaked", "for_free": 0, "free_memo": ""}' -p bankofstaked
21 | cleos -u $API push action bankofstaked addcreditor '{"account": "bosauthority", "for_free": 1, "free_memo": "A gift from EOS Authority"}' -p bankofstaked
22 | cleos -u $API push action bankofstaked addcreditor '{"account": "eostribefree", "for_free": 1, "free_memo": "A gift from EOS Tribe"}' -p bankofstaked
23 | cleos -u $API push action bankofstaked addcreditor '{"account": "eostribecred", "for_free": 0, "free_memo": ""}' -p bankofstaked
24 | cleos -u $API push action bankofstaked addcreditor '{"account": "eospacificbs", "for_free": 1, "free_memo": "A gift from EOS Pacific"}' -p bankofstaked
25 | cleos -u $API push action bankofstaked addcreditor '{"account": "eos42reserve", "for_free": 1, "free_memo": "A gift from EOS42"}' -p bankofstaked
26 | #cleos -u $API push action bankofstaked activate '{"account": "charity.bank"}' -p bankofstaked
27 | #cleos -u $API push action bankofstaked activate '{"account": "staking.bank"}' -p bankofstaked
28 | #cleos -u $API push action bankofstaked activate '{"account": "eosbeijinghp"}' -p bankofstaked
29 | #cleos -u $API push action bankofstaked activate '{"account": "eosriostaked"}' -p bankofstaked
30 |
--------------------------------------------------------------------------------
/scripts/bank_perm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ACCOUNT=$1
4 | PKEY=${2:-EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV}
5 | PERM_ACCOUNT=${3:-bankofstaked}
6 | PERMISSION=${4:-eosio.code}
7 | API=${5:-http://localhost:8888}
8 |
9 | cleos set account permission $ACCOUNT bankperm '{"threshold": 1,"keys": [{"key": "'$PKEY'","weight": 1}],"accounts": [{"permission":{"actor":"'$PERM_ACCOUNT'","permission":"'$PERMISSION'"},"weight":1}]}' "active" -p $ACCOUNT@active
10 | cleos set action permission $ACCOUNT eosio.token transfer bankperm -p $ACCOUNT@active
11 | cleos set action permission $ACCOUNT eosio delegatebw bankperm -p $ACCOUNT@active
12 | cleos set action permission $ACCOUNT eosio undelegatebw bankperm -p $ACCOUNT@active
13 | cleos set action permission $ACCOUNT bankofstaked expireorder bankperm -p $ACCOUNT@active
14 | cleos set action permission $ACCOUNT bankofstaked check bankperm -p $ACCOUNT@active
15 | cleos set action permission $ACCOUNT bankofstaked rotate bankperm -p $ACCOUNT@active
16 |
--------------------------------------------------------------------------------
/scripts/creditor_perm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ACCOUNT=$1
4 | PKEY=${2:-EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV}
5 | SAFE=${3:-false}
6 | API=${4:-http://localhost:8888}
7 | PERM_ACCOUNT=${5:-bankofstaked}
8 | PERMISSION=${6:-eosio.code}
9 |
10 | cleos set account permission $ACCOUNT creditorperm '{"threshold": 1,"keys": [{"key": "'$PKEY'","weight": 1}],"accounts": [{"permission":{"actor":"'$PERM_ACCOUNT'","permission":"'$PERMISSION'"},"weight":1}]}' "active" -p $ACCOUNT@active
11 | if [ "$SAFE" = true ] ; then
12 | cleos set action permission $ACCOUNT $ACCOUNT delegatebw creditorperm -p $ACCOUNT@active
13 | else
14 | cleos set action permission $ACCOUNT eosio delegatebw creditorperm -p $ACCOUNT@active
15 | fi
16 | cleos set action permission $ACCOUNT eosio undelegatebw creditorperm -p $ACCOUNT@active
17 |
--------------------------------------------------------------------------------
/scripts/dev.sh:
--------------------------------------------------------------------------------
1 | ./scripts/deploy.sh
2 | ./scripts/set_plan.sh
3 | API=${1:-http://localhost:8888}
4 | cleos -u $API push action bankofstaked addcreditor '{"account": "voter1", "for_free": 1, "free_memo": "A gift from EOSLaoMao team"}' -p bankofstaked
5 | cleos -u $API push action bankofstaked addcreditor '{"account": "voter2", "for_free": 0, "free_memo": ""}' -p bankofstaked
6 | cleos -u $API push action bankofstaked addcreditor '{"account": "freestaking1", "for_free": 1, "free_memo": "A gift from EOSLaoMao team"}' -p bankofstaked
7 | cleos -u $API push action bankofstaked addcreditor '{"account": "fundstaking1", "for_free": 0, "free_memo": ""}' -p bankofstaked
8 | cleos -u $API push action bankofstaked addcreditor '{"account": "freestaking2", "for_free": 1, "free_memo": "A gift from EOSLaoMao team"}' -p bankofstaked
9 | cleos -u $API push action bankofstaked addcreditor '{"account": "fundstaking2", "for_free": 0, "free_memo": ""}' -p bankofstaked
10 | cleos -u $API push action bankofstaked activate '{"account": "voter1"}' -p bankofstaked
11 | cleos -u $API push action bankofstaked activate '{"account": "voter2"}' -p bankofstaked
12 | ./scripts/set_perm.sh bankofstaked
13 | ./scripts/add_perm.sh voter1
14 | ./scripts/add_perm.sh voter2
15 | ./scripts/add_perm.sh freestaking1
16 | ./scripts/add_perm.sh freestaking2
17 | ./scripts/add_perm.sh fundstaking1
18 | ./scripts/add_perm.sh fundstaking2
19 |
--------------------------------------------------------------------------------
/scripts/dev/check.sh:
--------------------------------------------------------------------------------
1 | cleos get account voter1
2 | cleos get account voter2
3 | cleos get account bankofstaked
4 |
--------------------------------------------------------------------------------
/scripts/dev/deploy.sh:
--------------------------------------------------------------------------------
1 | API=${1:-http://localhost:8888}
2 | sleep 1
3 | cleos -u $API system newaccount voter3 bankofstaked EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV --stake-cpu "100 EOS" --stake-net "100 EOS" --buy-ram "100 EOS"
4 | sleep 1
5 | cleos -u $API set contract bankofstaked bankofstaked
6 | sleep 1
7 | cleos -u $API system newaccount voter3 stakedincome EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV --buy-ram "100 EOS" --stake-cpu "100 EOS" --stake-net "100 EOS"
8 | sleep 1
9 | cleos -u $API system newaccount voter3 masktransfer EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV --buy-ram "100 EOS" --stake-cpu "100 EOS" --stake-net "100 EOS"
10 | sleep 1
11 | cleos -u $API system newaccount voter3 fundstostake EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV --buy-ram "100 EOS" --stake-cpu "100 EOS" --stake-net "100 EOS"
12 | sleep 1
13 |
14 | cleos -u $API set contract masktransfer proxytoken
15 | sleep 1
16 | ./proxytoken/perms.sh masktransfer EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
17 | sleep 1
18 |
19 | cleos -u $API set contract voter1 safedelegatebw
20 | sleep 1
21 | ./safedelegatebw/delegate_perm.sh voter1
22 | sleep 1
23 | ./safedelegatebw/creditor_perm.sh voter1
24 | sleep 1
25 | ./scripts/creditor_perm.sh voter2 EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
26 | sleep 1
27 | ./scripts/bank_perm.sh bankofstaked EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
28 | sleep 1
29 | ./scripts/order_perm.sh bankofstaked EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
30 | sleep 1
31 | cleos -u $API push action bankofstaked addcreditor '{"account": "voter1", "for_free": 1, "free_memo": "A gift from EOSLaoMao team"}' -p bankofstaked
32 | sleep 1
33 | cleos -u $API push action bankofstaked addcreditor '{"account": "voter2", "for_free": 0, "free_memo": ""}' -p bankofstaked
34 | sleep 1
35 | cleos -u $API push action bankofstaked activate '{"account": "voter1"}' -p bankofstaked
36 | sleep 1
37 | cleos -u $API push action bankofstaked activate '{"account": "voter2"}' -p bankofstaked
38 | sleep 1
39 | cleos -u $API push action bankofstaked addsafeacnt '{"account": "voter1"}' -p bankofstaked
40 | sleep 1
41 |
42 | cleos -u $API push action bankofstaked setplan '{"price": "0.1000 EOS", "cpu": "0.5000 EOS", "net": "0.5000 EOS", "duration": 1, "is_free": true}' -p bankofstaked
43 | sleep 1
44 | cleos -u $API push action bankofstaked setplan '{"price": "0.2000 EOS", "cpu": "36.0000 EOS", "net": "4.0000 EOS", "duration": 1, "is_free": false}' -p bankofstaked
45 | sleep 1
46 | cleos -u $API push action bankofstaked activateplan '{"price": "0.1000 EOS", "is_active": true}' -p bankofstaked
47 | sleep 1
48 | cleos -u $API push action bankofstaked activateplan '{"price": "0.2000 EOS", "is_active": true}' -p bankofstaked
49 | sleep 1
50 |
51 |
52 | # add voter3 to whitelist table
53 | cleos -u $API push action bankofstaked addwhitelist '{"account": "voter3", "capacity": 1000}' -p bankofstaked
54 | sleep 1
55 |
--------------------------------------------------------------------------------
/scripts/dev/spammer.sh:
--------------------------------------------------------------------------------
1 | rm multi_*
2 | ./scripts/check.sh > multi_before
3 | for i in a b c d e f g h i j k l m n o p q r s t u v w x y z
4 | do
5 | for j in a b c d e f g h i j k l m n o p q r s t u v w x y z
6 | do
7 | name=testaccoua$i$j
8 | cleos system newaccount voter3 $name EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV --stake-net "10 EOS" --stake-cpu "10 EOS" --buy-ram "10 EOS"
9 | cleos transfer voter3 bankofstaked '0.1 EOS' "$name"
10 | done
11 | done
12 | ./scripts/check.sh > multi_after
13 | sleep 70
14 | ./scripts/check.sh > multi_undelegate
15 | sleep 70
16 | ./scripts/check.sh > multi_refund
17 |
--------------------------------------------------------------------------------
/scripts/empty.sh:
--------------------------------------------------------------------------------
1 | API=${1:-http://localhost:8888}
2 | cleos -u $API push action bankofstaked empty "" -p bankofstaked
3 |
--------------------------------------------------------------------------------
/scripts/get_table.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | API=${1:-http://localhost:8888}
4 | limit=${2:-100}
5 | v=921459758687; k=creditor; declare "table_$k=$v";
6 | v=921459758687; k=safecreditor; declare "table_$k=$v";
7 | v=921459758687; k=history; declare "table_$k=$v";
8 | v=921459758687; k=order; declare "table_$k=$v";
9 | v=921459758687; k=freelock; declare "table_$k=$v";
10 | v=921459758687; k=blacklist; declare "table_$k=$v";
11 | v=921459758687; k=whitelist; declare "table_$k=$v";
12 | v=bankofstaked; k=plan; declare "table_$k=$v";
13 |
14 |
15 | for name in creditor safecreditor plan order history freelock blacklist whitelist
16 | do
17 | echo "==============TABLE "$name"========"
18 | scope="table_$name"
19 | cleos -u $API get table bankofstaked ${!scope} $name -l " $limit"
20 | echo "------------------------------------"
21 | echo
22 | done
23 |
--------------------------------------------------------------------------------
/scripts/order_perm.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ACCOUNT=$1
4 | PKEY=${2:-EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV}
5 | PERM_ACCOUNT=${3:-bankofstaked}
6 | PERMISSION=${4:-eosio.code}
7 |
8 | cleos set account permission $ACCOUNT orderperm '{"threshold": 1,"keys": [{"key": "'$PKEY'","weight": 1}],"accounts": [{"permission":{"actor":"'$PERM_ACCOUNT'","permission":"'$PERMISSION'"},"weight":1}]}' "active" -p $ACCOUNT@active
9 | cleos set action permission $ACCOUNT bankofstaked customorder orderperm -p $ACCOUNT@active
10 |
--------------------------------------------------------------------------------
/scripts/set_plan.sh:
--------------------------------------------------------------------------------
1 | API=${1:-http://localhost:8888}
2 | cleos -u $API push action -s -j -d bankofstaked setplan '{"price": "0.2000 EOS", "cpu": "22.0000 EOS", "net": "2.0000 EOS", "duration": 10080, "is_free": false}' -p bankofstaked >> plan.json
3 | cleos -u $API push action -s -j -d bankofstaked setplan '{"price": "0.5000 EOS", "cpu": "58.0000 EOS", "net": "2.0000 EOS", "duration": 10080, "is_free": false}' -p bankofstaked >> plan.json
4 | cleos -u $API push action -s -j -d bankofstaked setplan '{"price": "1.0000 EOS", "cpu": "118.0000 EOS", "net": "2.0000 EOS", "duration": 10080, "is_free": false}' -p bankofstaked >> plan.json
5 | cleos -u $API push action -s -j -d bankofstaked setplan '{"price": "2.0000 EOS", "cpu": "238.0000 EOS", "net": "2.0000 EOS", "duration": 10080, "is_free": false}' -p bankofstaked >> plan.json
6 | cleos -u $API push action -s -j -d bankofstaked setplan '{"price": "180.0000 EOS", "cpu": "9900.0000 EOS", "net": "100.0000 EOS", "duration": 40320, "is_free": false}' -p bankofstaked >> plan.json
7 | cleos -u $API push action -s -j -d bankofstaked setplan '{"price": "800.0000 EOS", "cpu": "49500.0000 EOS", "net": "500.0000 EOS", "duration": 40320, "is_free": false}' -p bankofstaked >> plan.json
8 | #cleos -u $API push action -s -j -d bankofstaked activateplan '{"price": "130.0000 EOS", "is_active": false}' -p bankofstaked >> plan.json
9 | #cleos -u $API push action -s -j -d bankofstaked activateplan '{"price": "580.0000 EOS", "is_active": false}' -p bankofstaked >> plan.json
10 | #cleos -u $API push action -s -j -d bankofstaked activateplan '{"price": "180.0000 EOS", "is_active": true}' -p bankofstaked >> plan.json
11 | #cleos -u $API push action -s -j -d bankofstaked activateplan '{"price": "780.0000 EOS", "is_active": true}' -p bankofstaked >> plan.json
12 |
--------------------------------------------------------------------------------
/src/bankofstaked.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "../include/bankofstaked/bankofstaked.hpp"
5 | #include "lock.cpp"
6 | #include "utils.cpp"
7 | #include "validation.cpp"
8 | #include "safedelegatebw.hpp"
9 |
10 | using namespace eosio;
11 | using namespace eosiosystem;
12 | using namespace bank;
13 | using namespace lock;
14 | using namespace utils;
15 | using namespace validation;
16 |
17 | class [[eosio::contract]] bankofstaked : contract
18 | {
19 |
20 | public:
21 | using contract::contract;
22 |
23 | [[eosio::action]]
24 | void clearhistory(uint64_t max_depth)
25 | {
26 | require_auth(CODE_ACCOUNT);
27 | uint64_t depth = 0;
28 | history_table o(CODE_ACCOUNT, SCOPE);
29 | while (o.begin() != o.end())
30 | {
31 | depth += 1;
32 | if(depth > max_depth) {
33 | break;
34 | }
35 | auto itr = o.end();
36 | itr--;
37 | o.erase(itr);
38 | history_table o(CODE_ACCOUNT, SCOPE);
39 | }
40 | }
41 |
42 | // DEBUG only, action to empty entires in both tables
43 | [[eosio::action]]
44 | void empty()
45 | {
46 | require_auth(CODE_ACCOUNT);
47 | /*
48 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT);
49 | while (p.begin() != p.end())
50 | {
51 | auto itr = p.end();
52 | itr--;
53 | p.erase(itr);
54 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT);
55 | }
56 | order_table o(CODE_ACCOUNT, SCOPE);
57 | while (o.begin() != o.end())
58 | {
59 | auto itr = o.end();
60 | itr--;
61 | o.erase(itr);
62 | order_table o(CODE_ACCOUNT, SCOPE);
63 | }
64 |
65 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT);
66 | while (p.begin() != p.end())
67 | {
68 | auto itr = p.end();
69 | itr--;
70 | p.erase(itr);
71 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT);
72 | }
73 |
74 | creditor_table c(CODE_ACCOUNT, SCOPE);
75 | while (c.begin() != c.end())
76 | {
77 | auto itr = c.end();
78 | itr--;
79 | c.erase(itr);
80 | creditor_table c(CODE_ACCOUNT, SCOPE);
81 | }
82 | freelock_table c(CODE_ACCOUNT, SCOPE);
83 | while (c.begin() != c.end())
84 | {
85 | auto itr = c.end();
86 | itr--;
87 | c.erase(itr);
88 | freelock_table c(CODE_ACCOUNT, SCOPE);
89 | }
90 | */
91 | }
92 |
93 | [[eosio::action]]
94 | void test(name creditor)
95 | {
96 | require_auth(CODE_ACCOUNT);
97 |
98 | validate_creditor(creditor);
99 |
100 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT.value);
101 | auto idx = p.get_index<"price"_n>();
102 | auto plan = idx.find(FREE_PLAN_AMOUNT);
103 |
104 | //INLINE ACTION to test delegate CPU&NET for creditor itself
105 | if (is_safe_creditor(creditor)) {
106 | INLINE_ACTION_SENDER(safedelegatebw, delegatebw)
107 | (creditor, {{creditor, "creditorperm"_n}}, {creditor, plan->net, plan->cpu});
108 | } else {
109 | INLINE_ACTION_SENDER(eosiosystem::system_contract, delegatebw)
110 | (EOSIO, {{creditor, "creditorperm"_n}}, {creditor, creditor, plan->net, plan->cpu, false});
111 | }
112 |
113 | INLINE_ACTION_SENDER(eosiosystem::system_contract, undelegatebw)
114 | (EOSIO, {{creditor, "creditorperm"_n}}, {creditor, creditor, plan->net, plan->cpu});
115 |
116 | }
117 |
118 | [[eosio::action]]
119 | void rotate(name creditor, uint64_t for_free)
120 | {
121 | require_auth(CODE_ACCOUNT);
122 |
123 | validate_creditor(creditor);
124 | }
125 |
126 | [[eosio::action]]
127 | void check(name creditor)
128 | {
129 | require_auth(CODE_ACCOUNT);
130 |
131 | validate_creditor(creditor);
132 |
133 | order_table o(CODE_ACCOUNT, SCOPE);
134 | uint64_t depth = 0;
135 | std::vector order_ids;
136 |
137 | // order ordered by expire_at
138 | auto idx = o.get_index<"expire.at"_n>();
139 | auto itr = idx.begin();
140 | //force expire at most CHECK_MAX_DEPTH orders
141 | while (itr != idx.end() && depth < CHECK_MAX_DEPTH)
142 | {
143 | if(now() >= itr->expire_at) {
144 | order_ids.emplace_back(itr->id);
145 | }
146 | depth++;
147 | itr++;
148 | }
149 | undelegate(order_ids, 0);
150 | expire_freelock();
151 | rotate_creditor();
152 | get_balance(creditor);
153 | }
154 |
155 | [[eosio::action]]
156 | void forcexpire(const std::vector& order_ids=std::vector())
157 | {
158 | require_auth(CODE_ACCOUNT);
159 |
160 | //force expire provided orders
161 | undelegate(order_ids, 0);
162 | expire_freelock();
163 | rotate_creditor();
164 | }
165 |
166 | [[eosio::action]]
167 | void expireorder(uint64_t id)
168 | {
169 | require_auth(CODE_ACCOUNT);
170 |
171 | order_table o(CODE_ACCOUNT, SCOPE);
172 | auto order = o.find(id);
173 | eosio_assert(order != o.end(), "order entry not found!!!");
174 |
175 |
176 | // updated cpu_staked/net_staked/cpu_unstaked/net_unstaked of creditor entry
177 | creditor_table c(CODE_ACCOUNT, SCOPE);
178 | auto creditor_itr = c.find(order->creditor.value);
179 | c.modify(creditor_itr, RAM_PAYER, [&](auto &i) {
180 | i.cpu_staked -= order->cpu_staked;
181 | i.net_staked -= order->net_staked;
182 | i.cpu_unstaked += order->cpu_staked;
183 | i.net_unstaked += order->net_staked;
184 | i.balance = get_balance(order->creditor);
185 | i.updated_at = now();
186 | });
187 |
188 | save_order_history_table(&(*order));
189 |
190 | //delete order entry
191 | o.erase(order);
192 | }
193 |
194 | [[eosio::action]]
195 | void addwhitelist(name account, uint64_t capacity)
196 | {
197 | require_auth(CODE_ACCOUNT);
198 | whitelist_table w(CODE_ACCOUNT, SCOPE);
199 | auto itr = w.find(account.value);
200 | if(itr == w.end()) {
201 | w.emplace(RAM_PAYER, [&](auto &i) {
202 | i.account = account;
203 | i.capacity = capacity;
204 | i.created_at = now();
205 | i.updated_at = now();
206 | });
207 | } else {
208 | w.modify(itr, RAM_PAYER, [&](auto &i) {
209 | i.capacity = capacity;
210 | i.updated_at = now();
211 | });
212 | }
213 | }
214 |
215 | [[eosio::action]]
216 | void delwhitelist(name account, uint64_t capacity)
217 | {
218 | require_auth(CODE_ACCOUNT);
219 | whitelist_table w(CODE_ACCOUNT, SCOPE);
220 | auto itr = w.find(account.value);
221 | eosio_assert(itr != w.end(), "account not found in whitelist table");
222 | //delelete whitelist entry
223 | w.erase(itr);
224 | }
225 |
226 | [[eosio::action]]
227 | void addcreditor(name account, uint64_t for_free, std::string free_memo)
228 | {
229 | require_auth(CODE_ACCOUNT);
230 | creditor_table c(CODE_ACCOUNT, SCOPE);
231 | auto itr = c.find(account.value);
232 | eosio_assert(itr == c.end(), "account already exist in creditor table");
233 |
234 | c.emplace(RAM_PAYER, [&](auto &i) {
235 | i.is_active = FALSE;
236 | i.for_free = for_free?TRUE:FALSE;
237 | i.free_memo = for_free?free_memo:"";
238 | i.account = account;
239 | i.balance = get_balance(account);
240 | i.created_at = now();
241 | i.updated_at = 0; // set to 0 for creditor auto rotation
242 | });
243 | }
244 |
245 | [[eosio::action]]
246 | void addsafeacnt(name account)
247 | {
248 | require_auth(CODE_ACCOUNT);
249 |
250 | validate_creditor(account);
251 |
252 | safecreditor_table s(CODE_ACCOUNT, SCOPE);
253 | s.emplace(RAM_PAYER, [&](auto &i) {
254 | i.account = account;
255 | i.created_at = now();
256 | i.updated_at = now();
257 | });
258 | }
259 |
260 | [[eosio::action]]
261 | void delsafeacnt(name account)
262 | {
263 | require_auth(CODE_ACCOUNT);
264 | safecreditor_table s(CODE_ACCOUNT, SCOPE);
265 | auto itr = s.find(account.value);
266 | eosio_assert(itr != s.end(), "account does not exist in safecreditor table");
267 | s.erase(itr);
268 | }
269 |
270 | [[eosio::action]]
271 | void setrecipient(name creditor, name recipient)
272 | {
273 | require_auth(CODE_ACCOUNT);
274 |
275 | validate_creditor(creditor);
276 |
277 | recipient_table r(CODE_ACCOUNT, CODE_ACCOUNT.value);
278 | auto itr = r.find(creditor.value);
279 | if(itr == r.end()) {
280 | r.emplace(RAM_PAYER, [&](auto &i) {
281 | i.creditor = creditor;
282 | i.recipient_account = recipient;
283 | i.created_at = now();
284 | i.updated_at = now();
285 | });
286 | } else {
287 | r.modify(itr, RAM_PAYER, [&](auto &i) {
288 | i.recipient_account = recipient;
289 | i.updated_at = now();
290 | });
291 | }
292 | }
293 |
294 |
295 | [[eosio::action]]
296 | void delorders(const std::vector &order_ids = std::vector())
297 | {
298 | require_auth(CODE_ACCOUNT);
299 | if (order_ids.size() == 0)
300 | {
301 | return;
302 | }
303 |
304 | order_table o(CODE_ACCOUNT, SCOPE);
305 |
306 | for (int i = 0; i < order_ids.size(); i++)
307 | {
308 | uint64_t order_id = order_ids[i];
309 | auto order = o.find(order_id);
310 | eosio_assert(order != o.end(), "order entry not found!!!");
311 | save_order_history_table(&(*order));
312 | o.erase(order);
313 | }
314 | }
315 |
316 |
317 | [[eosio::action]]
318 | void delrecipient(name creditor)
319 | {
320 | require_auth(CODE_ACCOUNT);
321 | recipient_table r(CODE_ACCOUNT, CODE_ACCOUNT.value);
322 | auto itr = r.find(creditor.value);
323 | eosio_assert(itr != r.end(), "recipient entry not found!!!");
324 | r.erase(itr);
325 | }
326 |
327 | [[eosio::action]]
328 | void delcreditor(name account)
329 | {
330 | require_auth(CODE_ACCOUNT);
331 | creditor_table c(CODE_ACCOUNT, SCOPE);
332 | auto itr = c.find(account.value);
333 | eosio_assert(itr!= c.end(), "account not found in creditor table");
334 | eosio_assert(itr->is_active == FALSE, "cannot delete active creditor");
335 | //delelete creditor entry
336 | c.erase(itr);
337 | }
338 |
339 |
340 | [[eosio::action]]
341 | void addblacklist(name account)
342 | {
343 | require_auth(CODE_ACCOUNT);
344 | blacklist_table b(CODE_ACCOUNT, SCOPE);
345 | auto itr = b.find(account.value);
346 | eosio_assert(itr == b.end(), "account already exist in blacklist table");
347 |
348 | // add entry
349 | b.emplace(RAM_PAYER, [&](auto &i) {
350 | i.account = account;
351 | i.created_at = now();
352 | });
353 | }
354 |
355 |
356 | [[eosio::action]]
357 | void delblacklist(name account)
358 | {
359 | require_auth(CODE_ACCOUNT);
360 | blacklist_table b(CODE_ACCOUNT, SCOPE);
361 |
362 | //make sure specified blacklist account exists
363 | auto itr = b.find(account.value);
364 | eosio_assert(itr!= b.end(), "account not found in blacklist table");
365 | //delelete entry
366 | b.erase(itr);
367 | }
368 |
369 |
370 | [[eosio::action]]
371 | void activate(name account)
372 | {
373 | require_auth(CODE_ACCOUNT);
374 | activate_creditor(account);
375 | }
376 |
377 |
378 | [[eosio::action]]
379 | void setplan(asset price,
380 | asset cpu,
381 | asset net,
382 | uint64_t duration,
383 | bool is_free)
384 | {
385 | require_auth(CODE_ACCOUNT);
386 | validate_asset(price, cpu, net);
387 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT.value);
388 | auto idx = p.get_index<"price"_n>();
389 | auto itr = idx.find(price.amount);
390 | if (itr == idx.end())
391 | {
392 | p.emplace(RAM_PAYER, [&](auto &i) {
393 | i.id = p.available_primary_key();
394 | i.price = price;
395 | i.cpu = cpu;
396 | i.net = net;
397 | i.duration = duration;
398 | i.is_active = FALSE;
399 | i.is_free = is_free?TRUE:FALSE;
400 | i.created_at = now();
401 | i.updated_at = now();
402 | });
403 | }
404 | else
405 | {
406 | idx.modify(itr, RAM_PAYER, [&](auto &i) {
407 | i.cpu = cpu;
408 | i.net = net;
409 | i.duration = duration;
410 | i.is_free = is_free?TRUE:FALSE;
411 | i.updated_at = now();
412 | });
413 | }
414 | }
415 |
416 | [[eosio::action]]
417 | void activateplan(asset price, bool is_active)
418 | {
419 | require_auth(CODE_ACCOUNT);
420 | eosio_assert(price.is_valid(), "invalid price");
421 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT.value);
422 | auto idx = p.get_index<"price"_n>();
423 | auto itr = idx.find(price.amount);
424 | eosio_assert(itr != idx.end(), "price not found");
425 |
426 | idx.modify(itr, RAM_PAYER, [&](auto &i) {
427 | i.is_active = is_active?TRUE:FALSE;
428 | i.updated_at = now();
429 | });
430 | }
431 |
432 | [[eosio::action]]
433 | void customorder(name beneficiary, asset quantity, asset cpu, asset net, int64_t duration)
434 | {
435 | require_auth(CODE_ACCOUNT);
436 | bool is_free = false;
437 |
438 | // limit max quantity and resources
439 | eosio_assert(quantity <= asset{4000000, EOS_SYMBOL}, "quantity exceeds limit");
440 | eosio_assert(cpu <= asset{1980000000, EOS_SYMBOL}, "cpu exceeds limit");
441 | eosio_assert(net <= asset{20000000, EOS_SYMBOL}, "net exceeds limit");
442 | eosio_assert(duration >= 10080, "duration less than limit");
443 |
444 | // make sure beneficiary is a valid account
445 | eosio_assert( is_account( beneficiary ), "to account does not exist");
446 |
447 | //get active creditor
448 | name creditor = get_active_creditor(is_free);
449 |
450 | //plan is not free, make sure creditor has enough balance to delegate
451 | asset to_delegate = cpu + net;
452 | if(get_balance(creditor) < to_delegate) {
453 | creditor = get_qualified_paid_creditor(to_delegate);
454 | }
455 |
456 | //make sure creditor is a valid account
457 | eosio_assert( is_account( creditor ), "creditor account does not exist");
458 |
459 | //validate beneficiary
460 | //1. beneficiary shouldnt be CODE_ACCOUNT
461 | //2. beneficiary shouldnt be in blacklist
462 | //3. each beneficiary could only have 5 affective orders at most
463 | validate_beneficiary(beneficiary, creditor, is_free);
464 |
465 | //INLINE ACTION to delegate CPU&NET for beneficiary account
466 | if (is_safe_creditor(creditor)) {
467 | INLINE_ACTION_SENDER(safedelegatebw, delegatebw)
468 | (creditor, {{creditor, "creditorperm"_n}}, {beneficiary, net, cpu});
469 | } else {
470 | INLINE_ACTION_SENDER(eosiosystem::system_contract, delegatebw)
471 | (EOSIO, {{creditor, "creditorperm"_n}}, {creditor, beneficiary, net, cpu, false});
472 | }
473 |
474 | //INLINE ACTION to call check action of `bankofstaked`
475 | INLINE_ACTION_SENDER(bankofstaked, check)
476 | (CODE_ACCOUNT, {{CODE_ACCOUNT, "bankperm"_n}}, {creditor});
477 |
478 | // add cpu_staked&net_staked to creditor entry
479 | creditor_table c(CODE_ACCOUNT, SCOPE);
480 | auto creditor_itr = c.find(creditor.value);
481 | c.modify(creditor_itr, RAM_PAYER, [&](auto &i) {
482 | i.cpu_staked += cpu;
483 | i.net_staked += net;
484 | i.balance = get_balance(creditor);
485 | i.updated_at = now();
486 | });
487 |
488 | //create Order entry
489 | uint64_t order_id;
490 | order_table o(CODE_ACCOUNT, SCOPE);
491 | o.emplace(RAM_PAYER, [&](auto &i) {
492 | i.id = o.available_primary_key();
493 | i.buyer = CODE_ACCOUNT;
494 | i.price = quantity;
495 | i.creditor = creditor;
496 | i.beneficiary = beneficiary;
497 | i.plan_id = std::numeric_limits::max();
498 | i.cpu_staked = cpu;
499 | i.net_staked = net;
500 | i.is_free = is_free;
501 | i.created_at = now();
502 | i.expire_at = now() + duration * SECONDS_PER_MIN;
503 |
504 | order_id = i.id;
505 | });
506 |
507 | //deferred transaction to auto undelegate after expired
508 | std::vector order_ids;
509 | order_ids.emplace_back(order_id);
510 | undelegate(order_ids, duration);
511 | }
512 |
513 | //token received
514 | void received_token(name from, name to, asset quantity, string memo)
515 | {
516 | //validation token transfer, only accept EOS transfer
517 | eosio_assert(quantity.symbol == EOS_SYMBOL, "only accept EOS transfer");
518 |
519 | if (to == _self)
520 | {
521 | name buyer = from;
522 | //if token comes from fundstostake, do nothing, just take it :)
523 | if (from == "fundstostake"_n)
524 | {
525 | return;
526 | }
527 | //validate plan, is_active should be TRUE
528 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT.value);
529 | auto idx = p.get_index<"price"_n>();
530 | auto plan = idx.find(quantity.amount);
531 | eosio_assert(plan->is_active == TRUE, "plan is in-active");
532 | eosio_assert(plan != idx.end(), "invalid price");
533 |
534 | name beneficiary = get_beneficiary(memo, buyer);
535 |
536 | // if plan is free, validate there is no Freelock for this beneficiary
537 | if(plan->is_free == TRUE)
538 | {
539 | validate_freelock(beneficiary);
540 | }
541 |
542 | //get active creditor
543 | name creditor = get_active_creditor(plan->is_free);
544 |
545 | //if plan is not free, make sure creditor has enough balance to delegate
546 | if(plan->is_free == FALSE)
547 | {
548 | asset to_delegate = plan->cpu + plan->net;
549 | if(get_balance(creditor) < to_delegate) {
550 | creditor = get_qualified_paid_creditor(to_delegate);
551 | }
552 | }
553 |
554 | //make sure creditor is a valid account
555 | eosio_assert( is_account( creditor ), "creditor account does not exist");
556 |
557 | //validate buyer
558 | //1. buyer shouldnt be CODE_ACCOUNT
559 | //2. buyer shouldnt be in blacklist
560 | //3. each buyer could only have 5 affective orders at most
561 | validate_buyer(buyer, plan->is_free);
562 |
563 | //validate beneficiary
564 | //1. beneficiary shouldnt be CODE_ACCOUNT
565 | //2. beneficiary shouldnt be in blacklist
566 | //3. each beneficiary could only have 5 affective orders at most
567 | validate_beneficiary(beneficiary, creditor, plan->is_free);
568 |
569 | //INLINE ACTION to delegate CPU&NET for beneficiary account
570 | if (is_safe_creditor(creditor)) {
571 | INLINE_ACTION_SENDER(safedelegatebw, delegatebw)
572 | (creditor, {{creditor, "creditorperm"_n}}, {beneficiary, plan->net, plan->cpu});
573 | } else {
574 | INLINE_ACTION_SENDER(eosiosystem::system_contract, delegatebw)
575 | (EOSIO, {{creditor, "creditorperm"_n}}, {creditor, beneficiary, plan->net, plan->cpu, false});
576 | }
577 |
578 | //INLINE ACTION to call check action of `bankofstaked`
579 | INLINE_ACTION_SENDER(bankofstaked, check)
580 | (CODE_ACCOUNT, {{CODE_ACCOUNT, "bankperm"_n}}, {creditor});
581 |
582 | // add cpu_staked&net_staked to creditor entry
583 | creditor_table c(CODE_ACCOUNT, SCOPE);
584 | auto creditor_itr = c.find(creditor.value);
585 | c.modify(creditor_itr, RAM_PAYER, [&](auto &i) {
586 | i.cpu_staked += plan->cpu;
587 | i.net_staked += plan->net;
588 | i.balance = get_balance(creditor);
589 | i.updated_at = now();
590 | });
591 |
592 | //create Order entry
593 | uint64_t order_id;
594 | order_table o(CODE_ACCOUNT, SCOPE);
595 | o.emplace(RAM_PAYER, [&](auto &i) {
596 | i.id = o.available_primary_key();
597 | i.buyer = buyer;
598 | i.price = plan->price;
599 | i.creditor = creditor;
600 | i.beneficiary = beneficiary;
601 | i.plan_id = plan->id;
602 | i.cpu_staked = plan->cpu;
603 | i.net_staked = plan->net;
604 | i.is_free = plan->is_free;
605 | i.created_at = now();
606 | i.expire_at = now() + plan->duration * SECONDS_PER_MIN;
607 |
608 | order_id = i.id;
609 | });
610 |
611 | if(plan->is_free == TRUE)
612 | {
613 | // if plan is free, add a Freelock entry
614 | add_freelock(beneficiary);
615 | // auto refund immediately
616 | //INLINE ACTION to auto refund
617 | creditor_table c(CODE_ACCOUNT, SCOPE);
618 | std::string free_memo = c.get(creditor.value).free_memo;
619 | std::string buyer_name = buyer.to_string();
620 | std::string memo = buyer_name + " " + free_memo;
621 | INLINE_ACTION_SENDER(eosio::token, transfer)
622 | ("eosio.token"_n, {{CODE_ACCOUNT, "bankperm"_n}}, {CODE_ACCOUNT, MASK_TRANSFER, plan->price, memo});
623 | }
624 |
625 | //deferred transaction to auto undelegate after expired
626 | std::vector order_ids;
627 | order_ids.emplace_back(order_id);
628 | undelegate(order_ids, plan->duration);
629 | }
630 | }
631 |
632 | private:
633 |
634 | void save_order_history_table(const order *order){
635 |
636 |
637 | std::string content = "";
638 | //save order meta to history
639 | //buyer|creditor|beneficiary|plan_id|price|cpu|net|created_at|expire_at
640 | content += order->buyer.to_string();
641 | content += "|" + order->creditor.to_string();
642 | content += "|" + order->beneficiary.to_string();
643 | content += "|" + std::to_string(order->plan_id);
644 | content += "|" + std::to_string(order->price.amount);
645 | content += order->is_free==TRUE?"|free":"|paid";
646 | content += "|" + std::to_string(order->cpu_staked.amount);
647 | content += "|" + std::to_string(order->net_staked.amount);
648 | content += "|" + std::to_string(order->created_at);
649 | content += "|" + std::to_string(order->expire_at);
650 |
651 | // save order mete data to history table
652 | history_table h(CODE_ACCOUNT, SCOPE);
653 | h.emplace(RAM_PAYER, [&](auto &i) {
654 | i.id = h.available_primary_key();
655 | i.content = content;
656 | i.created_at = now();
657 | });
658 | }
659 |
660 | //undelegate Orders specified by order_ids
661 | //deferred(if duration > 0) transaction to auto undelegate after expired
662 | void undelegate(const std::vector& order_ids=std::vector(), uint64_t duration=0)
663 | {
664 | if(order_ids.size() == 0)
665 | {
666 | return;
667 | }
668 | eosio::transaction out;
669 |
670 | order_table o(CODE_ACCOUNT, SCOPE);
671 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT.value);
672 |
673 | uint64_t nonce = 0;
674 |
675 | for(int i=0; i 0) {
730 | out.delay_sec = duration * SECONDS_PER_MIN;
731 | }
732 | out.send((uint128_t(CODE_ACCOUNT.value) << 64) | current_time() | nonce, CODE_ACCOUNT, true);
733 | }
734 |
735 | };
736 |
737 | extern "C" {
738 | void apply(uint64_t receiver, uint64_t code, uint64_t action) {
739 | if (code == "eosio.token"_n.value && action == "transfer"_n.value) {
740 | eosio::execute_action(
741 | name(receiver), name(code), &bankofstaked::received_token
742 | );
743 | }
744 |
745 | if (code == receiver) {
746 | switch (action) {
747 | EOSIO_DISPATCH_HELPER(bankofstaked,
748 | (clearhistory)
749 | (empty)
750 | (test)
751 | (rotate)
752 | (check)
753 | (forcexpire)
754 | (expireorder)
755 | (addwhitelist)
756 | (delwhitelist)
757 | (addcreditor)
758 | (addsafeacnt)
759 | (delsafeacnt)
760 | (delcreditor)
761 | (delorders)
762 | (addblacklist)
763 | (delblacklist)
764 | (setplan)
765 | (activate)
766 | (activateplan)
767 | (setrecipient)
768 | (delrecipient)
769 | (customorder)
770 | )
771 | }
772 | }
773 | }
774 | }
775 |
--------------------------------------------------------------------------------
/src/lock.cpp:
--------------------------------------------------------------------------------
1 | using namespace eosio;
2 | using namespace eosiosystem;
3 | using namespace bank;
4 |
5 | namespace lock
6 | {
7 | //add freelock entry
8 | void add_freelock(name beneficiary)
9 | {
10 | freelock_table f(CODE_ACCOUNT, SCOPE);
11 | f.emplace(RAM_PAYER, [&](auto &i) {
12 | i.beneficiary = beneficiary;
13 | i.created_at = now();
14 | i.expire_at = i.created_at + SECONDS_PER_DAY;
15 | });
16 | }
17 |
18 | //delete expired freelock entries
19 | void expire_freelock()
20 | {
21 | uint64_t depth = 0;
22 | uint64_t n = now();
23 | freelock_table f(CODE_ACCOUNT, SCOPE);
24 | auto idx = f.get_index<"expire.at"_n>();
25 | auto last = idx.upper_bound(n);
26 | auto itr = idx.lower_bound(0);
27 | while(itr!=last && depth < CHECK_MAX_DEPTH)
28 | {
29 | idx.erase(itr);
30 | itr = idx.lower_bound(0);
31 | depth += 1;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/safedelegatebw.hpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | using namespace eosio;
6 | using namespace eosiosystem;
7 | using std::string;
8 |
9 | class [[eosio::contract]] safedelegatebw : contract {
10 | public:
11 | using contract::contract;
12 |
13 | [[eosio::action]]
14 | void delegatebw(name to,
15 | asset net_weight,
16 | asset cpu_weight){
17 |
18 | require_auth(_self);
19 |
20 | INLINE_ACTION_SENDER(eosiosystem::system_contract, delegatebw)
21 | ("eosio"_n, {{_self, "delegateperm"_n}}, {_self, to, net_weight, cpu_weight, false});
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/src/utils.cpp:
--------------------------------------------------------------------------------
1 | using namespace eosio;
2 | using namespace eosiosystem;
3 | using namespace bank;
4 |
5 | namespace utils
6 | {
7 | //try to get beneficiary from memo, otherwise, use sender.
8 | name get_beneficiary(const std::string &memo, name sender)
9 | {
10 | name to = sender;
11 | if (memo.length() > 0)
12 | {
13 | to = name(memo.c_str());
14 | eosio_assert( is_account( to ), "to account does not exist");
15 | }
16 | return to;
17 | }
18 |
19 | //get income recipient for creditor
20 | name get_recipient(name creditor)
21 | {
22 | recipient_table i(CODE_ACCOUNT, CODE_ACCOUNT.value);
23 | name recipient = creditor;
24 | auto itr = i.find(creditor.value);
25 | if(itr != i.end()) {
26 | recipient = itr->recipient_account;
27 | }
28 | eosio_assert( is_account( recipient ), "recipient account does not exist");
29 | return recipient;
30 | }
31 |
32 | //get active creditor from creditor table
33 | name get_active_creditor(uint64_t for_free)
34 | {
35 | uint64_t active = TRUE;
36 | creditor_table c(CODE_ACCOUNT, SCOPE);
37 | auto idx = c.get_index<"is.active"_n>();
38 | auto itr = idx.begin();
39 | name creditor;
40 | while (itr != idx.end())
41 | {
42 | if(itr->is_active != TRUE)
43 | {
44 | itr++;
45 | continue;
46 | }
47 |
48 | if(itr->for_free == for_free) {
49 | creditor = itr->account;
50 | break;
51 | }
52 | itr++;
53 | }
54 | return creditor;
55 | }
56 |
57 | //get account EOS balance
58 | asset get_balance(name owner)
59 | {
60 | auto balance = eosio::token::get_balance("eosio.token"_n, owner, EOS_SYMBOL.code());
61 | return balance;
62 | }
63 |
64 | //get account EOS balance
65 | asset update_balance(name owner)
66 | {
67 | auto balance = get_balance(owner);
68 | // update creditor if update is true
69 | creditor_table c(CODE_ACCOUNT, SCOPE);
70 | auto creditor_itr = c.find(owner.value);
71 | if(creditor_itr != c.end() && creditor_itr->balance != balance) {
72 | c.modify(creditor_itr, RAM_PAYER, [&](auto &i) {
73 | i.balance = balance;
74 | i.updated_at = now();
75 | });
76 | }
77 | return balance;
78 | }
79 |
80 | //get creditor with balance >= to_delegate
81 | name get_qualified_paid_creditor(asset to_delegate)
82 | {
83 | uint64_t active = TRUE;
84 | creditor_table c(CODE_ACCOUNT, SCOPE);
85 | auto idx = c.get_index<"is.active"_n>();
86 | auto itr = idx.begin();
87 | name creditor;
88 | while (itr != idx.end())
89 | {
90 | asset balance = get_balance(itr->account);
91 | if(itr->for_free == FALSE && balance >= to_delegate) {
92 | creditor = itr->account;
93 | break;
94 | }
95 | itr++;
96 | }
97 | return creditor;
98 | }
99 |
100 | //get creditor income
101 | asset get_income(name creditor, asset price)
102 | {
103 | dividend_table c(CODE_ACCOUNT, CODE_ACCOUNT.value);
104 | uint64_t amount = price.amount;
105 | auto itr = c.find(creditor.value);
106 | if(itr != c.end()) {
107 | price.amount = amount * itr->percentage / 100;
108 | } else {
109 | price.amount = amount * DEFAULT_DIVIDEND_PERCENTAGE / 100;
110 | }
111 | return price;
112 | }
113 |
114 | void activate_creditor(name account)
115 | {
116 | creditor_table c(CODE_ACCOUNT, SCOPE);
117 |
118 | auto creditor = c.find(account.value);
119 | //make sure specified creditor exists
120 | eosio_assert(creditor != c.end(), "account not found in creditor table");
121 |
122 | eosio::transaction out;
123 | //activate creditor, deactivate others
124 | auto itr = c.end();
125 | while (itr != c.begin())
126 | {
127 | itr--;
128 | if (itr->for_free != creditor->for_free) {
129 | continue;
130 | }
131 |
132 | if(itr->account==creditor->account) {
133 | c.modify(itr, RAM_PAYER, [&](auto &i) {
134 | i.is_active = TRUE;
135 | i.balance = get_balance(itr->account);
136 | i.updated_at = now();
137 | });
138 | action act1 = action(
139 | permission_level{ CODE_ACCOUNT, "bankperm"_n },
140 | CODE_ACCOUNT,
141 | "rotate"_n,
142 | std::make_tuple(itr->account, itr->for_free)
143 | );
144 | out.actions.emplace_back(act1);
145 | } else {
146 | if(itr->is_active == FALSE) {
147 | continue;
148 | }
149 | c.modify(itr, RAM_PAYER, [&](auto &i) {
150 | i.is_active = FALSE;
151 | i.balance = get_balance(itr->account);
152 | i.updated_at = now();
153 | });
154 | }
155 | }
156 | out.send((uint128_t(CODE_ACCOUNT.value) << 64) | current_time(), CODE_ACCOUNT, true);
157 | }
158 |
159 | //get min paid creditor balance
160 | uint64_t get_min_paid_creditor_balance()
161 | {
162 |
163 | uint64_t balance = 10000 * 10000; // 10000 EOS
164 | plan_table p(CODE_ACCOUNT, CODE_ACCOUNT.value);
165 | eosio_assert(p.begin() != p.end(), "plan table is empty!");
166 | auto itr = p.begin();
167 | while (itr != p.end())
168 | {
169 | auto required = itr->cpu.amount + itr->net.amount;
170 | if (itr->is_free == false && itr->is_active && required < balance) {
171 | balance = required;
172 | }
173 | itr++;
174 | }
175 | return balance;
176 | }
177 |
178 | //check creditor enabled safedelegate or not
179 | bool is_safe_creditor(name creditor)
180 | {
181 | safecreditor_table s(CODE_ACCOUNT, SCOPE);
182 | auto itr = s.find(creditor.value);
183 | if(itr == s.end()){
184 | return false;
185 | } else {
186 | return true;
187 | }
188 | }
189 |
190 | //rotate active creditor
191 | void rotate_creditor()
192 | {
193 | creditor_table c(CODE_ACCOUNT, SCOPE);
194 | auto free_creditor = get_active_creditor(TRUE);
195 | auto paid_creditor = get_active_creditor(FALSE);
196 |
197 | asset free_balance = get_balance(free_creditor);
198 | asset paid_balance = get_balance(paid_creditor);
199 | uint64_t min_paid_creditor_balance = get_min_paid_creditor_balance();
200 | auto free_rotated = free_balance.amount > MIN_FREE_CREDITOR_BALANCE ?TRUE:FALSE;
201 | auto paid_rotated = paid_balance.amount > min_paid_creditor_balance ?TRUE:FALSE;
202 | auto idx = c.get_index<"updated.at"_n>();
203 | auto itr = idx.begin();
204 | while (itr != idx.end())
205 | {
206 | if(itr->for_free == TRUE)
207 | {
208 | if(free_rotated == TRUE){itr++;continue;}
209 | auto balance = get_balance(itr->account);
210 | if (itr->account != free_creditor && balance.amount > MIN_FREE_CREDITOR_BALANCE)
211 | {
212 | activate_creditor(itr->account);
213 | free_rotated = TRUE;
214 | }
215 | itr++;
216 | }
217 | else
218 | {
219 | if(paid_rotated == TRUE){itr++;continue;}
220 | auto balance = get_balance(itr->account);
221 | if (itr->account != paid_creditor && balance.amount > min_paid_creditor_balance)
222 | {
223 | activate_creditor(itr->account);
224 | paid_rotated = TRUE;
225 | }
226 | itr++;
227 | }
228 | }
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/src/validation.cpp:
--------------------------------------------------------------------------------
1 | using namespace eosio;
2 | using namespace eosiosystem;
3 | using namespace bank;
4 | using namespace utils;
5 |
6 | namespace validation
7 | {
8 | // check freelock
9 | void validate_freelock(name beneficiary)
10 | {
11 | freelock_table f(CODE_ACCOUNT, SCOPE);
12 | auto itr = f.find(beneficiary.value);
13 | eosio_assert(itr == f.end(), "free plan is avaliable every 24 hours for each beneficiary");
14 | }
15 |
16 | // check blacklist
17 | void validate_blacklist(name account)
18 | {
19 | blacklist_table b(CODE_ACCOUNT, SCOPE);
20 | auto itr = b.find(account.value);
21 | eosio_assert(itr == b.end(), "something wrong with your account");
22 | }
23 |
24 | //get BUYER's free order amount limit
25 | uint64_t get_free_order_cap(name buyer)
26 | {
27 | uint64_t max_orders = MAX_FREE_ORDERS;
28 | whitelist_table w(CODE_ACCOUNT, SCOPE);
29 | auto itr = w.find(buyer.value);
30 | if(itr != w.end())
31 | {
32 | max_orders = itr->capacity;
33 | }
34 | return max_orders;
35 | }
36 |
37 | //make sure BUYER's affective records is no more than get_free_order_cap(BUYER)
38 | void validate_buyer(name buyer, uint64_t is_free)
39 | {
40 | eosio_assert(buyer != CODE_ACCOUNT, "buyer cannot be bankofstaked");
41 |
42 | //validate blacklist
43 | validate_blacklist(buyer);
44 |
45 | // for paid orders, check MAX_PAID_ORDERS
46 | // for free orders, check get_free_order_cap()
47 | uint64_t max_orders = MAX_PAID_ORDERS;
48 | if(is_free == TRUE) {
49 | max_orders = get_free_order_cap(buyer);
50 | }
51 | std::string suffix = " affective orders at most for each buyer";
52 | std::string error_msg = std::to_string(max_orders) + suffix;
53 |
54 | order_table o(CODE_ACCOUNT, SCOPE);
55 | auto idx = o.get_index<"buyer"_n>();
56 | auto first = idx.lower_bound(buyer.value);
57 | auto last = idx.upper_bound(buyer.value);
58 | uint64_t count = 0;
59 | while(first != last && first != idx.end())
60 | {
61 | if(first->is_free == is_free)
62 | {
63 | count += 1;
64 | }
65 | first++;
66 | }
67 | eosio_assert(count < max_orders, error_msg.c_str());
68 | }
69 |
70 | //make sure BENEFICIARY's affective free orders is no more than MAX_FREE_ORDERS
71 | void validate_beneficiary(name beneficiary, name creditor, uint64_t is_free)
72 | {
73 | eosio_assert(beneficiary != CODE_ACCOUNT, "cannot delegate to bankofstaked");
74 | eosio_assert(beneficiary != creditor, "cannot delegate to creditor");
75 |
76 | //validate blacklist
77 | validate_blacklist(beneficiary);
78 |
79 | // for paid orders, check MAX_PAID_ORDERS
80 | // for free orders, check MAX_FREE_ORDERS
81 | uint64_t max_orders = MAX_PAID_ORDERS;
82 | if(is_free == TRUE) {
83 | max_orders = MAX_FREE_ORDERS;
84 | }
85 |
86 | //make sure the account has less than MAX_BALANCE EOS in balance
87 | //disabled temperarily because of account not found issue
88 | /*
89 | auto balance = get_balance(beneficiary);
90 | print("balance:", balance.amount);
91 | eosio_assert(balance.amount();
96 | auto first = idx.lower_bound(beneficiary.value);
97 | auto last = idx.upper_bound(beneficiary.value);
98 | uint64_t count = 0;
99 | while(first != last && first != idx.end())
100 | {
101 | if(first->is_free == is_free)
102 | {
103 | count += 1;
104 | }
105 | first++;
106 | }
107 | std::string suffix = " affective orders at most for each beneficiary";
108 | std::string error_msg = std::to_string(max_orders) + suffix;
109 | eosio_assert(count < max_orders, error_msg.c_str());
110 | }
111 |
112 |
113 | //validate Plan asset fields
114 | void validate_asset(asset price,
115 | asset cpu,
116 | asset net)
117 | {
118 | eosio_assert(price.is_valid(), "invalid price");
119 | eosio_assert(cpu.is_valid(), "invalid cpu");
120 | eosio_assert(net.is_valid(), "invalid net");
121 | eosio_assert(price.amount >= 100 && price.amount <= 10000000, "price should between 0.01 EOS and 1000 EOS");
122 | }
123 |
124 | //validate account exist in creditor table
125 | void validate_creditor(name creditor)
126 | {
127 | creditor_table c(CODE_ACCOUNT, SCOPE);
128 | auto itr = c.find(creditor.value);
129 | eosio_assert(itr != c.end(), "account does not exist in creditor table");
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/stats/fetch.py:
--------------------------------------------------------------------------------
1 | import pprint
2 | import time
3 | from eosapi import Client
4 |
5 | c = Client(nodes=['https://geo.eosasia.one'])
6 |
7 | def check_order(lower_bound=1):
8 | expired_orders = []
9 | now = time.time()
10 | new_lower_bound = lower_bound
11 | r = c.get_table_rows(**{"code": "bankofstaked", "scope": "921459758687", "table": "order", "json": True, "limit": 100, "upper_bound": None, "lower_bound": lower_bound, "table_key": "id"})
12 | more = r["more"]
13 | total_count = 0
14 | count = 0
15 | free_count = 0
16 | paid = []
17 | for line in r["rows"]:
18 | total_count += 1
19 | if line["expire_at"] < now:
20 | expired_orders.append(line)
21 | count+=1
22 | #print(line)
23 | if line["is_free"]:
24 | #print("free id:", line["id"])
25 | free_count += 1
26 | else:
27 | paid.append(line["id"])
28 | if line["id"] > lower_bound:
29 | new_lower_bound = line["id"]
30 | print("total orders: %d" % total_count)
31 | print("expired orders: %d" % count)
32 | print("expired free orders: %d" % free_count)
33 | return more, new_lower_bound, expired_orders
34 |
35 |
36 |
37 | def fetch_creditors():
38 | paid_accounts = []
39 | free_accounts = []
40 | r = c.get_table_rows(**{"code": "bankofstaked", "scope": "921459758687", "table": "creditor", "json": True, "limit": 1000, "upper_bound": None, "lower_bound": None, "table_key": "account_name"})
41 |
42 | for a in r["rows"]:
43 | #print(a)
44 | if a["for_free"] == 1:
45 | free_accounts.append(a)
46 | else:
47 | paid_accounts.append(a)
48 | return free_accounts, paid_accounts
49 |
50 |
51 | def get_amount(asset):
52 | amount = float(asset.split(" ")[0])
53 | return amount
54 |
55 | def get_account(a, free=True):
56 | r = c.get_account(a["account"])
57 | ram_quota = r["ram_quota"]
58 | liquid_balance = get_amount(r["core_liquid_balance"])
59 | balance = liquid_balance + get_amount(a["cpu_staked"]) + get_amount(a["net_staked"])
60 | if r["self_delegated_bandwidth"]:
61 | self_delband = r["self_delegated_bandwidth"]
62 | balance += get_amount(self_delband["cpu_weight"]);
63 | balance += get_amount(self_delband["net_weight"]);
64 | if r["refund_request"]:
65 | refundings.append(r["refund_request"])
66 | balance += get_amount(r["refund_request"]["cpu_amount"]);
67 | balance += get_amount(r["refund_request"]["net_amount"]);
68 | if free:
69 | ram_required = balance * 0.16
70 | else:
71 | ram_required = balance * 0.12 / 30.
72 | #print(r["account_name"], liquid_balance)
73 | row = " | ".join([r["account_name"], str("%.4f EOS" % liquid_balance), str("%.4f EOS" % balance), str("%.2f" % (ram_quota/1024.)), str("%.2f" % ram_required), "✅" if (ram_quota/1024. > ram_required) else "❌"])
74 | row = "| %s |" % row
75 | print(row)
76 | return balance, liquid_balance
77 |
78 |
79 | if __name__ == "__main__":
80 | bps = set()
81 | def get_name(d):
82 | """ Return the value of a key in a dictionary. """
83 | return d["expire_at"]
84 |
85 | expired = []
86 | more, lower_bound, expired_orders = check_order()
87 | expired.extend(expired_orders)
88 | while more:
89 | more, lower_bound, expired_orders = check_order(lower_bound=lower_bound)
90 | expired.extend(expired_orders)
91 |
92 | expired.sort(key=get_name)
93 | paid_ids = set()
94 | ids = set()
95 | for e in expired:
96 | bps.add(e["creditor"])
97 |
98 | if e["is_free"]:
99 | ids.add(" ".join([e["creditor"], str(e["id"])]))
100 | else:
101 | paid_ids.add(" ".join([e["creditor"], str(e["id"])]))
102 | ids = list(ids)
103 | paid_ids = list(paid_ids)
104 | ids.sort()
105 | paid_ids.sort()
106 | print("total expired ids:", len(ids), ids)
107 | print("paid expired ids:", len(paid_ids), paid_ids)
108 | f1 = open("expired_order_ids.txt", "w")
109 | f1.write("\n".join([str(i) for i in ids]))
110 | f2 = open("expired_paid_order_ids.txt", "w")
111 | f2.write("\n".join([str(i) for i in paid_ids]))
112 | refundings = []
113 | free_accounts, paid_accounts = fetch_creditors()
114 | print("=================FREE ACCOUNTS==================")
115 | print("| Account | Liquid Balance | Total Balance | RAM Owned(kb) | RAM Requird(kb) | Enough RAM? |")
116 | print("| ------- | ------- | --------- | --------- | ----------- | ----------- |")
117 | for account in free_accounts:
118 | get_account(account)
119 | print("================================================\n\n")
120 |
121 | print("=================PAID ACCOUNTS==================")
122 | print("| Account | Liquid Balance | Total Balance | RAM Owned(kb) | RAM Requird(kb) | Enough RAM? |")
123 | print("| ------- | ------- | --------- | --------- | ----------- | ----------- |")
124 | total_balance = 0
125 | total_liquid_balance = 0
126 | for account in paid_accounts:
127 | balance, liquid_balance = get_account(account, False)
128 | total_balance += balance
129 | total_liquid_balance += liquid_balance
130 | print("total balance:", total_balance)
131 | print("total liquid balance:", total_liquid_balance)
132 | print("================================================")
133 |
134 | for r in refundings:
135 | print(r)
136 |
--------------------------------------------------------------------------------
/stats/requirements.txt:
--------------------------------------------------------------------------------
1 | beautifulsoup4==4.7.1
2 | certifi==2018.10.15
3 | chardet==3.0.4
4 | eosapi==0.4
5 | funcy==1.11
6 | idna==2.7
7 | numpy==1.15.4
8 | pandas==0.23.4
9 | prettytable==0.7.2
10 | pyeos-client==0.1.9
11 | python-dateutil==2.7.5
12 | pytz==2018.7
13 | requests==2.19.1
14 | six==1.11.0
15 | soupsieve==1.9.1
16 | toolz==0.9.0
17 | urllib3==1.23
18 | xlrd==1.1.0
19 |
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 | project(eosio_contracts VERSION 1.5.1)
3 |
4 | set(EOSIO_CDT_VERSION_MIN "1.4")
5 | set(EOSIO_CDT_VERSION_SOFT_MAX "1.4")
6 | #set(EOSIO_CDT_VERSION_HARD_MAX "")
7 |
8 | find_package(eosio.cdt)
9 |
10 | ### Check the version of eosio.cdt
11 | set(VERSION_MATCH_ERROR_MSG "")
12 | EOSIO_CHECK_VERSION(VERSION_OUTPUT "${EOSIO_CDT_VERSION}"
13 | "${EOSIO_CDT_VERSION_MIN}"
14 | "${EOSIO_CDT_VERSION_SOFT_MAX}"
15 | "${EOSIO_CDT_VERSION_HARD_MAX}"
16 | VERSION_MATCH_ERROR_MSG)
17 | if(VERSION_OUTPUT STREQUAL "MATCH")
18 | message(STATUS "Using eosio.cdt version ${EOSIO_CDT_VERSION}")
19 | elseif(VERSION_OUTPUT STREQUAL "WARN")
20 | message(WARNING "Using eosio.cdt version ${EOSIO_CDT_VERSION} even though it exceeds the maximum supported version of ${EOSIO_CDT_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use eosio.cdt version ${EOSIO_CDT_VERSION_SOFT_MAX}.x")
21 | else() # INVALID OR MISMATCH
22 | message(FATAL_ERROR "Found eosio.cdt version ${EOSIO_CDT_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use eosio.cdt version ${EOSIO_CDT_VERSION_SOFT_MAX}.x")
23 | endif(VERSION_OUTPUT STREQUAL "MATCH")
24 |
25 | if(CMAKE_BUILD_TYPE STREQUAL "Debug")
26 | set(TEST_BUILD_TYPE "Debug")
27 | set(CMAKE_BUILD_TYPE "Release")
28 | else()
29 | set(TEST_BUILD_TYPE ${CMAKE_BUILD_TYPE})
30 | endif()
31 |
32 |
33 | if (APPLE)
34 | set(OPENSSL_ROOT "/usr/local/opt/openssl")
35 | elseif (UNIX)
36 | set(OPENSSL_ROOT "/usr/include/openssl")
37 | endif()
38 | set(SECP256K1_ROOT "/usr/local")
39 |
40 | include(UnitTestsExternalProject.txt)
41 |
--------------------------------------------------------------------------------
/tests/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018, Respective Authors all rights reserved.
2 |
3 | The MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | # BankOfStaked
2 |
3 | How to run unit test.
4 |
5 | * ./build.sh
6 | * ./build/tests/unit_test
7 |
--------------------------------------------------------------------------------
/tests/UnitTestsExternalProject.txt:
--------------------------------------------------------------------------------
1 | include(ExternalProject)
2 | find_package(Git REQUIRED)
3 | include(GNUInstallDirs)
4 |
5 | string(REPLACE ";" "|" TEST_FRAMEWORK_PATH "${CMAKE_FRAMEWORK_PATH}")
6 | string(REPLACE ";" "|" TEST_MODULE_PATH "${CMAKE_MODULE_PATH}")
7 |
8 | ExternalProject_Add(
9 | contracts_unit_tests
10 | LIST_SEPARATOR | # Use the alternate list separator
11 | CMAKE_ARGS -DCMAKE_BUILD_TYPE=${TEST_BUILD_TYPE} -DCMAKE_FRAMEWORK_PATH=${TEST_FRAMEWORK_PATH} -DCMAKE_MODULE_PATH=${TEST_MODULE_PATH} -DEOSIO_ROOT=${EOSIO_ROOT} -DLLVM_DIR=${LLVM_DIR}
12 | SOURCE_DIR ${CMAKE_SOURCE_DIR}/tests
13 | BINARY_DIR ${CMAKE_BINARY_DIR}/tests
14 | BUILD_ALWAYS 1
15 | TEST_COMMAND ""
16 | INSTALL_COMMAND ""
17 | )
18 |
--------------------------------------------------------------------------------
/tests/build.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | printf "\t=========== Building eosio.contracts ===========\n\n"
4 |
5 | RED='\033[0;31m'
6 | NC='\033[0m'
7 |
8 | CORES=`getconf _NPROCESSORS_ONLN`
9 | mkdir -p build
10 | pushd build &> /dev/null
11 | cmake ../
12 | make -j${CORES}
13 | popd &> /dev/null
14 |
--------------------------------------------------------------------------------
/tests/clean-build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | rm -rf ./build
3 | rm -rf ./tests/build
--------------------------------------------------------------------------------
/tests/faketransfer/build.sh:
--------------------------------------------------------------------------------
1 | docker cp ../faketransfer nodeosd:/
2 |
--------------------------------------------------------------------------------
/tests/faketransfer/faketransfer.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | namespace play
5 | {
6 |
7 | using namespace std;
8 | using namespace eosio;
9 |
10 | class[[eosio::contract("faketransfer")]] faketransfer : public contract
11 | {
12 | public:
13 | using contract::contract;
14 |
15 | [[eosio::action]] void transfer(name from, name to, asset quantity, string memo) {
16 | require_recipient("bankofstaked"_n);
17 | }
18 |
19 | };
20 |
21 | } // namespace play
22 |
23 | extern "C" {
24 | void apply( uint64_t receiver, uint64_t code, uint64_t action ) {
25 | switch( action ) {
26 | EOSIO_DISPATCH_HELPER( play::faketransfer, (transfer) )
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required( VERSION 3.5 )
2 |
3 | set(EOSIO_VERSION_MIN "1.4")
4 | set(EOSIO_VERSION_SOFT_MAX "1.4")
5 | #set(EOSIO_VERSION_HARD_MAX "")
6 |
7 | find_package(eosio)
8 |
9 | ### Check the version of eosio
10 | set(VERSION_MATCH_ERROR_MSG "")
11 | EOSIO_CHECK_VERSION(VERSION_OUTPUT "${EOSIO_VERSION}"
12 | "${EOSIO_VERSION_MIN}"
13 | "${EOSIO_VERSION_SOFT_MAX}"
14 | "${EOSIO_VERSION_HARD_MAX}"
15 | VERSION_MATCH_ERROR_MSG)
16 | if(VERSION_OUTPUT STREQUAL "MATCH")
17 | message(STATUS "Using eosio version ${EOSIO_VERSION}")
18 | elseif(VERSION_OUTPUT STREQUAL "WARN")
19 | message(WARNING "Using eosio version ${EOSIO_VERSION} even though it exceeds the maximum supported version of ${EOSIO_VERSION_SOFT_MAX}; continuing with configuration, however build may fail.\nIt is recommended to use eosio version ${EOSIO_VERSION_SOFT_MAX}.x")
20 | else() # INVALID OR MISMATCH
21 | message(FATAL_ERROR "Found eosio version ${EOSIO_VERSION} but it does not satisfy version requirements: ${VERSION_MATCH_ERROR_MSG}\nPlease use eosio version ${EOSIO_VERSION_SOFT_MAX}.x")
22 | endif(VERSION_OUTPUT STREQUAL "MATCH")
23 |
24 |
25 | enable_testing()
26 |
27 | configure_file(${CMAKE_SOURCE_DIR}/contracts.hpp.in ${CMAKE_BINARY_DIR}/contracts.hpp)
28 |
29 | include_directories(${CMAKE_BINARY_DIR})
30 |
31 | file(GLOB UNIT_TESTS "*.cpp" "*.hpp")
32 |
33 | add_eosio_test( unit_test ${UNIT_TESTS} )
34 |
--------------------------------------------------------------------------------
/tests/tests/bankofstaked_tester.hpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "contracts.hpp"
5 | #include "eosio.system_tester.hpp"
6 |
7 | #include "Runtime/Runtime.h"
8 |
9 | #include
10 |
11 | using namespace eosio::testing;
12 | using namespace eosio;
13 | using namespace eosio::chain;
14 | using namespace eosio::testing;
15 | using namespace fc;
16 | using namespace std;
17 | using namespace eosio_system;
18 |
19 | using mvo = fc::mutable_variant_object;
20 |
21 | class bankofstaked_tester : public eosio_system_tester
22 | {
23 | public:
24 | bankofstaked_tester()
25 | {
26 | produce_blocks();
27 |
28 | eosio_system_tester::create_account_with_resources( N(bankofstaked), config::system_account_name, core_sym::from_string("100.0000"), false );
29 | eosio_system_tester::create_account_with_resources( N(masktransfer), config::system_account_name, core_sym::from_string("10.0000"), false );
30 | eosio_system_tester::create_account_with_resources( N(stakedincome), config::system_account_name, core_sym::from_string("10.0000"), false );
31 |
32 | eosio_system_tester::create_account_with_resources(
33 | N(alice.111111),
34 | config::system_account_name,
35 | core_sym::from_string("10.0000"),
36 | false,
37 | core_sym::from_string("10.0000"),
38 | core_sym::from_string("10.0000")
39 | );
40 | eosio_system_tester::create_account_with_resources(
41 | N(bob.11111111),
42 | config::system_account_name,
43 | core_sym::from_string("10.0000"),
44 | false,
45 | core_sym::from_string("10.0000"),
46 | core_sym::from_string("10.0000")
47 | );
48 | eosio_system_tester::create_account_with_resources(
49 | N(carol.111111),
50 | config::system_account_name,
51 | core_sym::from_string("10.0000"),
52 | false,
53 | core_sym::from_string("10.0000"),
54 | core_sym::from_string("10.0000")
55 | );
56 | eosio_system_tester::create_account_with_resources(
57 | N(ted.11111111),
58 | config::system_account_name,
59 | core_sym::from_string("10.0000"),
60 | false,
61 | core_sym::from_string("10.0000"),
62 | core_sym::from_string("10.0000")
63 | );
64 | eosio_system_tester::create_account_with_resources(
65 | N(carol.222222),
66 | config::system_account_name,
67 | core_sym::from_string("10.0000"),
68 | false,
69 | core_sym::from_string("10.0000"),
70 | core_sym::from_string("10.0000")
71 | );
72 |
73 | eosio_system_tester::issue(N(bankofstaked), core_sym::from_string("50.0000"));
74 | eosio_system_tester::issue(N(alice.111111), core_sym::from_string("500.0000"));
75 | eosio_system_tester::issue(N(bob.11111111), core_sym::from_string("5000.0000"));
76 | eosio_system_tester::issue(N(ted.11111111), core_sym::from_string("6000.0000"));
77 | eosio_system_tester::issue(N(carol.111111), core_sym::from_string("50000.0000"));
78 | eosio_system_tester::issue(N(carol.222222), core_sym::from_string("60000.0000"));
79 |
80 | produce_blocks();
81 |
82 | authority auth;
83 | fc::from_variant(
84 | fc::json::from_string(R"({"threshold": 1,"keys":[],"accounts": [{"permission":{"actor":"bankofstaked","permission":"eosio.code"},"weight":1}], "waits":[]})"),
85 | auth
86 | );
87 |
88 | set_authority(N(bankofstaked), N(bankperm), auth, config::active_name);
89 | link_authority(N(bankofstaked), N(eosio.token), N(bankperm), N(transfer));
90 | link_authority(N(bankofstaked), N(eosio), N(bankperm), N(delegatebw));
91 | link_authority(N(bankofstaked), N(eosio), N(bankperm), N(undelegatebw));
92 | link_authority(N(bankofstaked), N(bankofstaked), N(bankperm), N(expireorder));
93 | link_authority(N(bankofstaked), N(bankofstaked), N(bankperm), N(check));
94 | link_authority(N(bankofstaked), N(bankofstaked), N(bankperm), N(rotate));
95 |
96 | set_authority(N(bob.11111111), N(creditorperm), auth, config::active_name);
97 | set_authority(N(carol.111111), N(creditorperm), auth, config::active_name);
98 |
99 | link_authority(N(bob.11111111), N(eosio), N(creditorperm), N(delegatebw));
100 | link_authority(N(carol.111111), N(eosio), N(creditorperm), N(delegatebw));
101 | link_authority(N(bob.11111111), N(eosio), N(creditorperm), N(undelegatebw));
102 | link_authority(N(carol.111111), N(eosio), N(creditorperm), N(undelegatebw));
103 |
104 | produce_blocks();
105 |
106 | set_code(N(bankofstaked), contracts::bank_wasm());
107 | set_abi(N(bankofstaked), contracts::bank_abi().data());
108 | produce_blocks();
109 |
110 | eosio_system_tester::cross_15_percent_threshold();
111 |
112 | const auto &accnt = control->db().get(N(bankofstaked));
113 | abi_def bank_abi;
114 | BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, bank_abi), true);
115 | bank_abi_ser.set_abi(bank_abi, abi_serializer_max_time);
116 | }
117 |
118 | transaction_trace_ptr push_action(const account_name &signer, const action_name &name, const variant_object &data, bool auth = true)
119 | {
120 | vector accounts;
121 | if (auth)
122 | accounts.push_back(signer);
123 | auto trace = base_tester::push_action(N(bankofstaked), name, accounts, data);
124 | produce_block();
125 | BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trace->id));
126 | return trace;
127 | }
128 |
129 | fc::variant get_creditor(const account_name &act)
130 | {
131 | vector data = get_row_by_account(N(bankofstaked), 921459758687, N(creditor), act);
132 | return data.empty() ? EMPTY : bank_abi_ser.binary_to_variant("creditor", data, abi_serializer_max_time);
133 | }
134 |
135 | fc::variant get_safecreditor(const account_name &act)
136 | {
137 | vector data = get_row_by_account(N(bankofstaked), 921459758687, N(safecreditor), act);
138 | return data.empty() ? EMPTY : bank_abi_ser.binary_to_variant("safecreditor", data, abi_serializer_max_time);
139 | }
140 |
141 | fc::variant get_blacklist(const account_name &act)
142 | {
143 | vector data = get_row_by_account(N(bankofstaked), 921459758687, N(blacklist), act);
144 | return data.empty() ? EMPTY : bank_abi_ser.binary_to_variant("blacklist", data, abi_serializer_max_time);
145 | }
146 |
147 | fc::variant get_whitelist(const account_name &act)
148 | {
149 | vector data = get_row_by_account(N(bankofstaked), 921459758687, N(whitelist), act);
150 | return data.empty() ? EMPTY : bank_abi_ser.binary_to_variant("whitelist", data, abi_serializer_max_time);
151 | }
152 |
153 | fc::variant get_plan(const asset& price)
154 | {
155 | vector data = get_row_by_secondary_key(N(bankofstaked), N(bankofstaked), N(plan), (uint64_t)price.get_amount());
156 | return data.empty() ? EMPTY : bank_abi_ser.binary_to_variant("plan", data, abi_serializer_max_time);
157 | }
158 |
159 | fc::variant get_order(account_name buyer)
160 | {
161 | vector data = get_row_by_secondary_key(N(bankofstaked), 921459758687, N(order), buyer.value);
162 | return data.empty() ? EMPTY : bank_abi_ser.binary_to_variant("order", data, abi_serializer_max_time);
163 | }
164 |
165 | vector get_row_by_secondary_key( uint64_t code, uint64_t scope, uint64_t table, uint64_t key ) const {
166 | vector data;
167 | const auto& db = control->db();
168 | const auto* t_id = db.find( boost::make_tuple( code, scope, table ) );
169 | if ( !t_id ) {
170 | return data;
171 | }
172 |
173 | const auto& idx = db.get_index().indices().get();
174 |
175 | auto itr = idx.find( boost::make_tuple( t_id->id, key ) );
176 | if (itr != idx.end()) {
177 | const auto *obj = db.find(boost::make_tuple(t_id->id, itr->primary_key));
178 | if (obj) {
179 | data.resize( obj->value.size() );
180 | memcpy( data.data(), obj->value.data(), data.size() );
181 | }
182 | }
183 |
184 | return data;
185 | }
186 |
187 | // abi_serializer token_abi_ser;
188 | abi_serializer bank_abi_ser;
189 | fc::variant EMPTY = fc::variant(0).as_string().substr(0,8);
190 | };
191 |
--------------------------------------------------------------------------------
/tests/tests/bankofstaked_tests.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "contracts.hpp"
5 | #include "bankofstaked_tester.hpp"
6 |
7 | #include "Runtime/Runtime.h"
8 |
9 | #include
10 |
11 | using namespace eosio::testing;
12 | using namespace eosio;
13 | using namespace eosio::chain;
14 | using namespace eosio::testing;
15 | using namespace fc;
16 | using namespace std;
17 |
18 | using mvo = fc::mutable_variant_object;
19 |
20 | BOOST_AUTO_TEST_SUITE(bankofstaked_tests)
21 |
22 | // test action delcreditor
23 | BOOST_FIXTURE_TEST_CASE(rotate_test, bankofstaked_tester)
24 | try
25 | {
26 | // add 2 creditors, alice/bob
27 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "alice.111111")("for_free", 0)("free_memo", ""));
28 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 0)("free_memo", ""));
29 |
30 | push_action(N(bankofstaked), N(rotate), mvo()("creditor", "bob.11111111")("for_free", 0));
31 |
32 | // can't rotate non exist creditor
33 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(rotate), mvo()("creditor", "carol.111111")("for_free", 0)),
34 | eosio_assert_message_exception,
35 | eosio_assert_message_is("account does not exist in creditor table")
36 | );
37 | }
38 | FC_LOG_AND_RETHROW()
39 |
40 | // test action addwhitelist
41 | BOOST_FIXTURE_TEST_CASE(addwhitelist_test, bankofstaked_tester)
42 | try
43 | {
44 | // add 2 whitelist account, alice/bob
45 | push_action(N(bankofstaked), N(addwhitelist), mvo()("account", "alice.111111")("capacity", 100));
46 | push_action(N(bankofstaked), N(addwhitelist), mvo()("account", "bob.11111111")("capacity", 1000));
47 |
48 | auto whitelist = get_whitelist("alice.111111");
49 | REQUIRE_MATCHING_OBJECT(mvo()
50 | ("account", "alice.111111")
51 | ("capacity", 100),
52 | whitelist
53 | );
54 |
55 | whitelist = get_whitelist("bob.11111111");
56 | REQUIRE_MATCHING_OBJECT(mvo()
57 | ("account", "bob.11111111")
58 | ("capacity", 1000),
59 | whitelist
60 | );
61 |
62 | // update whitelist
63 | push_action(N(bankofstaked), N(addwhitelist), mvo()("account", "alice.111111")("capacity", 500));
64 | whitelist = get_whitelist("alice.111111");
65 | REQUIRE_MATCHING_OBJECT(mvo()
66 | ("account", "alice.111111")
67 | ("capacity", 500),
68 | whitelist
69 | );
70 | }
71 | FC_LOG_AND_RETHROW()
72 |
73 |
74 | BOOST_FIXTURE_TEST_CASE(delwhitelist_test, bankofstaked_tester)
75 | try
76 | {
77 | // add 2 whitelist account, alice/bob
78 | push_action(N(bankofstaked), N(addwhitelist), mvo()("account", "alice.111111")("capacity", 100));
79 |
80 | auto whitelist = get_whitelist("alice.111111");
81 | REQUIRE_MATCHING_OBJECT(mvo()
82 | ("account", "alice.111111")
83 | ("capacity", 100),
84 | whitelist
85 | );
86 |
87 | push_action(N(bankofstaked), N(delwhitelist), mvo()("account", "alice.111111")("capacity", 100));
88 |
89 | whitelist = get_blacklist("alice.111111");
90 | BOOST_REQUIRE_EQUAL(whitelist, "0");
91 |
92 | // can't delete non exist whitelist
93 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(delwhitelist), mvo()
94 | ("account", "bob.11111111")
95 | ("capacity", 100)),
96 | eosio_assert_message_exception,
97 | eosio_assert_message_is("account not found in whitelist table")
98 | );
99 |
100 | }
101 | FC_LOG_AND_RETHROW()
102 |
103 |
104 | BOOST_FIXTURE_TEST_CASE(addcreditor_test, bankofstaked_tester)
105 | try
106 | {
107 | // add 3 creditors, alice/bob/carol
108 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "alice.111111")("for_free", 1)("free_memo", "lucky you!"));
109 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 0)("free_memo", "hell yeah!"));
110 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "carol.111111")("for_free", 1)("free_memo", "oh"));
111 |
112 | auto creditor = get_creditor("alice.111111");
113 | REQUIRE_MATCHING_OBJECT(mvo()
114 | ("is_active", 0)
115 | ("for_free", 1)
116 | ("free_memo", "lucky you!")
117 | ("account", "alice.111111")
118 | ("balance", "500.0000 EOS")
119 | ("cpu_staked", "0.0000 EOS")
120 | ("net_staked", "0.0000 EOS")
121 | ("cpu_unstaked", "0.0000 EOS")
122 | ("net_unstaked", "0.0000 EOS"),
123 | creditor
124 | );
125 |
126 | creditor = get_creditor("bob.11111111");
127 | REQUIRE_MATCHING_OBJECT(mvo()
128 | ("is_active", 0)
129 | ("for_free", 0)
130 | ("free_memo", "")
131 | ("account", "bob.11111111")
132 | ("balance", "5000.0000 EOS")
133 | ("cpu_staked", "0.0000 EOS")
134 | ("net_staked", "0.0000 EOS")
135 | ("cpu_unstaked", "0.0000 EOS")
136 | ("net_unstaked", "0.0000 EOS"),
137 | creditor
138 | );
139 |
140 | creditor = get_creditor("carol.111111");
141 | REQUIRE_MATCHING_OBJECT(mvo()
142 | ("is_active", 0)
143 | ("for_free", 1)
144 | ("free_memo", "oh")
145 | ("account", "carol.111111")
146 | ("balance", "50000.0000 EOS")
147 | ("cpu_staked", "0.0000 EOS")
148 | ("net_staked", "0.0000 EOS")
149 | ("cpu_unstaked", "0.0000 EOS")
150 | ("net_unstaked", "0.0000 EOS"),
151 | creditor
152 | );
153 |
154 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(addcreditor), mvo()
155 | ("account", "carol.111111")
156 | ("for_free", 1)
157 | ("free_memo", "oh")),
158 | eosio_assert_message_exception,
159 | eosio_assert_message_is("account already exist in creditor table")
160 | );
161 | }
162 | FC_LOG_AND_RETHROW()
163 |
164 |
165 | BOOST_FIXTURE_TEST_CASE(addsafeacnt_test, bankofstaked_tester)
166 | try
167 | {
168 | // add 3 creditors, alice/bob/carol
169 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "alice.111111")("for_free", 1)("free_memo", "lucky you!"));
170 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 0)("free_memo", "hell yeah!"));
171 |
172 | auto creditor = get_creditor("alice.111111");
173 | REQUIRE_MATCHING_OBJECT(mvo()
174 | ("is_active", 0)
175 | ("for_free", 1)
176 | ("free_memo", "lucky you!")
177 | ("account", "alice.111111")
178 | ("balance", "500.0000 EOS")
179 | ("cpu_staked", "0.0000 EOS")
180 | ("net_staked", "0.0000 EOS")
181 | ("cpu_unstaked", "0.0000 EOS")
182 | ("net_unstaked", "0.0000 EOS"),
183 | creditor
184 | );
185 |
186 | creditor = get_creditor("bob.11111111");
187 | REQUIRE_MATCHING_OBJECT(mvo()
188 | ("is_active", 0)
189 | ("for_free", 0)
190 | ("free_memo", "")
191 | ("account", "bob.11111111")
192 | ("balance", "5000.0000 EOS")
193 | ("cpu_staked", "0.0000 EOS")
194 | ("net_staked", "0.0000 EOS")
195 | ("cpu_unstaked", "0.0000 EOS")
196 | ("net_unstaked", "0.0000 EOS"),
197 | creditor
198 | );
199 |
200 | push_action(N(bankofstaked), N(addsafeacnt), mvo()("account", "bob.11111111"));
201 |
202 | auto safecreditor = get_safecreditor("bob.11111111");
203 | REQUIRE_MATCHING_OBJECT(mvo()
204 | ("account", "bob.11111111"),
205 | safecreditor
206 | );
207 |
208 | safecreditor = get_safecreditor("alice.111111");
209 | BOOST_REQUIRE_EQUAL(safecreditor, "0");
210 |
211 |
212 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(addsafeacnt), mvo()("account", "carol.111111")),
213 | eosio_assert_message_exception,
214 | eosio_assert_message_is("account does not exist in creditor table")
215 | );
216 | }
217 | FC_LOG_AND_RETHROW()
218 |
219 |
220 | BOOST_FIXTURE_TEST_CASE(delsafeacnt_test, bankofstaked_tester)
221 | try
222 | {
223 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 0)("free_memo", "hell yeah!"));
224 |
225 | auto creditor = get_creditor("bob.11111111");
226 | REQUIRE_MATCHING_OBJECT(mvo()
227 | ("is_active", 0)
228 | ("for_free", 0)
229 | ("free_memo", "")
230 | ("account", "bob.11111111")
231 | ("balance", "5000.0000 EOS")
232 | ("cpu_staked", "0.0000 EOS")
233 | ("net_staked", "0.0000 EOS")
234 | ("cpu_unstaked", "0.0000 EOS")
235 | ("net_unstaked", "0.0000 EOS"),
236 | creditor
237 | );
238 |
239 | push_action(N(bankofstaked), N(addsafeacnt), mvo()("account", "bob.11111111"));
240 |
241 | auto safecreditor = get_safecreditor("bob.11111111");
242 | REQUIRE_MATCHING_OBJECT(mvo()
243 | ("account", "bob.11111111"),
244 | safecreditor
245 | );
246 |
247 | push_action(N(bankofstaked), N(delsafeacnt), mvo()("account", "bob.11111111"));
248 | safecreditor = get_safecreditor("bob.11111111");
249 | BOOST_REQUIRE_EQUAL(safecreditor, "0");
250 |
251 |
252 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(delsafeacnt), mvo()("account", "alice.111111")),
253 | eosio_assert_message_exception,
254 | eosio_assert_message_is("account does not exist in safecreditor table")
255 | );
256 | }
257 | FC_LOG_AND_RETHROW()
258 |
259 |
260 | // test action delcreditor
261 | BOOST_FIXTURE_TEST_CASE(delcreditor_test, bankofstaked_tester)
262 | try
263 | {
264 | // add 2 creditors, alice/bob
265 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "alice.111111")("for_free", 0)("free_memo", ""));
266 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 0)("free_memo", ""));
267 |
268 | auto creditor = get_creditor("bob.11111111");
269 | REQUIRE_MATCHING_OBJECT(mvo()
270 | ("is_active", 0)
271 | ("account", "bob.11111111")
272 | ("balance", "5000.0000 EOS")
273 | ("cpu_staked", "0.0000 EOS")
274 | ("net_staked", "0.0000 EOS")
275 | ("cpu_unstaked", "0.0000 EOS")
276 | ("net_unstaked", "0.0000 EOS"),
277 | creditor
278 | );
279 |
280 | // del creditor bob
281 | push_action(N(bankofstaked), N(delcreditor), mvo()("account", "bob.11111111"));
282 | //after deletion, bob should be EMPTY
283 | creditor = get_creditor("bob.11111111");
284 | BOOST_REQUIRE_EQUAL(creditor, "0");
285 |
286 | // can't delete non exist creditor
287 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(delcreditor), mvo()("account", "carol.111111")),
288 | eosio_assert_message_exception,
289 | eosio_assert_message_is("account not found in creditor table")
290 | );
291 |
292 | // can't delete active creditor
293 | push_action(N(bankofstaked), N(activate), mvo()("account", "alice.111111"));
294 |
295 | creditor = get_creditor("alice.111111");
296 | REQUIRE_MATCHING_OBJECT(mvo()
297 | ("is_active", 1)
298 | ("account", "alice.111111")
299 | ("balance", "500.0000 EOS")
300 | ("cpu_staked", "0.0000 EOS")
301 | ("net_staked", "0.0000 EOS")
302 | ("cpu_unstaked", "0.0000 EOS")
303 | ("net_unstaked", "0.0000 EOS"),
304 | creditor
305 | );
306 |
307 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(delcreditor), mvo()("account", "alice.111111")),
308 | eosio_assert_message_exception,
309 | eosio_assert_message_is("cannot delete active creditor")
310 | );
311 | }
312 | FC_LOG_AND_RETHROW()
313 |
314 |
315 | // test action addblacklist
316 | BOOST_FIXTURE_TEST_CASE(addblacklist_test, bankofstaked_tester)
317 | try
318 | {
319 | // add 2 accounts to blacklist table, alice/bob
320 | push_action(N(bankofstaked), N(addblacklist), mvo()("account", "alice.111111"));
321 | push_action(N(bankofstaked), N(addblacklist), mvo()("account", "bob.11111111"));
322 |
323 | auto blacklist = get_blacklist("alice.111111");
324 | BOOST_REQUIRE_EQUAL(blacklist["account"], "alice.111111");
325 | blacklist = get_blacklist("bob.11111111");
326 | BOOST_REQUIRE_EQUAL(blacklist["account"], "bob.11111111");
327 |
328 |
329 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(addblacklist), mvo()("account", "bob.11111111")),
330 | eosio_assert_message_exception,
331 | eosio_assert_message_is("account already exist in blacklist table")
332 | );
333 | }
334 | FC_LOG_AND_RETHROW()
335 |
336 |
337 | // test action delblacklist
338 | BOOST_FIXTURE_TEST_CASE(delblacklist_test, bankofstaked_tester)
339 | try
340 | {
341 | // add 2 accounts to blacklist table, alice/bob
342 | push_action(N(bankofstaked), N(addblacklist), mvo()("account", "alice.111111"));
343 | push_action(N(bankofstaked), N(addblacklist), mvo()("account", "bob.11111111"));
344 |
345 | auto blacklist = get_blacklist("alice.111111");
346 | BOOST_REQUIRE_EQUAL(blacklist["account"], "alice.111111");
347 | blacklist = get_blacklist("bob.11111111");
348 | BOOST_REQUIRE_EQUAL(blacklist["account"], "bob.11111111");
349 |
350 | // del blacklist bob
351 | push_action(N(bankofstaked), N(delblacklist), mvo()("account", "bob.11111111"));
352 | blacklist = get_blacklist("alice.111111");
353 | BOOST_REQUIRE_EQUAL(blacklist["account"], "alice.111111");
354 | //after deletion, bob should be EMPTY
355 | blacklist = get_blacklist("bob.11111111");
356 | BOOST_REQUIRE_EQUAL(blacklist, "0");
357 |
358 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(delblacklist), mvo()("account", "carol.111111")),
359 | eosio_assert_message_exception,
360 | eosio_assert_message_is("account not found in blacklist table")
361 | );
362 | }
363 | FC_LOG_AND_RETHROW()
364 |
365 |
366 | BOOST_FIXTURE_TEST_CASE(activate_test, bankofstaked_tester)
367 | try
368 | {
369 | // add 3 creditors, alice/bob/carol
370 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "alice.111111")("for_free", 0)("free_memo", ""));
371 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 0)("free_memo", ""));
372 |
373 | auto creditor = get_creditor("alice.111111");
374 | BOOST_REQUIRE_EQUAL(creditor["is_active"], 0);
375 | creditor = get_creditor("bob.11111111");
376 | BOOST_REQUIRE_EQUAL(creditor["is_active"], 0);
377 |
378 | //set bob as active creditor
379 | push_action(N(bankofstaked), N(activate), mvo()("account", "bob.11111111"));
380 | creditor = get_creditor("alice.111111");
381 | BOOST_REQUIRE_EQUAL(creditor["is_active"], 0);
382 | creditor = get_creditor("bob.11111111");
383 | BOOST_REQUIRE_EQUAL(creditor["is_active"], 1);
384 |
385 |
386 | BOOST_REQUIRE_EXCEPTION( push_action(N(bankofstaked), N(activate), mvo()("account", "carol.111111")),
387 | eosio_assert_message_exception,
388 | eosio_assert_message_is("account not found in creditor table")
389 | );
390 | }
391 | FC_LOG_AND_RETHROW()
392 |
393 |
394 | BOOST_FIXTURE_TEST_CASE(setplan_test, bankofstaked_tester)
395 | try
396 | {
397 | push_action(N(bankofstaked), N(setplan), mvo()
398 | ("price", "0.1000 EOS")
399 | ("cpu", "1.0000 EOS")
400 | ("net", "1.0000 EOS")
401 | ("duration", 300)
402 | ("is_free", 1));
403 | auto plan = get_plan(asset::from_string("0.1000 EOS"));
404 | REQUIRE_MATCHING_OBJECT(mvo()
405 | ("price", "0.1000 EOS")
406 | ("cpu", "1.0000 EOS")
407 | ("net", "1.0000 EOS")
408 | ("duration", 300)
409 | ("is_free", 1),
410 | plan
411 | );
412 |
413 | push_action(N(bankofstaked), N(setplan), mvo()
414 | ("price", "0.1000 EOS")
415 | ("cpu", "5.0000 EOS")
416 | ("net", "5.0000 EOS")
417 | ("duration", 400)
418 | ("is_free", 0));
419 | plan = get_plan(asset::from_string("0.1000 EOS"));
420 | REQUIRE_MATCHING_OBJECT(mvo()
421 | ("price", "0.1000 EOS")
422 | ("cpu", "5.0000 EOS")
423 | ("net", "5.0000 EOS")
424 | ("duration", 400)
425 | ("is_free", 0),
426 | plan
427 | );
428 |
429 | BOOST_REQUIRE_EXCEPTION( push_action( N(bankofstaked), N(setplan), mvo()
430 | ("price", "0.0099 EOS")
431 | ("cpu", "5.0000 EOS")
432 | ("net", "5.0000 EOS")
433 | ("duration", 400)
434 | ("is_free", 0)
435 | ),
436 | eosio_assert_message_exception,
437 | eosio_assert_message_is("price should between 0.01 EOS and 1000 EOS")
438 | );
439 |
440 | BOOST_REQUIRE_EXCEPTION( push_action( N(bankofstaked), N(setplan), mvo()
441 | ("price", "1000.0001 EOS")
442 | ("cpu", "5.0000 EOS")
443 | ("net", "5.0000 EOS")
444 | ("duration", 400)
445 | ("is_free", 0)
446 | ),
447 | eosio_assert_message_exception,
448 | eosio_assert_message_is("price should between 0.01 EOS and 1000 EOS")
449 | );
450 | }
451 | FC_LOG_AND_RETHROW()
452 |
453 | BOOST_FIXTURE_TEST_CASE(activateplan_test, bankofstaked_tester)
454 | try
455 | {
456 | push_action(N(bankofstaked), N(setplan), mvo()
457 | ("price", "0.1000 EOS")
458 | ("cpu", "1.0000 EOS")
459 | ("net", "1.0000 EOS")
460 | ("duration", 300)
461 | ("is_free", 1));
462 | auto plan = get_plan(asset::from_string("0.1000 EOS"));
463 | REQUIRE_MATCHING_OBJECT(mvo()
464 | ("price", "0.1000 EOS")
465 | ("cpu", "1.0000 EOS")
466 | ("net", "1.0000 EOS")
467 | ("is_active", 0)
468 | ("duration", 300)
469 | ("is_free", 1),
470 | plan
471 | );
472 |
473 | push_action(N(bankofstaked), N(activateplan), mvo()
474 | ("price", "0.1000 EOS")
475 | ("is_active", 1));
476 | plan = get_plan(asset::from_string("0.1000 EOS"));
477 | REQUIRE_MATCHING_OBJECT(mvo()
478 | ("price", "0.1000 EOS")
479 | ("cpu", "1.0000 EOS")
480 | ("net", "1.0000 EOS")
481 | ("is_active", 1)
482 | ("duration", 300)
483 | ("is_free", 1),
484 | plan
485 | );
486 | }
487 | FC_LOG_AND_RETHROW()
488 |
489 | BOOST_FIXTURE_TEST_CASE(buy_non_free_plan_test, bankofstaked_tester)
490 | try
491 | {
492 | push_action(N(bankofstaked), N(setplan), mvo()
493 | ("price", "0.1000 EOS")
494 | ("cpu", "1.0000 EOS")
495 | ("net", "1.0000 EOS")
496 | ("duration", 1)
497 | ("is_free", 1));
498 | push_action(N(bankofstaked), N(setplan), mvo()
499 | ("price", "1.0000 EOS")
500 | ("cpu", "10.0000 EOS")
501 | ("net", "10.0000 EOS")
502 | ("duration", 2)
503 | ("is_free", 0));
504 |
505 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 1)("free_memo", "hell yeah!"));
506 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "carol.111111")("for_free", 0)("free_memo", "should be ignored"));
507 |
508 | push_action(N(bankofstaked), N(activateplan), mvo()
509 | ("price", "0.1000 EOS")
510 | ("is_active", 1));
511 | push_action(N(bankofstaked), N(activateplan), mvo()
512 | ("price", "1.0000 EOS")
513 | ("is_active", 1));
514 |
515 | push_action(N(bankofstaked), N(activate), mvo()("account", "bob.11111111"));
516 | push_action(N(bankofstaked), N(activate), mvo()("account", "carol.111111"));
517 | produce_blocks();
518 |
519 | eosio_system_tester::transfer(N(alice.111111), N(bankofstaked), core_sym::from_string("1.0000"), N(alice.111111));
520 | produce_blocks();
521 |
522 | auto creditor = get_creditor("carol.111111");
523 | REQUIRE_MATCHING_OBJECT(mvo()
524 | ("is_active", 1)
525 | ("for_free", 0)
526 | ("free_memo", "")
527 | ("account", "carol.111111")
528 | ("balance", "50000.0000 EOS")
529 | ("cpu_staked", "10.0000 EOS")
530 | ("net_staked", "10.0000 EOS")
531 | ("cpu_unstaked", "0.0000 EOS")
532 | ("net_unstaked", "0.0000 EOS"),
533 | creditor
534 | );
535 |
536 | auto order = get_order("alice.111111");
537 | REQUIRE_MATCHING_OBJECT(mvo()
538 | ("buyer", "alice.111111")
539 | ("price", "1.0000 EOS")
540 | ("is_free", 0)
541 | ("creditor", "carol.111111")
542 | ("beneficiary", "alice.111111")
543 | ("cpu_staked", "10.0000 EOS")
544 | ("net_staked", "10.0000 EOS"),
545 | order
546 | );
547 |
548 | // after 2 minutes
549 | produce_blocks(240);
550 |
551 | creditor = get_creditor("carol.111111");
552 | REQUIRE_MATCHING_OBJECT(mvo()
553 | ("is_active", 1)
554 | ("for_free", 0)
555 | ("free_memo", "")
556 | ("account", "carol.111111")
557 | ("balance", "49980.0000 EOS")
558 | ("cpu_staked", "0.0000 EOS")
559 | ("net_staked", "0.0000 EOS")
560 | ("cpu_unstaked", "10.0000 EOS")
561 | ("net_unstaked", "10.0000 EOS"),
562 | creditor
563 | );
564 |
565 | BOOST_REQUIRE_EQUAL(get_balance(N(masktransfer)), asset::from_string("1.0000 EOS"));
566 | }
567 | FC_LOG_AND_RETHROW()
568 |
569 | BOOST_FIXTURE_TEST_CASE(buy_free_plan_test, bankofstaked_tester)
570 | try
571 | {
572 | push_action(N(bankofstaked), N(setplan), mvo()
573 | ("price", "0.1000 EOS")
574 | ("cpu", "1.0000 EOS")
575 | ("net", "1.0000 EOS")
576 | ("duration", 1)
577 | ("is_free", 1));
578 | push_action(N(bankofstaked), N(setplan), mvo()
579 | ("price", "1.0000 EOS")
580 | ("cpu", "10.0000 EOS")
581 | ("net", "10.0000 EOS")
582 | ("duration", 2)
583 | ("is_free", 0));
584 |
585 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 1)("free_memo", "hell yeah!"));
586 | push_action(N(bankofstaked), N(addcreditor), mvo()("account", "carol.111111")("for_free", 0)("free_memo", "should be ignored"));
587 |
588 | push_action(N(bankofstaked), N(activateplan), mvo()
589 | ("price", "0.1000 EOS")
590 | ("is_active", 1));
591 | push_action(N(bankofstaked), N(activateplan), mvo()
592 | ("price", "1.0000 EOS")
593 | ("is_active", 1));
594 |
595 | push_action(N(bankofstaked), N(activate), mvo()("account", "bob.11111111"));
596 | push_action(N(bankofstaked), N(activate), mvo()("account", "carol.111111"));
597 | produce_blocks();
598 |
599 | eosio_system_tester::transfer(N(alice.111111), N(bankofstaked), core_sym::from_string("0.1000"), N(alice.111111));
600 | produce_blocks();
601 |
602 | auto creditor = get_creditor("bob.11111111");
603 | REQUIRE_MATCHING_OBJECT(mvo()
604 | ("is_active", 1)
605 | ("for_free", 1)
606 | ("free_memo", "hell yeah!")
607 | ("account", "bob.11111111")
608 | ("balance", "5000.0000 EOS")
609 | ("cpu_staked", "1.0000 EOS")
610 | ("net_staked", "1.0000 EOS")
611 | ("cpu_unstaked", "0.0000 EOS")
612 | ("net_unstaked", "0.0000 EOS"),
613 | creditor
614 | );
615 |
616 | auto order = get_order("alice.111111");
617 | REQUIRE_MATCHING_OBJECT(mvo()
618 | ("buyer", "alice.111111")
619 | ("price", "0.1000 EOS")
620 | ("is_free", 1)
621 | ("creditor", "bob.11111111")
622 | ("beneficiary", "alice.111111")
623 | ("cpu_staked", "1.0000 EOS")
624 | ("net_staked", "1.0000 EOS"),
625 | order
626 | );
627 |
628 | // after 1 minutes
629 | produce_blocks(120);
630 |
631 | creditor = get_creditor("bob.11111111");
632 | REQUIRE_MATCHING_OBJECT(mvo()
633 | ("is_active", 1)
634 | ("for_free", 1)
635 | ("free_memo", "hell yeah!")
636 | ("account", "bob.11111111")
637 | ("balance", "4998.0000 EOS")
638 | ("cpu_staked", "0.0000 EOS")
639 | ("net_staked", "0.0000 EOS")
640 | ("cpu_unstaked", "1.0000 EOS")
641 | ("net_unstaked", "1.0000 EOS"),
642 | creditor
643 | );
644 |
645 | BOOST_REQUIRE_EQUAL(get_balance(N(masktransfer)), asset::from_string("0.1000 EOS"));
646 | BOOST_REQUIRE_EQUAL(get_balance(N(stakedincome)), asset::from_string("0.0000 EOS"));
647 |
648 | }
649 | FC_LOG_AND_RETHROW()
650 |
651 |
652 | // BOOST_FIXTURE_TEST_CASE(rotate_creditor_test, bankofstaked_tester)
653 | // try
654 | // {
655 | // push_action(N(bankofstaked), N(setplan), mvo()
656 | // ("price", "0.1000 EOS")
657 | // ("cpu", "2495.0000 EOS")
658 | // ("net", "2495.0000 EOS")
659 | // ("duration", 1)
660 | // ("is_free", 1));
661 | // push_action(N(bankofstaked), N(setplan), mvo()
662 | // ("price", "1.0000 EOS")
663 | // ("cpu", "10.0000 EOS")
664 | // ("net", "10.0000 EOS")
665 | // ("duration", 2)
666 | // ("is_free", 0));
667 |
668 | // push_action(N(bankofstaked), N(addcreditor), mvo()("account", "bob.11111111")("for_free", 1)("free_memo", ""));
669 | // push_action(N(bankofstaked), N(addcreditor), mvo()("account", "ted.11111111")("for_free", 1)("free_memo", ""));
670 | // push_action(N(bankofstaked), N(addcreditor), mvo()("account", "carol.111111")("for_free", 0)("free_memo", ""));
671 | // push_action(N(bankofstaked), N(addcreditor), mvo()("account", "carol.222222")("for_free", 0)("free_memo", ""));
672 |
673 | // push_action(N(bankofstaked), N(activateplan), mvo()
674 | // ("price", "0.1000 EOS")
675 | // ("is_active", 1));
676 | // push_action(N(bankofstaked), N(activateplan), mvo()
677 | // ("price", "1.0000 EOS")
678 | // ("is_active", 1));
679 |
680 | // push_action(N(bankofstaked), N(activate), mvo()("account", "bob.11111111"));
681 | // push_action(N(bankofstaked), N(activate), mvo()("account", "carol.111111"));
682 | // produce_blocks();
683 |
684 | // eosio_system_tester::transfer(N(alice.111111), N(bankofstaked), core_sym::from_string("0.1000"), N(alice.111111));
685 | // produce_blocks(10);
686 | // // eosio_system_tester::transfer(N(alice.111111), N(bankofstaked), core_sym::from_string("1.0000"), N(alice.111111));
687 | // // produce_blocks();
688 |
689 | // auto creditor = get_creditor("bob.11111111");
690 | // REQUIRE_MATCHING_OBJECT(mvo()
691 | // ("is_active", 0)
692 | // ("for_free", 1)
693 | // ("free_memo", "")
694 | // ("account", "bob.11111111")
695 | // ("balance", "5000.0000 EOS")
696 | // ("cpu_staked", "2495.0000 EOS")
697 | // ("net_staked", "2495.0000 EOS")
698 | // ("cpu_unstaked", "0.0000 EOS")
699 | // ("net_unstaked", "0.0000 EOS"),
700 | // creditor
701 | // );
702 |
703 | // creditor = get_creditor("ted.11111111");
704 | // REQUIRE_MATCHING_OBJECT(mvo()
705 | // ("is_active", 1)
706 | // ("for_free", 1)
707 | // ("free_memo", "")
708 | // ("account", "ted.11111111")
709 | // ("balance", "6000.0000 EOS")
710 | // ("cpu_staked", "0.0000 EOS")
711 | // ("net_staked", "0.0000 EOS")
712 | // ("cpu_unstaked", "0.0000 EOS")
713 | // ("net_unstaked", "0.0000 EOS"),
714 | // creditor
715 | // );
716 | // }
717 | // FC_LOG_AND_RETHROW()
718 |
719 | BOOST_AUTO_TEST_SUITE_END()
720 |
--------------------------------------------------------------------------------
/tests/tests/contracts.hpp.in:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | namespace eosio { namespace testing {
5 |
6 | struct contracts {
7 | static std::vector bank_wasm() { return read_wasm("${CMAKE_SOURCE_DIR}/../../build/bankofstaked.wasm"); }
8 | static std::vector bank_abi() { return read_abi("${CMAKE_SOURCE_DIR}/../../build/bankofstaked.abi"); }
9 |
10 | static std::vector token_wasm() { return read_wasm("${CMAKE_SOURCE_DIR}/test_contracts/eosio.token/eosio.token.wasm"); }
11 | static std::vector token_abi() { return read_abi("${CMAKE_SOURCE_DIR}/test_contracts/eosio.token/eosio.token.abi"); }
12 | static std::vector system_wasm() { return read_wasm("${CMAKE_SOURCE_DIR}/test_contracts/eosio.system/eosio.system.wasm"); }
13 | static std::vector system_abi() { return read_abi("${CMAKE_SOURCE_DIR}/test_contracts/eosio.system/eosio.system.abi"); }
14 | static std::vector msig_wasm() { return read_wasm("${CMAKE_SOURCE_DIR}/test_contracts/eosio.msig/eosio.msig.wasm"); }
15 | static std::vector msig_abi() { return read_abi("${CMAKE_SOURCE_DIR}/test_contracts/eosio.msig/eosio.msig.abi"); }
16 | };
17 | }} //ns eosio::testing
18 |
--------------------------------------------------------------------------------
/tests/tests/eosio.system_tester.hpp:
--------------------------------------------------------------------------------
1 | /**
2 | * @file
3 | * @copyright defined in eos/LICENSE.txt
4 | */
5 | #pragma once
6 |
7 | #include
8 | #include
9 | #include "contracts.hpp"
10 | #include "test_symbol.hpp"
11 |
12 | #include
13 | #include
14 |
15 | using namespace eosio::chain;
16 | using namespace eosio::testing;
17 | using namespace fc;
18 |
19 | using mvo = fc::mutable_variant_object;
20 |
21 | #ifndef TESTER
22 | #ifdef NON_VALIDATING_TEST
23 | #define TESTER tester
24 | #else
25 | #define TESTER validating_tester
26 | #endif
27 | #endif
28 |
29 |
30 | namespace eosio_system {
31 |
32 | class eosio_system_tester : public TESTER {
33 | public:
34 |
35 | void basic_setup() {
36 | produce_blocks( 2 );
37 |
38 | create_accounts({ N(eosio.token), N(eosio.ram), N(eosio.ramfee), N(eosio.stake),
39 | N(eosio.bpay), N(eosio.vpay), N(eosio.saving), N(eosio.names) });
40 |
41 |
42 | produce_blocks( 100 );
43 | set_code( N(eosio.token), contracts::token_wasm());
44 | set_abi( N(eosio.token), contracts::token_abi().data() );
45 | {
46 | const auto& accnt = control->db().get( N(eosio.token) );
47 | abi_def abi;
48 | BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true);
49 | token_abi_ser.set_abi(abi, abi_serializer_max_time);
50 | }
51 | }
52 |
53 | void create_core_token( symbol core_symbol = symbol{CORE_SYM} ) {
54 | FC_ASSERT( core_symbol.precision() != 4, "create_core_token assumes precision of core token is 4" );
55 | create_currency( N(eosio.token), config::system_account_name, asset(100000000000000, core_symbol) );
56 | issue(config::system_account_name, asset(10000000000000, core_symbol) );
57 | BOOST_REQUIRE_EQUAL( asset(10000000000000, core_symbol), get_balance( "eosio", core_symbol ) );
58 | }
59 |
60 | void deploy_contract( bool call_init = true ) {
61 | set_code( config::system_account_name, contracts::system_wasm() );
62 | set_abi( config::system_account_name, contracts::system_abi().data() );
63 | if( call_init ) {
64 | base_tester::push_action(config::system_account_name, N(init),
65 | config::system_account_name, mutable_variant_object()
66 | ("version", 0)
67 | ("core", CORE_SYM_STR)
68 | );
69 | }
70 |
71 | {
72 | const auto& accnt = control->db().get( config::system_account_name );
73 | abi_def abi;
74 | BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, abi), true);
75 | abi_ser.set_abi(abi, abi_serializer_max_time);
76 | }
77 | }
78 |
79 | void remaining_setup() {
80 | produce_blocks();
81 |
82 | // Assumes previous setup steps were done with core token symbol set to CORE_SYM
83 | create_account_with_resources( N(alice1111111), config::system_account_name, core_sym::from_string("1.0000"), false );
84 | create_account_with_resources( N(bob111111111), config::system_account_name, core_sym::from_string("0.4500"), false );
85 | create_account_with_resources( N(carol1111111), config::system_account_name, core_sym::from_string("1.0000"), false );
86 |
87 | BOOST_REQUIRE_EQUAL( core_sym::from_string("1000000000.0000"), get_balance("eosio") + get_balance("eosio.ramfee") + get_balance("eosio.stake") + get_balance("eosio.ram") );
88 | }
89 |
90 | enum class setup_level {
91 | none,
92 | minimal,
93 | core_token,
94 | deploy_contract,
95 | full
96 | };
97 |
98 | eosio_system_tester( setup_level l = setup_level::full ) {
99 | if( l == setup_level::none ) return;
100 |
101 | basic_setup();
102 | if( l == setup_level::minimal ) return;
103 |
104 | create_core_token();
105 | if( l == setup_level::core_token ) return;
106 |
107 | deploy_contract();
108 | if( l == setup_level::deploy_contract ) return;
109 |
110 | remaining_setup();
111 | }
112 |
113 | template
114 | eosio_system_tester(Lambda setup) {
115 | setup(*this);
116 |
117 | basic_setup();
118 | create_core_token();
119 | deploy_contract();
120 | remaining_setup();
121 | }
122 |
123 |
124 | void create_accounts_with_resources( vector accounts, account_name creator = config::system_account_name ) {
125 | for( auto a : accounts ) {
126 | create_account_with_resources( a, creator );
127 | }
128 | }
129 |
130 | transaction_trace_ptr create_account_with_resources( account_name a, account_name creator, uint32_t ram_bytes = 8000 ) {
131 | signed_transaction trx;
132 | set_transaction_headers(trx);
133 |
134 | authority owner_auth;
135 | owner_auth = authority( get_public_key( a, "owner" ) );
136 |
137 | trx.actions.emplace_back( vector{{creator,config::active_name}},
138 | newaccount{
139 | .creator = creator,
140 | .name = a,
141 | .owner = owner_auth,
142 | .active = authority( get_public_key( a, "active" ) )
143 | });
144 |
145 | trx.actions.emplace_back( get_action( config::system_account_name, N(buyrambytes), vector{{creator,config::active_name}},
146 | mvo()
147 | ("payer", creator)
148 | ("receiver", a)
149 | ("bytes", ram_bytes) )
150 | );
151 | trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{{creator,config::active_name}},
152 | mvo()
153 | ("from", creator)
154 | ("receiver", a)
155 | ("stake_net_quantity", core_sym::from_string("10.0000") )
156 | ("stake_cpu_quantity", core_sym::from_string("10.0000") )
157 | ("transfer", 0 )
158 | )
159 | );
160 |
161 | set_transaction_headers(trx);
162 | trx.sign( get_private_key( creator, "active" ), control->get_chain_id() );
163 | return push_transaction( trx );
164 | }
165 |
166 | transaction_trace_ptr create_account_with_resources( account_name a, account_name creator, asset ramfunds, bool multisig,
167 | asset net = core_sym::from_string("10.0000"), asset cpu = core_sym::from_string("10.0000") ) {
168 | signed_transaction trx;
169 | set_transaction_headers(trx);
170 |
171 | authority owner_auth;
172 | if (multisig) {
173 | // multisig between account's owner key and creators active permission
174 | owner_auth = authority(2, {key_weight{get_public_key( a, "owner" ), 1}}, {permission_level_weight{{creator, config::active_name}, 1}});
175 | } else {
176 | owner_auth = authority( get_public_key( a, "owner" ) );
177 | }
178 |
179 | trx.actions.emplace_back( vector{{creator,config::active_name}},
180 | newaccount{
181 | .creator = creator,
182 | .name = a,
183 | .owner = owner_auth,
184 | .active = authority( get_public_key( a, "active" ) )
185 | });
186 |
187 | trx.actions.emplace_back( get_action( config::system_account_name, N(buyram), vector{{creator,config::active_name}},
188 | mvo()
189 | ("payer", creator)
190 | ("receiver", a)
191 | ("quant", ramfunds) )
192 | );
193 |
194 | trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{{creator,config::active_name}},
195 | mvo()
196 | ("from", creator)
197 | ("receiver", a)
198 | ("stake_net_quantity", net )
199 | ("stake_cpu_quantity", cpu )
200 | ("transfer", 0 )
201 | )
202 | );
203 |
204 | set_transaction_headers(trx);
205 | trx.sign( get_private_key( creator, "active" ), control->get_chain_id() );
206 | return push_transaction( trx );
207 | }
208 |
209 | transaction_trace_ptr setup_producer_accounts( const std::vector& accounts,
210 | asset ram = core_sym::from_string("1.0000"),
211 | asset cpu = core_sym::from_string("80.0000"),
212 | asset net = core_sym::from_string("80.0000")
213 | )
214 | {
215 | account_name creator(config::system_account_name);
216 | signed_transaction trx;
217 | set_transaction_headers(trx);
218 |
219 | for (const auto& a: accounts) {
220 | authority owner_auth( get_public_key( a, "owner" ) );
221 | trx.actions.emplace_back( vector{{creator,config::active_name}},
222 | newaccount{
223 | .creator = creator,
224 | .name = a,
225 | .owner = owner_auth,
226 | .active = authority( get_public_key( a, "active" ) )
227 | });
228 |
229 | trx.actions.emplace_back( get_action( config::system_account_name, N(buyram), vector{ {creator, config::active_name} },
230 | mvo()
231 | ("payer", creator)
232 | ("receiver", a)
233 | ("quant", ram) )
234 | );
235 |
236 | trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw), vector{ {creator, config::active_name} },
237 | mvo()
238 | ("from", creator)
239 | ("receiver", a)
240 | ("stake_net_quantity", net)
241 | ("stake_cpu_quantity", cpu )
242 | ("transfer", 0 )
243 | )
244 | );
245 | }
246 |
247 | set_transaction_headers(trx);
248 | trx.sign( get_private_key( creator, "active" ), control->get_chain_id() );
249 | return push_transaction( trx );
250 | }
251 |
252 | action_result buyram( const account_name& payer, account_name receiver, const asset& eosin ) {
253 | return push_action( payer, N(buyram), mvo()( "payer",payer)("receiver",receiver)("quant",eosin) );
254 | }
255 | action_result buyrambytes( const account_name& payer, account_name receiver, uint32_t numbytes ) {
256 | return push_action( payer, N(buyrambytes), mvo()( "payer",payer)("receiver",receiver)("bytes",numbytes) );
257 | }
258 |
259 | action_result sellram( const account_name& account, uint64_t numbytes ) {
260 | return push_action( account, N(sellram), mvo()( "account", account)("bytes",numbytes) );
261 | }
262 |
263 | action_result push_action( const account_name& signer, const action_name &name, const variant_object &data, bool auth = true ) {
264 | string action_type_name = abi_ser.get_action_type(name);
265 |
266 | action act;
267 | act.account = config::system_account_name;
268 | act.name = name;
269 | act.data = abi_ser.variant_to_binary( action_type_name, data, abi_serializer_max_time );
270 |
271 | return base_tester::push_action( std::move(act), auth ? uint64_t(signer) : signer == N(bob111111111) ? N(alice1111111) : N(bob111111111) );
272 | }
273 |
274 | action_result stake( const account_name& from, const account_name& to, const asset& net, const asset& cpu ) {
275 | return push_action( name(from), N(delegatebw), mvo()
276 | ("from", from)
277 | ("receiver", to)
278 | ("stake_net_quantity", net)
279 | ("stake_cpu_quantity", cpu)
280 | ("transfer", 0 )
281 | );
282 | }
283 |
284 | action_result stake( const account_name& acnt, const asset& net, const asset& cpu ) {
285 | return stake( acnt, acnt, net, cpu );
286 | }
287 |
288 | action_result stake_with_transfer( const account_name& from, const account_name& to, const asset& net, const asset& cpu ) {
289 | return push_action( name(from), N(delegatebw), mvo()
290 | ("from", from)
291 | ("receiver", to)
292 | ("stake_net_quantity", net)
293 | ("stake_cpu_quantity", cpu)
294 | ("transfer", true )
295 | );
296 | }
297 |
298 | action_result stake_with_transfer( const account_name& acnt, const asset& net, const asset& cpu ) {
299 | return stake_with_transfer( acnt, acnt, net, cpu );
300 | }
301 |
302 | action_result unstake( const account_name& from, const account_name& to, const asset& net, const asset& cpu ) {
303 | return push_action( name(from), N(undelegatebw), mvo()
304 | ("from", from)
305 | ("receiver", to)
306 | ("unstake_net_quantity", net)
307 | ("unstake_cpu_quantity", cpu)
308 | );
309 | }
310 |
311 | action_result unstake( const account_name& acnt, const asset& net, const asset& cpu ) {
312 | return unstake( acnt, acnt, net, cpu );
313 | }
314 |
315 | action_result bidname( const account_name& bidder, const account_name& newname, const asset& bid ) {
316 | return push_action( name(bidder), N(bidname), mvo()
317 | ("bidder", bidder)
318 | ("newname", newname)
319 | ("bid", bid)
320 | );
321 | }
322 |
323 | static fc::variant_object producer_parameters_example( int n ) {
324 | return mutable_variant_object()
325 | ("max_block_net_usage", 10000000 + n )
326 | ("target_block_net_usage_pct", 10 + n )
327 | ("max_transaction_net_usage", 1000000 + n )
328 | ("base_per_transaction_net_usage", 100 + n)
329 | ("net_usage_leeway", 500 + n )
330 | ("context_free_discount_net_usage_num", 1 + n )
331 | ("context_free_discount_net_usage_den", 100 + n )
332 | ("max_block_cpu_usage", 10000000 + n )
333 | ("target_block_cpu_usage_pct", 10 + n )
334 | ("max_transaction_cpu_usage", 1000000 + n )
335 | ("min_transaction_cpu_usage", 100 + n )
336 | ("max_transaction_lifetime", 3600 + n)
337 | ("deferred_trx_expiration_window", 600 + n)
338 | ("max_transaction_delay", 10*86400+n)
339 | ("max_inline_action_size", 4096 + n)
340 | ("max_inline_action_depth", 4 + n)
341 | ("max_authority_depth", 6 + n)
342 | ("max_ram_size", (n % 10 + 1) * 1024 * 1024)
343 | ("ram_reserve_ratio", 100 + n);
344 | }
345 |
346 | action_result regproducer( const account_name& acnt, int params_fixture = 1 ) {
347 | action_result r = push_action( acnt, N(regproducer), mvo()
348 | ("producer", acnt )
349 | ("producer_key", get_public_key( acnt, "active" ) )
350 | ("url", "" )
351 | ("location", 0 )
352 | );
353 | BOOST_REQUIRE_EQUAL( success(), r);
354 | return r;
355 | }
356 |
357 | action_result vote( const account_name& voter, const std::vector& producers, const account_name& proxy = name(0) ) {
358 | return push_action(voter, N(voteproducer), mvo()
359 | ("voter", voter)
360 | ("proxy", proxy)
361 | ("producers", producers));
362 | }
363 |
364 | uint32_t last_block_time() const {
365 | return time_point_sec( control->head_block_time() ).sec_since_epoch();
366 | }
367 |
368 | asset get_balance( const account_name& act, symbol balance_symbol = symbol{CORE_SYM} ) {
369 | vector data = get_row_by_account( N(eosio.token), act, N(accounts), balance_symbol.to_symbol_code().value );
370 | return data.empty() ? asset(0, balance_symbol) : token_abi_ser.binary_to_variant("account", data, abi_serializer_max_time)["balance"].as();
371 | }
372 |
373 | fc::variant get_total_stake( const account_name& act ) {
374 | vector data = get_row_by_account( config::system_account_name, act, N(userres), act );
375 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "user_resources", data, abi_serializer_max_time );
376 | }
377 |
378 | fc::variant get_voter_info( const account_name& act ) {
379 | vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(voters), act );
380 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "voter_info", data, abi_serializer_max_time );
381 | }
382 |
383 | fc::variant get_producer_info( const account_name& act ) {
384 | vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(producers), act );
385 | return abi_ser.binary_to_variant( "producer_info", data, abi_serializer_max_time );
386 | }
387 |
388 | fc::variant get_producer_info2( const account_name& act ) {
389 | vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(producers2), act );
390 | return abi_ser.binary_to_variant( "producer_info2", data, abi_serializer_max_time );
391 | }
392 |
393 | void create_currency( name contract, name manager, asset maxsupply ) {
394 | auto act = mutable_variant_object()
395 | ("issuer", manager )
396 | ("maximum_supply", maxsupply );
397 |
398 | base_tester::push_action(contract, N(create), contract, act );
399 | }
400 |
401 | void issue( name to, const asset& amount, name manager = config::system_account_name ) {
402 | base_tester::push_action( N(eosio.token), N(issue), manager, mutable_variant_object()
403 | ("to", to )
404 | ("quantity", amount )
405 | ("memo", "")
406 | );
407 | }
408 | void transfer( name from, name to, const asset& amount, name manager = config::system_account_name ) {
409 | base_tester::push_action( N(eosio.token), N(transfer), manager, mutable_variant_object()
410 | ("from", from)
411 | ("to", to )
412 | ("quantity", amount)
413 | ("memo", "")
414 | );
415 | }
416 |
417 | double stake2votes( asset stake ) {
418 | auto now = control->pending_block_time().time_since_epoch().count() / 1000000;
419 | return stake.get_amount() * pow(2, int64_t((now - (config::block_timestamp_epoch / 1000)) / (86400 * 7))/ double(52) ); // 52 week periods (i.e. ~years)
420 | }
421 |
422 | double stake2votes( const string& s ) {
423 | return stake2votes( core_sym::from_string(s) );
424 | }
425 |
426 | fc::variant get_stats( const string& symbolname ) {
427 | auto symb = eosio::chain::symbol::from_string(symbolname);
428 | auto symbol_code = symb.to_symbol_code().value;
429 | vector data = get_row_by_account( N(eosio.token), symbol_code, N(stat), symbol_code );
430 | return data.empty() ? fc::variant() : token_abi_ser.binary_to_variant( "currency_stats", data, abi_serializer_max_time );
431 | }
432 |
433 | asset get_token_supply() {
434 | return get_stats("4," CORE_SYM_NAME)["supply"].as();
435 | }
436 |
437 | uint64_t microseconds_since_epoch_of_iso_string( const fc::variant& v ) {
438 | return static_cast( time_point::from_iso_string( v.as_string() ).time_since_epoch().count() );
439 | }
440 |
441 | fc::variant get_global_state() {
442 | vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global), N(global) );
443 | if (data.empty()) std::cout << "\nData is empty\n" << std::endl;
444 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state", data, abi_serializer_max_time );
445 | }
446 |
447 | fc::variant get_global_state2() {
448 | vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global2), N(global2) );
449 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state2", data, abi_serializer_max_time );
450 | }
451 |
452 | fc::variant get_global_state3() {
453 | vector data = get_row_by_account( config::system_account_name, config::system_account_name, N(global3), N(global3) );
454 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "eosio_global_state3", data, abi_serializer_max_time );
455 | }
456 |
457 | fc::variant get_refund_request( name account ) {
458 | vector data = get_row_by_account( config::system_account_name, account, N(refunds), account );
459 | return data.empty() ? fc::variant() : abi_ser.binary_to_variant( "refund_request", data, abi_serializer_max_time );
460 | }
461 |
462 | abi_serializer initialize_multisig() {
463 | abi_serializer msig_abi_ser;
464 | {
465 | create_account_with_resources( N(eosio.msig), config::system_account_name );
466 | BOOST_REQUIRE_EQUAL( success(), buyram( "eosio", "eosio.msig", core_sym::from_string("5000.0000") ) );
467 | produce_block();
468 |
469 | auto trace = base_tester::push_action(config::system_account_name, N(setpriv),
470 | config::system_account_name, mutable_variant_object()
471 | ("account", "eosio.msig")
472 | ("is_priv", 1)
473 | );
474 |
475 | set_code( N(eosio.msig), contracts::msig_wasm() );
476 | set_abi( N(eosio.msig), contracts::msig_abi().data() );
477 |
478 | produce_blocks();
479 | const auto& accnt = control->db().get( N(eosio.msig) );
480 | abi_def msig_abi;
481 | BOOST_REQUIRE_EQUAL(abi_serializer::to_abi(accnt.abi, msig_abi), true);
482 | msig_abi_ser.set_abi(msig_abi, abi_serializer_max_time);
483 | }
484 | return msig_abi_ser;
485 | }
486 |
487 | vector active_and_vote_producers() {
488 | //stake more than 15% of total EOS supply to activate chain
489 | transfer( "eosio", "alice1111111", core_sym::from_string("650000000.0000"), "eosio" );
490 | BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_sym::from_string("300000000.0000"), core_sym::from_string("300000000.0000") ) );
491 |
492 | // create accounts {defproducera, defproducerb, ..., defproducerz} and register as producers
493 | std::vector producer_names;
494 | {
495 | producer_names.reserve('z' - 'a' + 1);
496 | const std::string root("defproducer");
497 | for ( char c = 'a'; c < 'a'+21; ++c ) {
498 | producer_names.emplace_back(root + std::string(1, c));
499 | }
500 | setup_producer_accounts(producer_names);
501 | for (const auto& p: producer_names) {
502 |
503 | BOOST_REQUIRE_EQUAL( success(), regproducer(p) );
504 | }
505 | }
506 | produce_blocks( 250);
507 |
508 | auto trace_auth = TESTER::push_action(config::system_account_name, updateauth::get_name(), config::system_account_name, mvo()
509 | ("account", name(config::system_account_name).to_string())
510 | ("permission", name(config::active_name).to_string())
511 | ("parent", name(config::owner_name).to_string())
512 | ("auth", authority(1, {key_weight{get_public_key( config::system_account_name, "active" ), 1}}, {
513 | permission_level_weight{{config::system_account_name, config::eosio_code_name}, 1},
514 | permission_level_weight{{config::producers_account_name, config::active_name}, 1}
515 | }
516 | ))
517 | );
518 | BOOST_REQUIRE_EQUAL(transaction_receipt::executed, trace_auth->receipt->status);
519 |
520 | //vote for producers
521 | {
522 | transfer( config::system_account_name, "alice1111111", core_sym::from_string("100000000.0000"), config::system_account_name );
523 | BOOST_REQUIRE_EQUAL(success(), stake( "alice1111111", core_sym::from_string("30000000.0000"), core_sym::from_string("30000000.0000") ) );
524 | BOOST_REQUIRE_EQUAL(success(), buyram( "alice1111111", "alice1111111", core_sym::from_string("30000000.0000") ) );
525 | BOOST_REQUIRE_EQUAL(success(), push_action(N(alice1111111), N(voteproducer), mvo()
526 | ("voter", "alice1111111")
527 | ("proxy", name(0).to_string())
528 | ("producers", vector(producer_names.begin(), producer_names.begin()+21))
529 | )
530 | );
531 | }
532 | produce_blocks( 250 );
533 |
534 | auto producer_keys = control->head_block_state()->active_schedule.producers;
535 | BOOST_REQUIRE_EQUAL( 21, producer_keys.size() );
536 | BOOST_REQUIRE_EQUAL( name("defproducera"), producer_keys[0].producer_name );
537 |
538 | return producer_names;
539 | }
540 |
541 | void cross_15_percent_threshold() {
542 | setup_producer_accounts({N(producer1111)});
543 | regproducer(N(producer1111));
544 | {
545 | signed_transaction trx;
546 | set_transaction_headers(trx);
547 |
548 | trx.actions.emplace_back( get_action( config::system_account_name, N(delegatebw),
549 | vector{{config::system_account_name, config::active_name}},
550 | mvo()
551 | ("from", name{config::system_account_name})
552 | ("receiver", "producer1111")
553 | ("stake_net_quantity", core_sym::from_string("150000000.0000") )
554 | ("stake_cpu_quantity", core_sym::from_string("0.0000") )
555 | ("transfer", 1 )
556 | )
557 | );
558 | trx.actions.emplace_back( get_action( config::system_account_name, N(voteproducer),
559 | vector{{N(producer1111), config::active_name}},
560 | mvo()
561 | ("voter", "producer1111")
562 | ("proxy", name(0).to_string())
563 | ("producers", vector(1, N(producer1111)))
564 | )
565 | );
566 | trx.actions.emplace_back( get_action( config::system_account_name, N(undelegatebw),
567 | vector{{N(producer1111), config::active_name}},
568 | mvo()
569 | ("from", "producer1111")
570 | ("receiver", "producer1111")
571 | ("unstake_net_quantity", core_sym::from_string("150000000.0000") )
572 | ("unstake_cpu_quantity", core_sym::from_string("0.0000") )
573 | )
574 | );
575 |
576 | set_transaction_headers(trx);
577 | trx.sign( get_private_key( config::system_account_name, "active" ), control->get_chain_id() );
578 | trx.sign( get_private_key( N(producer1111), "active" ), control->get_chain_id() );
579 | push_transaction( trx );
580 | produce_block();
581 | }
582 | }
583 |
584 | abi_serializer abi_ser;
585 | abi_serializer token_abi_ser;
586 | };
587 |
588 | inline fc::mutable_variant_object voter( account_name acct ) {
589 | return mutable_variant_object()
590 | ("owner", acct)
591 | ("proxy", name(0).to_string())
592 | ("producers", variants() )
593 | ("staked", int64_t(0))
594 | //("last_vote_weight", double(0))
595 | ("proxied_vote_weight", double(0))
596 | ("is_proxy", 0)
597 | ;
598 | }
599 |
600 | inline fc::mutable_variant_object voter( account_name acct, const asset& vote_stake ) {
601 | return voter( acct )( "staked", vote_stake.get_amount() );
602 | }
603 |
604 | inline fc::mutable_variant_object voter( account_name acct, int64_t vote_stake ) {
605 | return voter( acct )( "staked", vote_stake );
606 | }
607 |
608 | inline fc::mutable_variant_object proxy( account_name acct ) {
609 | return voter( acct )( "is_proxy", 1 );
610 | }
611 |
612 | inline uint64_t M( const string& eos_str ) {
613 | return core_sym::from_string( eos_str ).get_amount();
614 | }
615 |
616 | }
617 |
--------------------------------------------------------------------------------
/tests/tests/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include "eosio.system_tester.hpp"
14 |
15 | using namespace eosio_system;
16 | #define BOOST_TEST_STATIC_LINK
17 |
18 | void translate_fc_exception(const fc::exception &e) {
19 | std::cerr << "\033[33m" << e.to_detail_string() << "\033[0m" << std::endl;
20 | BOOST_TEST_FAIL("Caught Unexpected Exception");
21 | }
22 |
23 | boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
24 | // Turn off blockchain logging if no --verbose parameter is not added
25 | // To have verbose enabled, call "tests/chain_test -- --verbose"
26 | bool is_verbose = false;
27 | std::string verbose_arg = "--verbose";
28 | for (int i = 0; i < argc; i++) {
29 | if (verbose_arg == argv[i]) {
30 | is_verbose = true;
31 | break;
32 | }
33 | }
34 | if(!is_verbose) fc::logger::get(DEFAULT_LOGGER).set_log_level(fc::log_level::off);
35 |
36 | // Register fc::exception translator
37 | boost::unit_test::unit_test_monitor.template register_exception_translator(&translate_fc_exception);
38 |
39 | std::srand(time(NULL));
40 | std::cout << "Random number generator seeded to " << time(NULL) << std::endl;
41 | return nullptr;
42 | }
43 |
--------------------------------------------------------------------------------
/tests/tests/test_contracts/eosio.msig/eosio.msig.abi:
--------------------------------------------------------------------------------
1 | {
2 | "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Jan 4 07:43:36 2019",
3 | "version": "eosio::abi/1.1",
4 | "structs": [
5 | {
6 | "name": "action",
7 | "base": "",
8 | "fields": [
9 | {
10 | "name": "account",
11 | "type": "name"
12 | },
13 | {
14 | "name": "name",
15 | "type": "name"
16 | },
17 | {
18 | "name": "authorization",
19 | "type": "permission_level[]"
20 | },
21 | {
22 | "name": "data",
23 | "type": "bytes"
24 | }
25 | ]
26 | },
27 | {
28 | "name": "approval",
29 | "base": "",
30 | "fields": [
31 | {
32 | "name": "level",
33 | "type": "permission_level"
34 | },
35 | {
36 | "name": "time",
37 | "type": "time_point"
38 | }
39 | ]
40 | },
41 | {
42 | "name": "approvals_info",
43 | "base": "",
44 | "fields": [
45 | {
46 | "name": "version",
47 | "type": "uint8"
48 | },
49 | {
50 | "name": "proposal_name",
51 | "type": "name"
52 | },
53 | {
54 | "name": "requested_approvals",
55 | "type": "approval[]"
56 | },
57 | {
58 | "name": "provided_approvals",
59 | "type": "approval[]"
60 | }
61 | ]
62 | },
63 | {
64 | "name": "approve",
65 | "base": "",
66 | "fields": [
67 | {
68 | "name": "proposer",
69 | "type": "name"
70 | },
71 | {
72 | "name": "proposal_name",
73 | "type": "name"
74 | },
75 | {
76 | "name": "level",
77 | "type": "permission_level"
78 | },
79 | {
80 | "name": "proposal_hash",
81 | "type": "checksum256$"
82 | }
83 | ]
84 | },
85 | {
86 | "name": "cancel",
87 | "base": "",
88 | "fields": [
89 | {
90 | "name": "proposer",
91 | "type": "name"
92 | },
93 | {
94 | "name": "proposal_name",
95 | "type": "name"
96 | },
97 | {
98 | "name": "canceler",
99 | "type": "name"
100 | }
101 | ]
102 | },
103 | {
104 | "name": "exec",
105 | "base": "",
106 | "fields": [
107 | {
108 | "name": "proposer",
109 | "type": "name"
110 | },
111 | {
112 | "name": "proposal_name",
113 | "type": "name"
114 | },
115 | {
116 | "name": "executer",
117 | "type": "name"
118 | }
119 | ]
120 | },
121 | {
122 | "name": "extension",
123 | "base": "",
124 | "fields": [
125 | {
126 | "name": "type",
127 | "type": "uint16"
128 | },
129 | {
130 | "name": "data",
131 | "type": "bytes"
132 | }
133 | ]
134 | },
135 | {
136 | "name": "invalidate",
137 | "base": "",
138 | "fields": [
139 | {
140 | "name": "account",
141 | "type": "name"
142 | }
143 | ]
144 | },
145 | {
146 | "name": "invalidation",
147 | "base": "",
148 | "fields": [
149 | {
150 | "name": "account",
151 | "type": "name"
152 | },
153 | {
154 | "name": "last_invalidation_time",
155 | "type": "time_point"
156 | }
157 | ]
158 | },
159 | {
160 | "name": "old_approvals_info",
161 | "base": "",
162 | "fields": [
163 | {
164 | "name": "proposal_name",
165 | "type": "name"
166 | },
167 | {
168 | "name": "requested_approvals",
169 | "type": "permission_level[]"
170 | },
171 | {
172 | "name": "provided_approvals",
173 | "type": "permission_level[]"
174 | }
175 | ]
176 | },
177 | {
178 | "name": "permission_level",
179 | "base": "",
180 | "fields": [
181 | {
182 | "name": "actor",
183 | "type": "name"
184 | },
185 | {
186 | "name": "permission",
187 | "type": "name"
188 | }
189 | ]
190 | },
191 | {
192 | "name": "proposal",
193 | "base": "",
194 | "fields": [
195 | {
196 | "name": "proposal_name",
197 | "type": "name"
198 | },
199 | {
200 | "name": "packed_transaction",
201 | "type": "bytes"
202 | }
203 | ]
204 | },
205 | {
206 | "name": "propose",
207 | "base": "",
208 | "fields": [
209 | {
210 | "name": "proposer",
211 | "type": "name"
212 | },
213 | {
214 | "name": "proposal_name",
215 | "type": "name"
216 | },
217 | {
218 | "name": "requested",
219 | "type": "permission_level[]"
220 | },
221 | {
222 | "name": "trx",
223 | "type": "transaction"
224 | }
225 | ]
226 | },
227 | {
228 | "name": "transaction",
229 | "base": "transaction_header",
230 | "fields": [
231 | {
232 | "name": "context_free_actions",
233 | "type": "action[]"
234 | },
235 | {
236 | "name": "actions",
237 | "type": "action[]"
238 | },
239 | {
240 | "name": "transaction_extensions",
241 | "type": "extension[]"
242 | }
243 | ]
244 | },
245 | {
246 | "name": "transaction_header",
247 | "base": "",
248 | "fields": [
249 | {
250 | "name": "expiration",
251 | "type": "time_point_sec"
252 | },
253 | {
254 | "name": "ref_block_num",
255 | "type": "uint16"
256 | },
257 | {
258 | "name": "ref_block_prefix",
259 | "type": "uint32"
260 | },
261 | {
262 | "name": "max_net_usage_words",
263 | "type": "varuint32"
264 | },
265 | {
266 | "name": "max_cpu_usage_ms",
267 | "type": "uint8"
268 | },
269 | {
270 | "name": "delay_sec",
271 | "type": "varuint32"
272 | }
273 | ]
274 | },
275 | {
276 | "name": "unapprove",
277 | "base": "",
278 | "fields": [
279 | {
280 | "name": "proposer",
281 | "type": "name"
282 | },
283 | {
284 | "name": "proposal_name",
285 | "type": "name"
286 | },
287 | {
288 | "name": "level",
289 | "type": "permission_level"
290 | }
291 | ]
292 | }
293 | ],
294 | "types": [],
295 | "actions": [
296 | {
297 | "name": "approve",
298 | "type": "approve",
299 | "ricardian_contract": ""
300 | },
301 | {
302 | "name": "cancel",
303 | "type": "cancel",
304 | "ricardian_contract": ""
305 | },
306 | {
307 | "name": "exec",
308 | "type": "exec",
309 | "ricardian_contract": ""
310 | },
311 | {
312 | "name": "invalidate",
313 | "type": "invalidate",
314 | "ricardian_contract": ""
315 | },
316 | {
317 | "name": "propose",
318 | "type": "propose",
319 | "ricardian_contract": ""
320 | },
321 | {
322 | "name": "unapprove",
323 | "type": "unapprove",
324 | "ricardian_contract": ""
325 | }
326 | ],
327 | "tables": [
328 | {
329 | "name": "approvals",
330 | "type": "old_approvals_info",
331 | "index_type": "i64",
332 | "key_names": [],
333 | "key_types": []
334 | },
335 | {
336 | "name": "approvals2",
337 | "type": "approvals_info",
338 | "index_type": "i64",
339 | "key_names": [],
340 | "key_types": []
341 | },
342 | {
343 | "name": "invals",
344 | "type": "invalidation",
345 | "index_type": "i64",
346 | "key_names": [],
347 | "key_types": []
348 | },
349 | {
350 | "name": "proposal",
351 | "type": "proposal",
352 | "index_type": "i64",
353 | "key_names": [],
354 | "key_types": []
355 | }
356 | ],
357 | "ricardian_clauses": [],
358 | "variants": [],
359 | "abi_extensions": []
360 | }
--------------------------------------------------------------------------------
/tests/tests/test_contracts/eosio.msig/eosio.msig.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EOSLaoMao/BankofStaked-CE/3b764debe9bad8047c0cf28930b91b7a736a09d6/tests/tests/test_contracts/eosio.msig/eosio.msig.wasm
--------------------------------------------------------------------------------
/tests/tests/test_contracts/eosio.system/eosio.system.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EOSLaoMao/BankofStaked-CE/3b764debe9bad8047c0cf28930b91b7a736a09d6/tests/tests/test_contracts/eosio.system/eosio.system.wasm
--------------------------------------------------------------------------------
/tests/tests/test_contracts/eosio.token/eosio.token.abi:
--------------------------------------------------------------------------------
1 | {
2 | "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Fri Jan 4 07:43:34 2019",
3 | "version": "eosio::abi/1.1",
4 | "structs": [
5 | {
6 | "name": "account",
7 | "base": "",
8 | "fields": [
9 | {
10 | "name": "balance",
11 | "type": "asset"
12 | }
13 | ]
14 | },
15 | {
16 | "name": "close",
17 | "base": "",
18 | "fields": [
19 | {
20 | "name": "owner",
21 | "type": "name"
22 | },
23 | {
24 | "name": "symbol",
25 | "type": "symbol"
26 | }
27 | ]
28 | },
29 | {
30 | "name": "create",
31 | "base": "",
32 | "fields": [
33 | {
34 | "name": "issuer",
35 | "type": "name"
36 | },
37 | {
38 | "name": "maximum_supply",
39 | "type": "asset"
40 | }
41 | ]
42 | },
43 | {
44 | "name": "currency_stats",
45 | "base": "",
46 | "fields": [
47 | {
48 | "name": "supply",
49 | "type": "asset"
50 | },
51 | {
52 | "name": "max_supply",
53 | "type": "asset"
54 | },
55 | {
56 | "name": "issuer",
57 | "type": "name"
58 | }
59 | ]
60 | },
61 | {
62 | "name": "issue",
63 | "base": "",
64 | "fields": [
65 | {
66 | "name": "to",
67 | "type": "name"
68 | },
69 | {
70 | "name": "quantity",
71 | "type": "asset"
72 | },
73 | {
74 | "name": "memo",
75 | "type": "string"
76 | }
77 | ]
78 | },
79 | {
80 | "name": "open",
81 | "base": "",
82 | "fields": [
83 | {
84 | "name": "owner",
85 | "type": "name"
86 | },
87 | {
88 | "name": "symbol",
89 | "type": "symbol"
90 | },
91 | {
92 | "name": "ram_payer",
93 | "type": "name"
94 | }
95 | ]
96 | },
97 | {
98 | "name": "retire",
99 | "base": "",
100 | "fields": [
101 | {
102 | "name": "quantity",
103 | "type": "asset"
104 | },
105 | {
106 | "name": "memo",
107 | "type": "string"
108 | }
109 | ]
110 | },
111 | {
112 | "name": "transfer",
113 | "base": "",
114 | "fields": [
115 | {
116 | "name": "from",
117 | "type": "name"
118 | },
119 | {
120 | "name": "to",
121 | "type": "name"
122 | },
123 | {
124 | "name": "quantity",
125 | "type": "asset"
126 | },
127 | {
128 | "name": "memo",
129 | "type": "string"
130 | }
131 | ]
132 | }
133 | ],
134 | "types": [],
135 | "actions": [
136 | {
137 | "name": "close",
138 | "type": "close",
139 | "ricardian_contract": ""
140 | },
141 | {
142 | "name": "create",
143 | "type": "create",
144 | "ricardian_contract": ""
145 | },
146 | {
147 | "name": "issue",
148 | "type": "issue",
149 | "ricardian_contract": ""
150 | },
151 | {
152 | "name": "open",
153 | "type": "open",
154 | "ricardian_contract": ""
155 | },
156 | {
157 | "name": "retire",
158 | "type": "retire",
159 | "ricardian_contract": ""
160 | },
161 | {
162 | "name": "transfer",
163 | "type": "transfer",
164 | "ricardian_contract": ""
165 | }
166 | ],
167 | "tables": [
168 | {
169 | "name": "accounts",
170 | "type": "account",
171 | "index_type": "i64",
172 | "key_names": [],
173 | "key_types": []
174 | },
175 | {
176 | "name": "stat",
177 | "type": "currency_stats",
178 | "index_type": "i64",
179 | "key_names": [],
180 | "key_types": []
181 | }
182 | ],
183 | "ricardian_clauses": [],
184 | "variants": [],
185 | "abi_extensions": []
186 | }
--------------------------------------------------------------------------------
/tests/tests/test_contracts/eosio.token/eosio.token.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EOSLaoMao/BankofStaked-CE/3b764debe9bad8047c0cf28930b91b7a736a09d6/tests/tests/test_contracts/eosio.token/eosio.token.wasm
--------------------------------------------------------------------------------
/tests/tests/test_symbol.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define CORE_SYM_NAME "EOS"
4 | #define CORE_SYM_PRECISION 4
5 |
6 | #define _STRINGIZE1(x) #x
7 | #define _STRINGIZE2(x) _STRINGIZE1(x)
8 |
9 | #define CORE_SYM_STR ( _STRINGIZE2(CORE_SYM_PRECISION) "," CORE_SYM_NAME )
10 | #define CORE_SYM ( ::eosio::chain::string_to_symbol_c( CORE_SYM_PRECISION, CORE_SYM_NAME ) )
11 |
12 | struct core_sym {
13 | static inline eosio::chain::asset from_string(const std::string& s) {
14 | return eosio::chain::asset::from_string(s + " " CORE_SYM_NAME);
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/unittest.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | RED='\033[01;31m'
3 |
4 | cd /bankofstaked/tests
5 | ./clean-build.sh
6 |
7 | ./build.sh
8 |
9 | ./build/tests/unit_test -- --verbose
10 |
11 | if [ $? -eq 0 ]; then
12 | echo "Run unit test success"
13 | else
14 | echo -e "-----------------------------------"
15 | echo -e "${RED}Please run ./build.sh first."
16 | echo -e "-----------------------------------"
17 | fi
18 |
--------------------------------------------------------------------------------