Guest User

Untitled

a guest
Jul 16th, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.30 KB | None | 0 0
  1. pragma solidity ^0.4.18;
  2.  
  3. import "zeppelin-solidity/contracts/math/SafeMath.sol";
  4. import "zeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol";
  5.  
  6. import "../mixins/BalanceManager.sol";
  7. import "../mixins/Domicile.sol";
  8.  
  9. import "./BaseRegulatorService.sol";
  10. import "../RegulatedToken.sol";
  11.  
  12.  
  13. /**
  14. * @title On-chain RegulatorService for approving US REIT trades
  15. * @author Elpizo Choi
  16. */
  17. contract REITRegulatorService is BaseRegulatorService, BalanceManager, Domicile {
  18. using SafeMath for uint256;
  19.  
  20. // @dev REIT specific settings that affect token trading at a token level.
  21. struct REITSettings {
  22.  
  23. // @dev Min number of shareholders a token can have
  24. uint256 shareholderMin;
  25.  
  26. // @dev Max number of shareholders a token can have
  27. uint256 shareholderMax;
  28.  
  29. /**
  30. * @dev Max percentage of shares a shareholder can have,
  31. * represented in integers. Ex: 10% will be represented as 10.
  32. */
  33. uint8 ownershipCap;
  34.  
  35. /**
  36. * @dev Max percentage of shares that can be owned by foreign
  37. * shareholders, represented in integers.
  38. * Ex: 50% is represented as 50.
  39. */
  40. uint8 foreignOwnedSharesCap;
  41.  
  42. /**
  43. * @dev Current count of shareholders.
  44. * Updated on `transfer()` functions success.
  45. */
  46. uint256 shareholderCount;
  47.  
  48. // @dev Current count of foreign owned shares.
  49. // Updated after successful `transfer()` calls.
  50. uint256 foreignOwnedShares;
  51. }
  52.  
  53. // @notice Permissions that allow/disallow token trades on a per token level
  54. mapping(address => REITSettings) private reitSettings;
  55.  
  56. // @dev Event raised when a token's shareholder min setting is set
  57. event LogShareholderMinSet(address indexed _token, uint256 _min);
  58.  
  59. // @dev Event raised when a token's shareholder max setting is set
  60. event LogShareholderMaxSet(address indexed _token, uint256 _max);
  61.  
  62. // @dev Event raised when a token's shareholder cap setting is set
  63. event LogOwnershipCapSet(address indexed _token, uint8 _cap);
  64.  
  65. // @dev Event raised when a token's foreign shareholder cap is set
  66. event LogForeignOwnedSharesCapSet(address indexed _token, uint8 _cap);
  67.  
  68. // @dev Event raised when a token's shareholder max setting is set
  69. event LogShareholderCountSet(address indexed _token, uint256 _count);
  70.  
  71. // @dev Event raised when a token's foreign shares count is set
  72. event LogForeignOwnedSharesSet(address indexed _token, uint256 _shares);
  73.  
  74. /**
  75. * @notice Sets shareholder min for a token
  76. *
  77. * @dev This method can only be called by this contract's admin
  78. *
  79. * @param _token The address of the token to update
  80. * @param _min The number of shareholders to set minimum to
  81. */
  82. function setShareholderMin(address _token, uint256 _min) public onlyRole(ROLE_ADMIN) {
  83. reitSettings[_token].shareholderMin = _min;
  84. emit LogShareholderMinSet(_token, _min);
  85. }
  86.  
  87. /**
  88. * @notice Sets shareholder max for a token
  89. *
  90. * @dev This method can only be called by this contract's admin
  91. *
  92. * @param _token The address of the token to update
  93. * @param _max The number of shareholders to set maximum to
  94. */
  95. function setShareholderMax(address _token, uint256 _max) public onlyRole(ROLE_ADMIN) {
  96. reitSettings[_token].shareholderMax = _max;
  97. emit LogShareholderMaxSet(_token, _max);
  98. }
  99.  
  100. /**
  101. * @notice Sets ownership cap for a token
  102. *
  103. * @dev This method can only be called by this contract's admin
  104. * Cap must be between 1 and 100.
  105. *
  106. * @param _token The address of the token to update
  107. * @param _cap The max ownership % a shareholder can have for given token.
  108. * Given in int form (ex: 10% would be represented as 10)
  109. */
  110. function setOwnershipCap(address _token, uint8 _cap) public onlyRole(ROLE_ADMIN) {
  111. require(_cap >= 1 && _cap <= 100, "Cap must be between 1 and 100");
  112. reitSettings[_token].ownershipCap = _cap;
  113. emit LogOwnershipCapSet(_token, _cap);
  114. }
  115.  
  116. /**
  117. * @notice Sets foreign owned shares cap for a token
  118. *
  119. * @dev This method can only be called by this contract's admin
  120. * Cap must be between 1 and 100.
  121. *
  122. * @param _token The address of the token to update
  123. * @param _cap The max % of foreign-owned shares a token can have.
  124. * Given in int form (ex: 50% is represented as 50).
  125. */
  126. function setForeignOwnedSharesCap(address _token, uint8 _cap)
  127. public
  128. onlyRole(ROLE_ADMIN)
  129. {
  130. require(_cap >= 1 && _cap <= 100, "Cap must be between 1 and 100");
  131. reitSettings[_token].foreignOwnedSharesCap = _cap;
  132. emit LogForeignOwnedSharesCapSet(_token, _cap);
  133. }
  134.  
  135. /**
  136. * @notice Public method to set `shareholderCount`
  137. *
  138. * @dev This method can only be called by this contract's admin
  139. *
  140. * @param _token The address of the token to update
  141. * @param _count The number of shareholders to set current count to
  142. */
  143. function setShareholderCount(address _token, uint256 _count)
  144. public
  145. onlyRole(ROLE_ADMIN)
  146. {
  147. _setShareholderCount(_token, _count);
  148. }
  149.  
  150. /**
  151. * @notice Public method to set `foreignOwnedShares`
  152. *
  153. * @dev This method can only be called by this contract's admin
  154. *
  155. * @param _token The address of the token to update
  156. * @param _count The number of foreign-owned shares for token
  157. */
  158. function setForeignOwnedShares(address _token, uint256 _count)
  159. public
  160. onlyRole(ROLE_ADMIN)
  161. {
  162. _setForeignOwnedShares(_token, _count);
  163. }
  164.  
  165. /**
  166. * @notice Sets `isForeign` flag for a participant on a token.
  167. * Also updates `foreignOwnedShares` based on direction of change.
  168. *
  169. * @dev This method can only be called by this contract's controller
  170. *
  171. * @param _token The address of the token to update
  172. * @param _participant The address of the trade participant
  173. * @param _isForeign Whether the participant is foreign for this token
  174. */
  175. function setIsForeign(
  176. address _token,
  177. bytes32 _participant,
  178. bool _isForeign
  179. ) public onlyRole(ROLE_CONTROLLER) {
  180. bool currForeign = isForeign[_token][_participant];
  181.  
  182. // Return if no change
  183. if (currForeign == _isForeign) {
  184. return;
  185. }
  186.  
  187. // Update `foreignOwnedShares`
  188. uint256 currShares = reitSettings[_token].foreignOwnedShares;
  189. uint256 balance = balances[_participant][_token];
  190.  
  191. // Add balance if becoming foreign
  192. if (_isForeign) {
  193. _setForeignOwnedShares(_token, currShares.add(balance));
  194.  
  195. // Subtract balance if becoming domestic
  196. } else {
  197. _setForeignOwnedShares(_token, currShares.sub(balance));
  198. }
  199.  
  200. super.setIsForeign(_token, _participant, _isForeign);
  201. }
  202.  
  203. /**
  204. * @notice Checks for REIT rules before calling `super.check()` for
  205. * generic token rules.
  206. *
  207. * @param _token The address of the token to be transferred
  208. * @param _spender The address of the spender of the token
  209. * (unused in this implementation)
  210. * @param _from The address of the sender account
  211. * @param _to The address of the receiver account
  212. * @param _amount The quantity of the token to trade
  213. *
  214. * @return `true` if the trade should be approved and
  215. * `false` if the trade should not be approved
  216. */
  217. function check(
  218. address _token,
  219. address _spender,
  220. address _from,
  221. address _to,
  222. uint256 _amount
  223. )
  224. public
  225. onlyTokenOrAdmin(_token)
  226. returns (uint8)
  227. {
  228. if (violatesShareholderMin(_token, _from, _to, _amount)) {
  229. return CHECK_ESHMIN;
  230. }
  231. if (violatesShareholderMax(_token, _from, _to, _amount)) {
  232. return CHECK_ESHMAX;
  233. }
  234. if (violatesOwnershipCap(_token, _to, _amount)) {
  235. return CHECK_EOWNCAP;
  236. }
  237. if (violatesForeignOwnedSharesCap(_token, _from, _to, _amount)) {
  238. return CHECK_EFOWNSCAP;
  239. }
  240. return super.check(_token, _spender, _from, _to, _amount);
  241. }
  242.  
  243. /**
  244. * @notice Updates `shareholderCount` and `foreignOwnedShares`
  245. * after `mint()` is successfully called by a `RegulatedToken`
  246. *
  247. * @param _to The address of the receiver account
  248. * @param _amount The quantity of the token to mint
  249. */
  250. function onMintSuccess(
  251. address _to,
  252. uint256 _amount
  253. )
  254. public
  255. onlyRole(ROLE_TOKEN)
  256. onlyOwnedWallet(_to)
  257. {
  258. bytes32 toUUID = walletOwners[_to];
  259.  
  260. // Update user balance
  261. addBalance(toUUID, msg.sender, _amount);
  262.  
  263. /**
  264. * Update shareholder count.
  265. *
  266. * Method is called after minting is successful,
  267. * so we subtract _amount from
  268. * balance to find out if `_to` address is a new shareholder.
  269. */
  270. uint256 newShareholderCount;
  271.  
  272. if (_amount == balances[toUUID][msg.sender]) {
  273. newShareholderCount = reitSettings[msg.sender].shareholderCount.add(1);
  274. } else {
  275. newShareholderCount = reitSettings[msg.sender].shareholderCount;
  276. }
  277. _setShareholderCount(msg.sender, newShareholderCount);
  278.  
  279. // Update foreign owned shares by adding if `_to` address is foreign
  280. uint256 currForeignOwnedShares = reitSettings[msg.sender].foreignOwnedShares;
  281.  
  282. if (isForeign[msg.sender][toUUID]) {
  283. _setForeignOwnedShares(msg.sender, currForeignOwnedShares.add(_amount));
  284. } else {
  285. _setForeignOwnedShares(msg.sender, currForeignOwnedShares);
  286. }
  287. // Call super for general mint callbacks
  288. super.onMintSuccess(_to, _amount);
  289. }
  290.  
  291. /**
  292. * @notice Updates `shareholderCount` and `foreignOwnedShares`
  293. * after `transfer()` or `transferFrom` is successfully
  294. * called by a `RegulatedToken`
  295. *
  296. * @param _spender The address of the spender of the token
  297. * @param _from The address of the sender account
  298. * @param _to The address of the receiver account
  299. * @param _amount The quantity of the token to trade
  300. */
  301. function onTransferSuccess(
  302. address _spender,
  303. address _from,
  304. address _to,
  305. uint256 _amount
  306. )
  307. public
  308. onlyRole(ROLE_TOKEN)
  309. onlyOwnedWallet(_from)
  310. onlyOwnedWallet(_to)
  311. {
  312. // Update user balances
  313. subBalance(walletOwners[_from], msg.sender, _amount);
  314. addBalance(walletOwners[_to], msg.sender, _amount);
  315.  
  316. /**
  317. * Update shareholder count by using amount and current balance
  318. * to figure out who's a new shareholder and who is no longer one.
  319. */
  320. bool subShareholder = balances[walletOwners[_from]][msg.sender] == 0;
  321. bool addShareholder = balances[walletOwners[_to]][msg.sender] == _amount;
  322. uint256 currCount = reitSettings[msg.sender].shareholderCount;
  323.  
  324. if (subShareholder && !addShareholder) {
  325. _setShareholderCount(msg.sender, currCount.sub(1));
  326.  
  327. } else if (addShareholder && !subShareholder) {
  328. _setShareholderCount(msg.sender, currCount.add(1));
  329.  
  330. } else {
  331. _setShareholderCount(msg.sender, currCount);
  332. }
  333.  
  334. /**
  335. * Update foreign owned shares based on `isForeign` property of
  336. * `from` & `to`.
  337. *
  338. * Can reuse `foreignOwnedSharesFromTransfer` because it doesn't
  339. * depend on updated balances.
  340. */
  341. _setForeignOwnedShares(
  342. msg.sender,
  343. foreignOwnedSharesFromTransfer(msg.sender, _from, _to, _amount)
  344. );
  345.  
  346. // Call super for general transfer callbacks
  347. super.onTransferSuccess(_spender, _from, _to, _amount);
  348. }
  349.  
  350. /**
  351. * @notice Sets current shareholder count for a token
  352. *
  353. * @dev This method is used for internal functions
  354. *
  355. * @param _token The address of the token to update
  356. * @param _count The number of shareholders to set current count to
  357. */
  358. function _setShareholderCount(address _token, uint256 _count) private {
  359. reitSettings[_token].shareholderCount = _count;
  360. emit LogShareholderCountSet(_token, _count);
  361. }
  362.  
  363. /**
  364. * @notice Sets current number of foreign-owned shares for a token
  365. *
  366. * @dev This method is used for internal functions
  367. *
  368. * @param _token The address of the token to update
  369. * @param _count The number of foreign-owned shares for token
  370. */
  371. function _setForeignOwnedShares(address _token, uint256 _count) private {
  372. ERC20Basic rToken = ERC20Basic(_token);
  373. require(
  374. _count <= rToken.totalSupply(),
  375. "Foreign owned shares cannot be more than total supply"
  376. );
  377. reitSettings[_token].foreignOwnedShares = _count;
  378. emit LogForeignOwnedSharesSet(_token, _count);
  379. }
  380.  
  381. /**
  382. * @notice Checks to see if a trade would result in `shareholderCount`
  383. * dropping below `shareholderMin`
  384. *
  385. * @param _token The address of the token to be transferred
  386. * @param _from The address of the sender account
  387. * @param _to The address of the receiver account
  388. * @param _amount The quantity of the token to trade
  389. *
  390. * @return `true` if the trade would result in `shareholderCount`
  391. * going below `shareholderMin`
  392. */
  393. function violatesShareholderMin(
  394. address _token,
  395. address _from,
  396. address _to,
  397. uint256 _amount
  398. ) private view returns (bool) {
  399.  
  400. uint256 tCount = shareholderCountFromTransfer(_token, _from, _to, _amount);
  401. return (tCount < reitSettings[_token].shareholderMin);
  402. }
  403.  
  404. /**
  405. * @notice Checks to see if a trade would result in `shareholderCount`
  406. * going above `shareholderMax`
  407. *
  408. * @param _token The address of the token to be transferred
  409. * @param _from The address of the sender account
  410. * @param _to The address of the receiver account
  411. * @param _amount The quantity of the token to trade
  412. *
  413. * @return `true` if the trade would result in `shareholderCount`
  414. * going above `shareholderMax`
  415. */
  416. function violatesShareholderMax(
  417. address _token,
  418. address _from,
  419. address _to,
  420. uint256 _amount
  421. ) private view returns (bool) {
  422.  
  423. uint256 tCount = shareholderCountFromTransfer(_token, _from, _to, _amount);
  424. return (tCount > reitSettings[_token].shareholderMax);
  425. }
  426.  
  427. /**
  428. * @notice Checks to see if a trade would result in a shareholder
  429. * going over `ownershipCap`.
  430. *
  431. * @param _token The address of the token to be transferred
  432. * @param _to The address of the receiver account
  433. * @param _amount The quantity of the token to trade
  434. *
  435. * @return `true` if the trade would result in a shareholder
  436. * owning more than `ownershipCap`.
  437. */
  438. function violatesOwnershipCap(
  439. address _token,
  440. address _to,
  441. uint256 _amount
  442. ) private view returns (bool) {
  443.  
  444. ERC20Basic rToken = ERC20Basic(_token);
  445. uint256 toBalance = balances[walletOwners[_to]][_token];
  446. uint256 _cap = reitSettings[_token].ownershipCap;
  447.  
  448. // New balance should be less than capped amount
  449. uint256 newBalance = toBalance.add(_amount);
  450. uint256 maxShares = rToken.totalSupply().mul(_cap).div(100);
  451. return (newBalance > maxShares);
  452. }
  453.  
  454. /**
  455. * @notice Checks to see if a trade would result in `foreignOwnedShares`
  456. * going above `foreignOwnedSharesCap`
  457. *
  458. * @param _token The address of the token to be transfered
  459. * @param _from The address of the sender account
  460. * @param _to The address of the receiver account
  461. * @param _amount The quantity of the token to trade
  462. *
  463. * @return `true` if the trade would result in `foreignOwnedShares`
  464. * going above `foreignOwnedSharesCap`
  465. */
  466. function violatesForeignOwnedSharesCap(
  467. address _token,
  468. address _from,
  469. address _to,
  470. uint256 _amount
  471. ) private view returns (bool) {
  472.  
  473. uint256 tShares = foreignOwnedSharesFromTransfer(
  474. _token, _from, _to, _amount
  475. );
  476. uint256 totalSupply = ERC20Basic(_token).totalSupply();
  477.  
  478. uint256 maxForeignShares = totalSupply.mul(
  479. reitSettings[_token].foreignOwnedSharesCap
  480. ).div(100);
  481.  
  482. return (tShares > maxForeignShares);
  483. }
  484.  
  485. /**
  486. * @notice Computes resulting number of foreign-owned shares
  487. * if a transfer is successful
  488. *
  489. * @param _token The address of the token to be transfered
  490. * @param _from The address of the sender account
  491. * @param _to The address of the receiver account
  492. * @param _amount The quantity of the token to trade
  493. *
  494. * @return Number of foreign-owned shares if transfer succeeds
  495. */
  496. function foreignOwnedSharesFromTransfer(
  497. address _token,
  498. address _from,
  499. address _to,
  500. uint256 _amount
  501. )
  502. private
  503. view
  504. onlyOwnedWallet(_from)
  505. onlyOwnedWallet(_to)
  506. returns (uint256)
  507. {
  508. bool fromIsForeign = isForeign[_token][walletOwners[_from]];
  509. bool toIsForeign = isForeign[_token][walletOwners[_to]];
  510. uint256 currForeignShares = reitSettings[_token].foreignOwnedShares;
  511.  
  512. // Decrease foreign shares if `from` is foreign but `to` is not
  513. if (fromIsForeign && !toIsForeign) {
  514. return currForeignShares.sub(_amount);
  515.  
  516. // Increase foreign shares if `from` is not foreign but `to` is
  517. } else if (!fromIsForeign && toIsForeign) {
  518. return currForeignShares.add(_amount);
  519.  
  520. // Otherwise return same number of shares
  521. } else {
  522. return currForeignShares;
  523. }
  524. }
  525.  
  526. /**
  527. * @notice Computes resulting shareholder count if a transfer is successful
  528. *
  529. * @param _token The address of the token to be transferred
  530. * @param _from The address of the sender account
  531. * @param _to The address of the receiver account
  532. * @param _amount The quantity of the token to trade
  533. *
  534. * @return Number of shareholders if transfer succeeds
  535. */
  536. function shareholderCountFromTransfer(
  537. address _token,
  538. address _from,
  539. address _to,
  540. uint256 _amount
  541. )
  542. private
  543. view
  544. returns (uint256)
  545. {
  546. uint256 fromBalance = balances[walletOwners[_from]][_token];
  547. uint256 toBalance = balances[walletOwners[_to]][_token];
  548. uint256 currCount = reitSettings[_token].shareholderCount;
  549.  
  550. // Return current count if no shares are transferred
  551. if (_amount == 0) {
  552. return currCount;
  553. }
  554.  
  555. // Increment if to address is new shareholder
  556. // and from address will remain a shareholder after transfer
  557. if (fromBalance > _amount && toBalance == 0) {
  558. return currCount.add(1);
  559.  
  560. // Decrement if from address will go to 0 balance
  561. // and to address is existing shareholder
  562. } else if (fromBalance == _amount && toBalance > 0) {
  563. return currCount.sub(1);
  564.  
  565. // Otherwise keep same number of shareholders
  566. } else {
  567. return currCount;
  568. }
  569. }
  570. }
Add Comment
Please, Sign In to add comment