Guest User

Untitled

a guest
Jun 18th, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.09 KB | None | 0 0
  1. pragma solidity ^0.4.18;
  2.  
  3.  
  4. import "./Ownable.sol";
  5.  
  6.  
  7. contract RentalContract is Ownable {
  8.  
  9. struct Article{
  10. uint id;
  11. address seller;
  12. address buyer;
  13. string propaddress;
  14. uint256 rental_price;
  15. string description;
  16. bool available;
  17. string contact;
  18. }
  19. mapping(uint => Article) public articles;
  20.  
  21. uint articleCounter;
  22.  
  23. event LogSellArticle(
  24. uint indexed _id,
  25. address indexed _seller,
  26. string _propaddress,
  27. uint256 _rental_price,
  28. string _description,
  29. bool _available,
  30. string _contact
  31. );
  32. event LogBuyArticle(
  33. uint indexed _id,
  34. address indexed _seller,
  35. address indexed _buyer,
  36. string _propaddress,
  37. uint256 _rental_price,
  38. string _description,
  39. bool _available,
  40. string _contact
  41.  
  42. );
  43.  
  44. function kill() public onlyOwner {
  45.  
  46. selfdestruct(owner);
  47. }
  48.  
  49. function sellArticle(string _propaddress, uint256 _rental_price, string _description, bool _available, string _contact) public {
  50. articleCounter++;
  51.  
  52. articles[articleCounter] = Article(
  53. articleCounter,
  54. msg.sender,
  55. 0x0,
  56. _propaddress,
  57. _rental_price,
  58. _description,
  59. _available,
  60. _contact
  61. );
  62.  
  63. LogSellArticle(articleCounter, msg.sender, _propaddress, _rental_price, _description, _available, _contact);
  64. }
  65. function getNumberOfArticles() public view returns (uint){
  66. return articleCounter;
  67. }
  68.  
  69.  
  70. function getArticlesForSale() public view returns (uint[]){
  71.  
  72. uint[] memory articleIds = new uint[](articleCounter);
  73. uint numberOfArticlesForSale = 0;
  74.  
  75. for(uint i = 1; i <= articleCounter; i++){
  76.  
  77. if(articles[i].buyer == 0x0){
  78.  
  79. articleIds[numberOfArticlesForSale] = articles[i].id;
  80.  
  81. numberOfArticlesForSale++;
  82.  
  83. }
  84. }
  85.  
  86. uint[] memory forSale = new uint[](numberOfArticlesForSale);
  87. for(uint j = 0; j < numberOfArticlesForSale; j++){
  88.  
  89. forSale[j] = articleIds[j];
  90.  
  91. }
  92. return forSale;
  93.  
  94. }
  95.  
  96.  
  97. function buyArticle(uint _id) payable public {
  98.  
  99. require(articleCounter > 0);
  100. require(_id > 0 && _id <= articleCounter);
  101.  
  102. Article storage article = articles[_id];
  103.  
  104. require(article.buyer == 0x0);
  105.  
  106. require(msg.sender != article.seller);
  107.  
  108. require(msg.value == article.rental_price);
  109.  
  110. article.buyer = msg.sender;
  111.  
  112. article.seller.transfer(msg.value);
  113. LogBuyArticle(_id, article.seller, article.buyer, article.propaddress, article.rental_price, article.description, article.available, article.contact);
  114. }
  115. }
  116.  
  117. <!DOCTYPE html>
  118. <html lang="en">
  119.  
  120. <head>
  121. <meta charset="utf-8">
  122. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  123. <meta name="viewport" content="width=device-width, initial-scale=1">
  124. <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
  125. <title>Rent My Place</title>
  126. <!-- Title will appear as a tab in browser on webpage -->
  127. <!-- Bootstrap -->
  128. <link href="css/bootstrap.min.css" rel="stylesheet">
  129.  
  130. <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
  131. <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  132. <!--[if lt IE 9]>
  133. <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  134. <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  135. <![endif]-->
  136.  
  137. <!-- Application -->
  138. <link href="css/app.css" rel="stylesheet">
  139.  
  140. </head>
  141.  
  142. <body>
  143. <div class="container">
  144. <!-- container that contains title panel-->
  145. <div class="jumbotron text-center">
  146. <p style="font-size:80px;padding: 1em;padding-top: 10px;padding-bottom: 10px; border:10px;border-style:solid;border-color:#c3c3c3;">
  147. <font color = "#880015" >Rent My Place</font></p>
  148. </div>
  149.  
  150. <div class="col-md-12" id="article-list">
  151. <div class="row">
  152. <div class="col-lg-12">
  153. <p id="account" class="welcome pull-right"></p>
  154. <p id="accountBalance" class="welcome pull-left"></p>
  155. </div>
  156. </div>
  157.  
  158. <div class="row panel panel-default">
  159. <div class="panel-heading clearfix">
  160. <div class="panel-title">
  161. <p style="font-size:24px;padding: 1em;padding-top: 10px;padding-bottom: 10px; border:5px;border-style:solid;border-color:#c3c3c3;">
  162. <font color = "#880015">Renter's Tip: </font><font color = "#000000">Inspect the property before you send money.</font><br><font color = "#880015">Landlord's Tip: </font><font color = "#000000">Meet prospective tenants in person.</font></p>
  163. <!-- Button that opens second window to a form to fill out-->
  164. <button class="btn btn-info btn-lg pull-right" data-toggle="modal" data-target="#sellArticle">Post a Rental</button>
  165. </div>
  166. </div>
  167. <!-- when the event button gets click, it will show the list-->
  168. <ul id="events" class="collapse list-group"></ul>
  169. </div>
  170.  
  171. <div id="articlesRow" class="row">
  172. <!-- ARTICLES with pertinent item information LOAD HERE -->
  173. </div>
  174. </div>
  175. </div>
  176.  
  177. <!--Result that is displayed after input-->
  178. <div id="articleTemplate" style="display: none;">
  179. <div class="row-lg-12">
  180. <div class="panel panel-default panel-article">
  181. <div class="panel-heading">
  182. <h3 class="panel-title"></h3>
  183. </div>
  184. <div class="panel-body">
  185. <strong>Baths</strong>: <span class="baths"></span><br/>-->
  186. <strong>Address</strong>: <span class="propaddress"></span><br/>
  187. <strong>Rental Price</strong>: <span class="rental_price"></span><br/>
  188. <strong>Description</strong>: <span class="description"></span><br/>
  189. <strong>Property is available for showing</strong>: <span class="available"></span><br/>
  190. <strong>Contact Email</strong>: <span class="contact"></span><br/>
  191. </div>
  192. <div class="panel-footer">
  193. <button type="button" class= "btn btn-primary btn-success btn-buy" onclick="App.buyArticle(); return false;">Buy</button>
  194. </div>
  195. </div>
  196. </div>
  197. </div>
  198.  
  199. <!-- Modal form to sell an article -->
  200. <div class="modal fade" id="sellArticle" role="dialog">
  201. <div class="modal-dialog">
  202.  
  203. <!-- Modal content-->
  204. <div class="modal-content">
  205. <div class="modal-header">
  206. <button type="button" class="close" data-dismiss="modal">&times;</button>
  207. <h4 class="modal-title">Rent Your Place</h4>
  208. </div>
  209. <div class="modal-body">
  210.  
  211. <div class="row">
  212. <div class="col-lg-12">
  213. <form>
  214. <div class="form-group">
  215. <label for="propaddress">Address</label>
  216. <input type="text" class="form-control" id="propaddress" placeholder="Enter the address">
  217. </div>
  218. <div class="form-group">
  219. <label for="rental_price">Rent (in USD) </label>
  220. <input type="text" class="form-control" id="rental_price" placeholder="$" pattern="[0-9]+([.,][0-9]+)?">
  221. </div>
  222. <div class="form-group">
  223. <label for="description">Description</label>
  224. <textarea type="text" class="form-control vresize" id="description" placeholder="Describe your property" maxlength="255"></textarea>
  225. </div>
  226. <div class="form-group">
  227. <label for="available"></label>
  228. <input type="checkbox" id="available"> Property is available for showing
  229. </div>
  230. <div class="form-group">
  231. <label for="contact">Contact Email</label>
  232. <input type="text" class="form-control" id="contact" placeholder="Enter your contact email" >
  233. </div>
  234. </form>
  235. </div>
  236. </div>
  237. </div>
  238. <div class="modal-footer">
  239. <button type="button" class="btn btn-primary btn-success" data-dismiss="modal" onclick="App.sellArticle(); return false;">Submit</button>
  240. <button type="button" class="btn" data-dismiss="modal">Close</button>
  241. </div>
  242. </div>
  243.  
  244. </div>
  245. </div>
  246.  
  247. <div id="footer" class="container">
  248. <nav class="navbar navbar-default navbar-fixed-bottom">
  249. <div class="navbar-inner navbar-content-center text-center">
  250. <p class="text-muted" credit><a href="http://www.axbean.com">AXbean</a> - &copy; 2018</a></p>
  251. </div>
  252. </nav>
  253. </div>
  254.  
  255.  
  256. <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
  257. <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  258. <!-- Include all compiled plugins (below), or include individual files as needed -->
  259. <script src="js/RentalApp.js"></script>
  260. <script src="js/bootstrap.min.js"></script>
  261. <script src="js/web3.min.js"></script>
  262. <script src="js/truffle-contract.js"></script>
  263.  
  264. </body>
  265.  
  266. </html>
  267.  
  268. App = {
  269. web3Provider: null,
  270. contracts: {},
  271. account: 0x0,
  272. loading: false,
  273.  
  274. init: function() {
  275. return App.initWeb3();
  276. },
  277.  
  278. initWeb3: function() {
  279. // initialize web3
  280. if(typeof web3 !== 'undefined') {
  281. //reuse the provider of the Web3 object injected by Metamask
  282. App.web3Provider = web3.currentProvider;
  283. } else {
  284. //create a new provider and plug it directly into our local node
  285. App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
  286. }
  287. web3 = new Web3(App.web3Provider);
  288.  
  289. App.displayAccountInfo();
  290.  
  291. return App.initContract();
  292. },
  293.  
  294. displayAccountInfo: function() {
  295. web3.eth.getCoinbase(function(err, account) {
  296. if(err === null) {
  297. App.account = account;
  298. $('#account').text(account);
  299. web3.eth.getBalance(account, function(err, balance) {
  300. if(err === null) {
  301. $('#accountBalance').text(web3.fromWei(balance, "ether") + " ETH");
  302. }
  303. })
  304. }
  305. });
  306. },
  307.  
  308. initContract: function() {
  309. $.getJSON('RentalContract.json', function(chainListArtifact) {
  310. // get the contract artifact file and use it to instantiate a truffle contract abstraction
  311. App.contracts.RentalContract = TruffleContract(chainListArtifact);
  312. // set the provider for our contracts
  313. App.contracts.RentalContract.setProvider(App.web3Provider);
  314. // listen to events
  315. App.listenToEvents();
  316. // retrieve the article from the contract
  317. return App.reloadArticles();
  318. });
  319. },
  320.  
  321. reloadArticles: function() {
  322. //avoid reentry bugs
  323. if(App.loading){
  324. return;
  325. }
  326. App.loading = true;
  327.  
  328. // refresh account information because the balance might have changed
  329. App.displayAccountInfo();
  330.  
  331. var chainListInstance;
  332.  
  333. App.contracts.RentalContract.deployed().then(function(instance) {
  334. chainListInstance = instance;
  335. return chainListInstance.getArticlesForSale();
  336. }).then(function(articlesIds) {
  337.  
  338. // retrieve the article placeholder and clear it
  339. $('#articlesRow').empty();
  340.  
  341. for(var i = 0; i < articlesIds.length; i++){
  342. var articleId = articlesIds[i];
  343. chainListInstance.articles(articleId.toNumber()).then(function(article){
  344. App.displayArticle(article[0], article[1], article[3], article[4], article[5], article[6], article[7]);
  345. });
  346. }
  347. App.loading = false;
  348.  
  349. }).catch(function(err) {
  350. console.error(err.message);
  351. App.loading = false;
  352. });
  353. },
  354.  
  355. displayArticle: function(id, seller, propaddress, rental_price, description, available, contact) {
  356. var articlesRow = $('#articlesRow');
  357.  
  358.  
  359. var articleTemplate = $("#articleTemplate");
  360. articleTemplate.find('.propaddress').text(propaddress);
  361. articleTemplate.find('.rental_price').text('$' + rental_price);
  362. articleTemplate.find('.description').text(description);
  363. articleTemplate.find('.available').text(available);
  364. articleTemplate.find('.contact').text(contact);
  365. articleTemplate.find('.btn-buy').attr('data-id', id);
  366.  
  367. //seller
  368. if(seller == App.account){
  369. articleTemplate.find('.article-seller').text("You");
  370. articleTemplate.find('.btn-buy').hide();
  371. }else{
  372. articleTemplate.find('.article-seller').text(seller);
  373. articleTemplate.find('.btn-buy').show();
  374. }
  375. //add this new article
  376. articlesRow.append(articleTemplate.html());
  377. },
  378.  
  379.  
  380.  
  381. sellArticle: function() {
  382. // retrieve the detail of the article
  383. var _description = $('#description').val();
  384. var _propaddress = $('#propaddress').val();
  385. var _rental_price = $('#rental_price').val();
  386. var _available = $('#available').val();
  387. var _contact = $('#contact').val();
  388.  
  389.  
  390. App.contracts.RentalContract.deployed().then(function(instance) {
  391. //return instance.sellArticle(_description, _beds, _baths, _propaddress, _rental_price, _property_type, _available, _contact_email, {
  392. return instance.sellArticle(_propaddress, _rental_price, _description, _available, _contact,{
  393. from: App.account,
  394. gas: 500000
  395. });
  396. }).then(function(result) {
  397.  
  398. }).catch(function(err) {
  399. console.error(err);
  400. });
  401. },
  402.  
  403. // listen to events triggered by the contract
  404. listenToEvents: function() {
  405. App.contracts.RentalContract.deployed().then(function(instance) {
  406. instance.LogSellArticle({}, {}).watch(function(error, event) {
  407. if (!error) {
  408. $("#events").append('<li class="list-group-item">' + event.args._propaddress + ' is now for sale</li>');
  409. } else {
  410. console.error(error);
  411. }
  412. App.reloadArticles();
  413. });
  414.  
  415. instance.LogBuyArticle({}, {}).watch(function(error, event) {
  416. if (!error) {
  417. $("#events").append('<li class="list-group-item">' + event.args._buyer + ' bought ' + event.args._propaddress + '</li>');
  418. } else {
  419. console.error(error);
  420. }
  421. App.reloadArticles();
  422. });
  423. });
  424. },
  425.  
  426. buyArticle: function() {
  427. event.preventDefault();
  428.  
  429. // retrieve the article price and data
  430. var _articleId = $(event.target).data('id');
  431. var _price = parseFloat($(event.target).data('value'));
  432.  
  433. App.contracts.RentalContract.deployed().then(function(instance){
  434. return instance.buyArticle(_articleId, {
  435. from: App.account,
  436. value: web3.toWei(_price, "ether"),
  437. gas: 500000
  438. });
  439. }).catch(function(error) {
  440. console.error(error);
  441. });
  442. }
  443. };
  444.  
  445. $(function() {
  446. $(window).load(function() {
  447. App.init();
  448. });
  449. });
Add Comment
Please, Sign In to add comment