All Products
Search
Document Center

Contract Examples

Last Updated: Jan 09, 2020

This topic is a reference to help you design a contract as required. The smart contract-based system for managing housing rental points is used as an example.

Note: The following example is for reference only and cannot be used in production environments.

Background

The blockchain smart contract-based system used to manage housing rental points efficiently provides services for individuals and organizations. It helps those involved in city development find affordable houses to rent and those who contribute to long-term city development to find houses to buy. With the blockchain, big data, and other cutting-edge technologies, this system provides a housing rental point mechanism based on the main characteristics of the housing rental market, incentives, and rental behavior. This system implements an effective, scientific system to manage the lifecycles of housing rental points and creates a dynamic, healthy, organized, and sustainable housing rental ecosystem.

Purpose

The system uses the blockchain platform to protect privacy and prevent data from being tampered with. This system provides a point decision-making engine and a point evaluation mechanism and gives a comprehensive point solution for housing rental. This implements fairness, impartiality, and transparency. This solution is horizontally expandable. It relies on its unchanged fundamental technologies and data. This system supports the construction of diverse point systems (such as an economic credit point system or green living point system) for the future and can be expanded to an urban credit system for medical education, financial lending, green living, and other scenarios.

Contract design

Roles

In the system used to manage housing rental points, there are four roles: administrators, calculators, observers, and players. Administrators, calculators, and observers conduct operations on smart contracts, and each role can correspond to multiple persons. Players are the core users of smart contracts for rental points.

Permissions on roles

  • An administrator acts as a super administrator of contracts. The super administrator can add, delete, or query administrators, calculators, and observers.
  • A calculator can view information about calculators.
  • An observer can view information about observers.

1

Permissions on points

  • An administrator can reward, query, transfer, deduct, and exchange points.
  • A calculator is specified by the administrator, and can be a person or system service. A calculator can reward, transfer, deduct, and exchange points.
  • An observer is specified by the administrator, and can be a person or system service. An observer can only query points.
  • A player is a user of the housing rental point system and benefits from this system.
    • A player can obtain points by using observer permissions to query rental points from the external service system proxy of an organization.
    • The external service system for rental points rewards or deducts points for a player based on player’s performance.
    • A player can transfer or exchange points by using administrator permissions to query rental points from the external service system proxy of an organization.

2

Point management

Smart contracts for rental points provide the following service methods: awardScore, queryScore, exchangeScore, deductScore, transferScore, and SCORE_EQUITY_NOTICE triggered after points reach the upper limit.

3

Point reward (awardScore)

Accumulates points for players while they rent houses based on the rental period and behavior.

Point query (queryScore)

Enables players to obtain their points by using the observer permissions of the external service system for rental points.

Point exchange (exchangeScore)

Allows players to receive benefits, such as preferential rental, qualifications for buying a house, and qualifications for settling down, after their points reach a specific threshold.

Point deduction (deductScore)

Deducts points for player violations while they rent houses. Housing rental points are used to encourage players. In regards to information falsification, player points are deducted, players are disqualified, and their rights and interests to exchange points are reclaimed based on the severity of the circumstances.

Point event (SCORE_EQUITY_NOTICE)

When point rights and interests are added in real time, they will be checked. If points reach a specific threshold, an event for notifying related rights and interests will be triggered. The external service system notifies players of these rights and interests.

Point transfer (transferScore)

If a player moves to another city, his/her points can be transferred to the point system in the destination city. To call the original contract, the target contract must have the awardScore method, and provide operation permissions for the original contract. Make sure that the address of the original contract must be the administrator or calculator.

Smart contract code

  1. pragma solidity ^0.4.20;
  2. contract LeasingScoreManager {
  3. identity[] adminList;
  4. identity[] observerList;
  5. identity[] calculatorList;
  6. //Record elements that are set in management arrays.
  7. uint adminDeled;
  8. uint observerDeled;
  9. uint calculatorDeled;
  10. mapping (bytes32 => uint) leasingScore;
  11. enum ScoreAction {
  12. //Perform point reward based on behavior.
  13. ActionAwardScore,
  14. //Exchange specified points.
  15. ActionExchangeScore,
  16. //Deduct points due to violations.
  17. ActionDeductScore,
  18. //Query points.
  19. ActionQueryScore
  20. //Transfer points to another contract.
  21. }
  22. enum UserRole {
  23. RoleAdmin, //Administrator
  24. RoleCalculator, //Calculator
  25. RoleObserver, //Observer
  26. RolePlayer //Player
  27. }
  28. //Whether the calculator is valid.
  29. event VALID(bool valid, UserRole role);
  30. //Whether the administrator, observer, or calculator exists.
  31. event USER_EXIST(bool exist, UserRole role);
  32. //Point event
  33. event SCORE_OPERATOR(ScoreAction action, string describe);
  34. //Incorrect operation on points
  35. event SCORE_ERROR(ScoreAction action, string describe);
  36. //Notification of rights and interests
  37. event SCORE_EQUITY_NOTICE(string action, uint score, string describe);
  38. constructor() public {
  39. adminList.push(msg.sender);
  40. adminList.push(this);
  41. }
  42. function indexAdmin(identity admin) view returns (uint) {
  43. for (uint i = 0; i < adminList.length; i++) {
  44. if (adminList[i] == admin) {
  45. return i;
  46. }
  47. }
  48. return adminList.length;
  49. }
  50. function validAdmin(identity admin) view returns (bool) {
  51. return indexAdmin(admin) < adminList.length;
  52. }
  53. function indexCalculator(identity calculator) view returns (uint) {
  54. for (uint i = 0; i < calculatorList.length; i++) {
  55. if (calculatorList[i] == calculator) {
  56. return i;
  57. }
  58. }
  59. return calculatorList.length;
  60. }
  61. function validCalculator(identity calculator) view returns (bool) {
  62. return indexCalculator(calculator) < calculatorList.length;
  63. }
  64. function indexObserver(identity observer) view returns (uint) {
  65. for (uint i = 0; i < observerList.length; i++) {
  66. if (observerList[i] == observer) {
  67. return i;
  68. }
  69. }
  70. return observerList.length;
  71. }
  72. function validObserver(identity observer) view returns (bool) {
  73. return indexObserver(observer) < observerList.length;
  74. }
  75. modifier onlyAdmin {
  76. bool isValid = validAdmin(msg.sender);
  77. emit VALID(isValid, UserRole.RoleAdmin);
  78. require(isValid);
  79. _;
  80. }
  81. modifier onlyCalculatorOrAdmin {
  82. bool isValid = validAdmin(msg.sender);
  83. if(isValid) {
  84. emit VALID(isValid, UserRole.RoleAdmin);
  85. } else {
  86. isValid = validCalculator(msg.sender);
  87. emit VALID(isValid, UserRole.RoleCalculator);
  88. }
  89. require(isValid);
  90. _;
  91. }
  92. modifier onlyObserverOrAdmin {
  93. bool isValid = validAdmin(msg.sender);
  94. if(isValid) {
  95. emit VALID(isValid, UserRole.RoleAdmin);
  96. } else {
  97. isValid = validObserver(msg.sender);
  98. emit VALID(isValid, UserRole.RoleObserver);
  99. }
  100. require(isValid);
  101. _;
  102. }
  103. function addAdmin(identity admin) public onlyAdmin {
  104. bool isExist = validAdmin(admin);
  105. emit USER_EXIST(isExist, UserRole.RoleAdmin);
  106. require(!isExist);
  107. if(adminDeled > 0) {
  108. uint deled = 1;
  109. for (uint i = 0; i < adminList.length; i++) {
  110. if(deled&adminDeled != 0) {
  111. adminList[i] = admin;
  112. adminDeled ^= deled;
  113. break;
  114. }
  115. deled <<= 1;
  116. }
  117. } else {
  118. adminList.push(admin);
  119. }
  120. }
  121. function removeAdmin(identity admin) public onlyAdmin {
  122. uint index = indexAdmin(admin);
  123. bool isValid = index != adminList.length;
  124. emit USER_EXIST(isValid, UserRole.RoleAdmin);
  125. require(isValid);
  126. delete adminList[index];
  127. adminDeled ^= 1 << index;
  128. }
  129. function queryAdmins() view public onlyAdmin returns (identity[]) {
  130. return adminList;
  131. }
  132. function addCalculator(identity calculator) public onlyAdmin {
  133. bool isExist = validCalculator(calculator);
  134. emit USER_EXIST(isExist, UserRole.RoleCalculator);
  135. require(!isExist);
  136. if(calculatorDeled > 0) {
  137. uint deled = 1;
  138. for (uint i = 0; i < calculatorList.length; i++) {
  139. if(deled&calculatorDeled != 0) {
  140. calculatorList[i] = calculator;
  141. calculatorDeled ^= deled;
  142. break;
  143. }
  144. deled <<= 1;
  145. }
  146. } else {
  147. calculatorList.push(calculator);
  148. }
  149. }
  150. function removeCalculator(identity calculator) public onlyAdmin {
  151. uint index = indexCalculator(calculator);
  152. bool isValid = index < calculatorList.length;
  153. emit USER_EXIST(isValid, UserRole.RoleCalculator);
  154. require(isValid);
  155. delete calculatorList[index];
  156. calculatorDeled ^= 1 << index;
  157. }
  158. function queryCalculators() view public onlyCalculatorOrAdmin returns (identity[]) {
  159. return calculatorList;
  160. }
  161. function addObserver(identity observer) public onlyAdmin {
  162. bool isExist = validObserver(observer);
  163. emit USER_EXIST(isExist, UserRole.RoleObserver);
  164. require(!isExist);
  165. if(observerDeled > 0) {
  166. uint deled = 1;
  167. for (uint i = 0; i < observerList.length; i++) {
  168. if(deled&observerDeled != 0) {
  169. observerList[i] = observer;
  170. observerDeled ^= deled;
  171. break;
  172. }
  173. deled <<= 1;
  174. }
  175. } else {
  176. observerList.push(observer);
  177. }
  178. }
  179. function removeObserver(identity observer) public onlyAdmin {
  180. uint index = indexCalculator(observer);
  181. bool isValid = index < observerList.length;
  182. emit USER_EXIST(isValid, UserRole.RoleObserver);
  183. require(isValid);
  184. delete observerList[index];
  185. observerDeled ^= 1 << index;
  186. }
  187. function queryObservers() view public onlyObserverOrAdmin returns (identity[]) {
  188. return observerList;
  189. }
  190. function checkScoreEquity(uint balance, uint score) {
  191. uint total = balance + score;
  192. if(total >= 100 && balance < 100) {
  193. emit SCORE_EQUITY_NOTICE("RentConcessions", total, "Citizens enjoy a 90% discount on rental housing");
  194. }
  195. if(total >= 200 && balance < 200) {
  196. emit SCORE_EQUITY_NOTICE("RentConcessions_1", total, "Citizens enjoy a 80% discount on rental housing");
  197. }
  198. if(total >= 300 && balance < 300) {
  199. emit SCORE_EQUITY_NOTICE("PurchaseDiscount", total, "Citizens enjoy a 90% discount on purchase housing");
  200. }
  201. }
  202. //Point reward
  203. function awardScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin {
  204. uint balance = leasingScore[player];
  205. leasingScore[player] = balance + score;
  206. emit SCORE_OPERATOR(ScoreAction.ActionAwardScore, describe);
  207. checkScoreEquity(balance, score);
  208. }
  209. //Point exchange by the player. If points are not enough, points will not be deducted, and a failure event will be reported.
  210. function exchangeScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin returns (bool) {
  211. emit SCORE_OPERATOR(ScoreAction.ActionExchangeScore, describe);
  212. if(leasingScore[player] >= score) {
  213. leasingScore[player] -= score;
  214. return true;
  215. }
  216. emit SCORE_ERROR(ScoreAction.ActionExchangeScore, "Score not enough to exchange");
  217. return false;
  218. }
  219. //Point deduction that is not initiated by the player. If points are not enough for the deduction, points will be cleared, and a failure event will be reported.
  220. function deductScore(bytes32 player, uint score, string describe) public onlyCalculatorOrAdmin {
  221. emit SCORE_OPERATOR(ScoreAction.ActionDeductScore, describe);
  222. uint balance = leasingScore[player];
  223. if(balance >= score) {
  224. leasingScore[player] -= score;
  225. } else {
  226. if(balance != 0) {
  227. leasingScore[player] = 0;
  228. }
  229. emit SCORE_ERROR(ScoreAction.ActionDeductScore, "Score not enough to deduct");
  230. }
  231. }
  232. //Point query
  233. function queryScore(bytes32 player, string describe) view public onlyObserverOrAdmin returns (uint) {
  234. emit SCORE_OPERATOR(ScoreAction.ActionQueryScore, describe);
  235. return leasingScore[player];
  236. }
  237. //String combination
  238. function stringAdd(string a, string b) returns(string){
  239. bytes memory _a = bytes(a);
  240. bytes memory _b = bytes(b);
  241. bytes memory res = new bytes(_a.length + _b.length);
  242. for(uint i = 0;i < _a.length;i++)
  243. res[i] = _a[i];
  244. for(uint j = 0;j < _b.length;j++)
  245. res[_a.length+j] = _b[j];
  246. return string(res);
  247. }
  248. //Point transfer to another contract
  249. function transferScore(bytes32 player, uint score, LeasingScoreManager toContract, string describe) public onlyCalculatorOrAdmin {
  250. //Point deduction if points are enough
  251. describe = stringAdd("Transfer score: ", describe);
  252. require(exchangeScore(player, score, describe));
  253. toContract.awardScore(player, score, describe);
  254. }
  255. }