The ether_real_estate Package
This software simulates a game in which players purchase properities that rent out real estate to businesses. When leases expire, players submit bids to the firm for a new lease, and the winning player adds the firm to one of their properties for the duration of the lease.
All transactions take place on a private Ethereum blockchain, which allows students to explore blockchain technology as a ledger for recording transactions.
Loading the Game
The key blockchain component of the game utilizes the eth-tester module.
The module makes use of the pyEVM backend, which is currently listed in an experimental (alpha) stage.
The eth-tester
module is Linux-only for now.
There are ways to run the game on Windows by interfacing with something like Ganache in the Truffle Suite for Ethereum development, and a later version of ether_real_estate
will enable this functionality.
Install the following packages from PyPI. Because ether_real_estate
and some of its core dependencies (eth-hash
, eth-tester
, py-evm
) are in early development, the ether_real_estate
module is picky about version numbering for dependencies. Create a virtual environment if you want to use other versions of the dependency packages for other projects that will not make use of ether_real_estate
.
!pip install ether_real_estate
!pip install eth-hash[pycryptodome]
Requirement already satisfied: ether_real_estate in /mnt/software/anaconda3/lib/python3.8/site-packages (1.1)
Requirement already satisfied: eth-hash==0.3.1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from ether_real_estate) (0.3.1)
Requirement already satisfied: pandas in /mnt/software/anaconda3/lib/python3.8/site-packages (from ether_real_estate) (1.2.2)
Requirement already satisfied: numpy in /mnt/software/anaconda3/lib/python3.8/site-packages (from ether_real_estate) (1.19.2)
Requirement already satisfied: py-evm==0.4.0a4 in /mnt/software/anaconda3/lib/python3.8/site-packages (from ether_real_estate) (0.4.0a4)
Requirement already satisfied: eth-tester==0.5.0b4 in /mnt/software/anaconda3/lib/python3.8/site-packages (from ether_real_estate) (0.5.0b4)
Requirement already satisfied: eth-utils in /mnt/software/anaconda3/lib/python3.8/site-packages (from ether_real_estate) (1.10.0)
Requirement already satisfied: eth-keys<0.4.0,>=0.2.1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-tester==0.5.0b4->ether_real_estate) (0.3.3)
Requirement already satisfied: rlp<3,>=1.1.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-tester==0.5.0b4->ether_real_estate) (2.0.1)
Requirement already satisfied: semantic-version<3.0.0,>=2.6.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-tester==0.5.0b4->ether_real_estate) (2.8.5)
Requirement already satisfied: eth-abi<3.0.0,>=2.0.0b4 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-tester==0.5.0b4->ether_real_estate) (2.1.1)
Requirement already satisfied: cached-property<2,>=1.5.1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (1.5.2)
Requirement already satisfied: lru-dict>=1.1.6 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (1.1.7)
Requirement already satisfied: mypy-extensions<1.0.0,>=0.4.1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (0.4.3)
Requirement already satisfied: pyethash<1.0.0,>=0.1.27 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (0.1.27)
Requirement already satisfied: eth-bloom<2.0.0,>=1.0.3 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (1.0.4)
Requirement already satisfied: trie==2.0.0-alpha.5 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (2.0.0a5)
Requirement already satisfied: py-ecc<5.0.0,>=1.4.7 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (4.1.0)
Requirement already satisfied: blake2b-py<0.2,>=0.1.4 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (0.1.4)
Requirement already satisfied: eth-typing<3.0.0,>=2.2.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from py-evm==0.4.0a4->ether_real_estate) (2.2.2)
Requirement already satisfied: typing-extensions<4,>=3.7.4 in /mnt/software/anaconda3/lib/python3.8/site-packages (from trie==2.0.0-alpha.5->py-evm==0.4.0a4->ether_real_estate) (3.7.4.3)
Requirement already satisfied: sortedcontainers<3,>=2.1.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from trie==2.0.0-alpha.5->py-evm==0.4.0a4->ether_real_estate) (2.3.0)
Requirement already satisfied: hexbytes<0.3.0,>=0.2.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from trie==2.0.0-alpha.5->py-evm==0.4.0a4->ether_real_estate) (0.2.1)
Requirement already satisfied: parsimonious<0.9.0,>=0.8.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-abi<3.0.0,>=2.0.0b4->eth-tester==0.5.0b4->ether_real_estate) (0.8.1)
Requirement already satisfied: pycryptodome<4,>=3.6.6 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-hash==0.3.1->ether_real_estate) (3.10.1)
Requirement already satisfied: cytoolz<1.0.0,>=0.10.1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-utils->ether_real_estate) (0.11.0)
Requirement already satisfied: toolz>=0.8.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from cytoolz<1.0.0,>=0.10.1->eth-utils->ether_real_estate) (0.11.1)
Requirement already satisfied: six>=1.9.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from parsimonious<0.9.0,>=0.8.0->eth-abi<3.0.0,>=2.0.0b4->eth-tester==0.5.0b4->ether_real_estate) (1.15.0)
Requirement already satisfied: python-dateutil>=2.7.3 in /mnt/software/anaconda3/lib/python3.8/site-packages (from pandas->ether_real_estate) (2.8.1)
Requirement already satisfied: pytz>=2017.3 in /mnt/software/anaconda3/lib/python3.8/site-packages (from pandas->ether_real_estate) (2021.1)
Requirement already satisfied: eth-hash[pycryptodome] in /mnt/software/anaconda3/lib/python3.8/site-packages (0.3.1)
Requirement already satisfied: eth-utils<2,>=1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-hash[pycryptodome]) (1.10.0)
Requirement already satisfied: pycryptodome<4,>=3.6.6 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-hash[pycryptodome]) (3.10.1)
Requirement already satisfied: eth-typing<3.0.0,>=2.2.1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-utils<2,>=1->eth-hash[pycryptodome]) (2.2.2)
Requirement already satisfied: cytoolz<1.0.0,>=0.10.1 in /mnt/software/anaconda3/lib/python3.8/site-packages (from eth-utils<2,>=1->eth-hash[pycryptodome]) (0.11.0)
Requirement already satisfied: toolz>=0.8.0 in /mnt/software/anaconda3/lib/python3.8/site-packages (from cytoolz<1.0.0,>=0.10.1->eth-utils<2,>=1->eth-hash[pycryptodome]) (0.11.1)
Then load the module.
import ether_real_estate
A couple notes about how the game runs:
- Transactions are handled by the game directly. In a later version, transactions will be auto-enforced via smart contracts in Vyper so that students can learn about that aspect of blockchain development.
- Gas prices are currently set to zero to keep things simple. Variable gas prices will be added later to simulate transaction costs.
The game will save/read data from a user-specified directory.
Instantiating the Game
A new Game
object, g
, is created below. Options for the Game
object are:
num_industry
(default =5
)- Number of industries in the game. Firm cash flows are partially correlated within an industry.
num_players
(default =5
)- Number of human players in the game. This should be set to either the number of students in the class or the number of groups in the class (if working in teams).
num_ai' (default =
0`)- Number of AI players in the game.
- AI players can comprise the full user list if testing the game.
- Alternatively, AIs can be added to student games for small classes.
verbose
(default =False
)- If
True
, print out extra information at each step of the game. Useful for testing.
- If
game_path
(default =''
)- Path to store game data
- If left blank, the user will be asked to provide one (or a default will be suggested).
Some notes about the economy:
- There will be 3 times as many buildings are there are players.
- There will be 20% more firms than can fit in all of the buildings.
The command below creates an all-AI game for testing purposes. I specify 5
industries, 0
players, 5
AI players, and a game folder test_game
set under my home directory.
g = ether_real_estate.Game(num_industry=5, num_players=0, num_ai=5, verbose=True, game_path='/home/james/test_game')
Starting deposit transactions: ('0x25f5c23f5e31bb112d18d980c74912529bde17b83f7068581f6e354ecd08d46d', '0x6c4cfe34d1125d704be2ab60f0e70b152fcaf6a16f8854e8dbc654f48040106a', '0xcdb9b6c4378ce4b2aaf87200c538c68fa37b1a9d5dccd2941b63f3326bc63b72', '0xac8360365d3cb3eabdb7f837ed0f327fecf77d05b224c95ad6c28891cd67e075', '0x92a63e09d3d234a61c8eb27fb3ed58648a1ef146847e36741df451377fea6467', '0x0cd15ba5656ba3f5f33d0538393fc6109eef9bd1d5ce4e701165690d74f4740c', '0xb43b1840dba519f88c863df4a10d4aeab7d380224c0ac09a32eee9a6b009f256', '0xf65187fa5235546912423a7a00455098dd8a01bb9a077ef2e582760a13008d33', '0x262c75e2363d97b550005abb97a3c557bc5c475a388ec8e82ab28789d4ef4700', '0xe2d1d2f4c7903f26c81921ed036b6a46cd5ea081a5d5925e9dc3c424630f5fb4', '0xde9c89250fd7b0bc5924c1f351e750c3d65d3175e881f11c9f1475558086b66b', '0xaabb2eaf031d0031567104a9abd6e8550844b648a95aa926c1c5407e45b48c02', '0x2f33b9d18929154ecfaf7a69e5a803a5c7aa69717d3a932eba62d33165aaf652', '0xc29d2a21b00f98b6b604d93da11c4e0c8bb69265617b0940c1ef6a75c7b239c3', '0xd7ed552ed40e9a997a9632cb7b49aaf75a999e124c4b12edbc3e0051e5d91dd8', '0x4c205bff5765ddbc59795d310fd81cc2d9f75d0579b9c707d2e9eb6ffea4ca48', '0x78f50c87be4d6db9930a440c014e104ef677479403fc54823d3f81ee8d99b1f5', '0x6980ada7ed17b8bab16bbcd86455eee9c6389e692203d18ce6a84449c903d6b0', '0x09cf46bd135a442285c9b985cd9ee1346c0df72f4f4877daf725bb6faabfeb87', '0xe000f137e882230d799b5ce60adf2282dcf01eefcd789098359003f970abc5f6', '0x4a6358fbd8908a7f673cc72e137bb87783514ed220316bdcf25a9290ddd6dc59', '0x9855b92c06a61421a21a489e0789b57f49d682e70209ba7335d81814bcf76c32', '0x7c7e0a959f868805ed84c34bdbed681238802a94515549d9ed5d127671ada634', '0x988a3fdb86e243caaeb9688f9c2388efc97729631e0ff716c5eb48f7b861bc07', '0xd06bd53c8d07683bf29eeaa6b2badf358caaa3a7932c189eb9efc27232145fcc', '0x6b88028d7effba8b28d298586ed1574cbe0ef872f3e0f76c438be4cf260f4079', '0x8cb118131fa2652159a14adc23efed02b3432ce71a761db2be3082f70f324e93', '0xdb7726c42d05d6e2f9db493360abee1b8ba65820965ced8a919ba5e81b805217', '0x910957c1d4c70540e510d609e4ee7bfc525d2a88c2b185765a986a91eaf27d41', '0xaa5fe63420d5f072ba429cd34edfa0087c37a319978bfeed02f7a3d9cee0379b', '0xda8bedb870fb45bab97e0b9c90df2048bc8f7b8bf44a4d6700eb299f4ec98430', '0xe530f1cb0710b2c916a6c55be782071fd87be675f13c5e71a3d278dcc785a03d', '0x205f328fd56d2bc0fd488b4280ce757d92727e88745a68c875df7921f9e4cca1', '0x292e0a339c86ae9d0946aba8e64fa3af68caabbfeaf0dbc40303e5a85fc69990', '0x444fae63fda58789bf699db146be9fb3f2a22c9758a5618d6787e478a0abeb17', '0x55faaa90403ecb0acc7777d468566e9b805d0557c9ab7d92b0f561a395e86cee', '0xe3f5e24a18a86d24b0d5aad2cb27a6957116cb75aa365994f5b37c0983c80d0c', '0x35d380a5b1eb38fb8795c158539817b0f7b3b68bfc35f8385a500cd2986186e6', '0x9836a600327e0313ec5db443ea839f9d53c3273522f7b38be7e55220a12c0b0a', '0x0c90de936140a26a68eccb04befdd36755aa674ae0c7d25efc1749007678ae00', '0x9531712dcc4d4ac7edeb57c97f4d4e3dece942c88db9c108f02de3e0e686c58f', '0xb27d52e98f8309cb47899de91e3115ce6c8406f74f91841f3939245529a39bbb', '0xcaa74ab533d47096aa292b52e8a613e79a2f970a23b8ed4c85b071c3a985da63', '0xeb19c460d46439bb23b616bdc3f358399ad208cd0f6d6defafe43367041388af', '0xf0cfc1e505b2e07f85274656fdc4b30a5d99dbd51f2b37d3e28e11dfde3ce9ca', '0xf454172d7866b25897c0c96f068504fea34ddb101bbd133cab746968a04dbe1d', '0x41abc2b8146e2a0d3c2544ebf352d4f08d0289b77953e98e5754a2917f6e43b3', '0x1d8d63b312db1a9541c91db13fc4d83b87a8fda140a6acae6739a88586341dce', '0x0d8743f563e5a1f222c058098ae817855bfb498fdef305f71bdc2df85ccc3281', '0x9f5271a52017d79477821943ef29174de913709c04cf101bd68ee908705cebd3', '0x9cbd6352404a4753493180ab66c4a668d9080cc033113a38125930971a75d2c3', '0x2aba42d2e8df3b115b8e3ac217d4dded2a7ac6c5c3c081c3b0e2e17b111c1631', '0xc9a443c1388d4afea7aa92885c04df5a426b86fb84d3e305ad965cebbf130920', '0x4c9d8fb61925315e04a0e65659005b8c35ff54bc158f81265db018d1f79a0cf5', '0xf3c89e42f0ad7120c5b041e355a88a4afc34f29db2be92221597cd5103e502d9', '0xa14d2a3011fa90ccd0bed7a7fb81281919289eb6dd73c7d0088f3f96fbeb5692', '0x5043f9e26c62437cae4df087148345eef31733a33b89acc170c60f3465c3b99f', '0x4679bca5104188e608d171b9d0e7e996a6b9ea9448e29107e6f1eba7c72f0e68', '0xbea11c9895ff40e239ba74ff3a4ea5a10cdf1b46567dfe3296fda3ecfa9ab063', '0xb872d90e072fee02964ddf47eeff5464243f35cd5ba2c529f336fedc76051a7f', '0x90ef839570d2ab5fafbc1eaba1968d655ef855543cbdf32b62bb74d9cb419888', '0x0a4fb25f18cb0e8625640b74d3171514bec5f716f85f09867fde359a1d34e56f', '0x69da9e3ba42466ca12978ff415d2ee098c013f8897e9fb37bce6ee081abb0b74', '0xd78eafd39a462ef825f84c8682b5e91f53d0bc0bcb2c7b48c4722e8c2e8df3a6', '0x7ef079fa12efa135a4b89ccd3cff5f2a474246f00c4406c86f06391ca2968dda', '0x2571f5b772384acb98ba6ead13857f65cb5cde3b50f1e9d5add8774bb931a454', '0xd941be6c9a6d5ed212a7f6341d50871e80255ef470c0e69fb6df26f4ffa52e66', '0xe40d7d0df9992f9bc4d2216a9862d6063b31a868094b31b426f17969f0e20fd6', '0xde83b42b6f0ebd1f4e3a6c19117d470f4a17adaaa322245aa83d105c234827ec', '0x80f994c2d6dff5449183a81c5c131a9c83095f674c6fb1df0ced37411179254e', '0x77d09afe4409f3409ddf5cb73d9a517296a12fe9082e6098687873ebebc10a44', '0x228a141821b7ec9e9b5d886ad20c956a73013176a96ffe796a645590999d74b5', '0x19b561c87237d1c16a2dba6fab60cd314ba8e63842c2272b01ebd70af83259f8', '0xf9c4521d1d365d57bb9453c405872cedfeb8870730663deb8168c75203efb56a', '0xdc10913d4abc7c5cf656939bce9730ebf5e91dfaa7acf25b644bb7a9e105b146', '0xab0f0b28ff505043b726f71c74f4cfd330c51f060002cbc9ecaa2b640e160789', '0x2bed42efdb7135474c62013968e10a9cad47756e2d087c01bb5050d5d4591e16', '0x47e43957dad2a1487bafcd72249f5ebcc018e1361a685066d3f9b70aa8c57f8d', '0x89c2a3867153a14aa4ec997879f7016674dfce8484f62a6785932e4990e95561', '0x8797af59c867a65196ba7c3185554978decc61258ec224d26d8fb5f539c243fa', '0xa66b6c9ad8f219281d34ed508ae25c81450a6ebe1817d10c364c97e292a92946', '0xf04e5bbeba1059558ba62a2f1cb3565ba15c1ff632d7a5a0dd4aed744959de6e', '0x5ac7cdd4efa7645ed3ad8094c1db13d05936a35e7b165e4fed197ec53ccf14ca', '0x2044347cd81fec65053df55e0d7fbc4f51f2b63cd06e8099213cd762e043c137', '0xa19dfebced9734a226e6893c2bdeec1d55b5dc7b62876c1c40ec60007c229ed0', '0xa28490e55bc648736ef5239f79205e43db40eb18d76e2ebdfbbb464f62863db9', '0x7f1dfff6592ecacda08875440f5bc15373e0c222408786a4b43f20e4dce098fc', '0x8e4ac45099c21ccfdb1d8eb45cbe75d9eac80a9e06783731612c275ba5ed0a6e', '0x53df65a215fdeaf8c5022ba611519150ebb7ebf4f5c7f855c5901e8158197131', '0x75a6caad3ff69b45d9be676fac939a8b94323bb4fc29ef4f9a2e2739030890f5', '0xe6557add2637f2c25493628e903d909d4bfffe24122451a50a9c41724b64e8c0', '0x57cd60c19232ccc65fd6b60a9afcd6e45d637e5eea3acc4084ed0d1300c5a379', '0x0880ac885ab5b1fa83eec16cd0cdbc62fe885077cfacc70a9bbc17dced32ae37', '0xe35f2de046fe4873ba6a42a67f133534d4ae4de81665f284a67a91c0f5067713', '0x9542e1458aeaf71a2c89992c24872932cd1d99b66e0764aa5d798a36793c1ed2', '0x2ad518e3554a398ee531c63efd00b1e661ce0bc3dfa16e0840c620e0a589bbe3', '0xc33d0d70b8d8780a607412a334fd9585be52779a49ff568668859b195d943510', '0xe9c84dd5939e31e57241570eee459a423935a45734dc7ad44191d332aa75622e', '0x7a7ffe5d179f82c32e08d44502b3036f4543eb1b4d2bb8d30f9c7d54fda51cc9', '0x2dbf90535b8429a33121ac3d6174a152a9a820e6a989a5033ccf49693fbcc1fb', '0x7388194cf94350906b0bfd6090fe671ddd4e60790517ef0fb98eadd094f3a11f', '0x667da3f3a7ce26ae8ca145465abd6f4d9b36db3b14e4ce333e3c0074cfb441bf', '0xa45af75c9bd67893308492ea92f9b350dc6403dad4e61b13b22a8d9b9def5b6a', '0x99ce672031007d10da8e8ae69ae11be05b968b395bd6d8d16a0bbb954b640ded', '0x7f08d13153385af9c3ddf3fbb77a59fe1f7fc8a3016ff1a983e6ccca20cc10fa', '0x4dca0edc35d4fe9fe61641dd4b925b22598cacd49b543aa4f31e22ae06275dba', '0x876c34d7675a785a75a2f6682f0de08561ef4aa979e3ceaa4a9df4dac30800cd', '0x40877206a4ef2e75f6de65a4e118cbd1b62bd54c45ed4dd25e1c256afc54e24e', '0x81acd8078afe6f8117582f94bae09842566dec01aae6b83cfd551f36fd3bffdb', '0x1f7ec6454ff4a75e133d129677e7f038d3f9baba110c98b640cdcc3dd3a6199e', '0x84ea64383d1a965b182515e8f95b48f6a219d770ec4c72d869dfee83706f9465', '0x1076ff3fc148ed90c18a449b054224161b28b6fc3a4e134edcef34a53cc36f90', '0x8feb2ce5f2f08eab040cbe4cce1a7350cded0202154d19bf15206f1d6c92a476', '0x347a24b482dbce3399822f1e1bebe6d7a66e4946779e896f7ad41cb49c06e357', '0xfaec76d10c68fbb68c0090b8fa41e8895cbb59747ed8e7af479012134e018e6f', '0x8f7e0bfa632e4b27725b3fa5d61c992562f4c357aaeac35601e7442f7382849b', '0x1e1596fef5c376e41257a3c90d032c0b0c7265951a5666d7d63639badb0060b3', '0xaa06a10cda3835b2fb9f4818750248fc352057f902011861f16d5e7c13ad3272', '0x7fce8a37d84761142d80e97ab3228877ad2e51ac247087110d81e4599e2a0c2c', '0x7badc88125a135f3a9163e89d9f52c7549a4cdb3405e9d82eeaffb2a422e0643', '0x51247092d80ba6d7180de1afeb73f9b3aa46efedd9b9b4bd5ae6eae3a6a09c1d', '0x9b97a7e0878bf49fda26cf0e660a7fa96901de43e63b3a52248d9780b7337b8b', '0xcb177c2b9767fc0bbd7abe39e9f3c14fd309b3af0eafb82f3b3c9444e0faf56b', '0x8b378be9dda68678cac993e6b7e749b8f2bda6377614102e91a35041a59eb53a', '0xa3c0f215d80a30a699d5e1781ae7948c8c3116ff28f007da7b7baa1055c43af6', '0xadef82a83a8bacb120385374a814b52fbd3e82a765c1c34cf8068e1262602b19', '0x55fc5d68d34f793bac327359aa1ee56a56f9b3a63db95f4d4a4d8dd356d95d0b', '0xd8cfcfe322eac6c58753b496d204e0cdf09d7b16ef1661f8ea3d90c5d5deeb4d', '0xb3f10af3eb8b04ce158f3c345ed886dee38fb05330f95c958f7ab754f70d2eef', '0xc48ac3de961467e6b33a69c210eab933d77d391872f13c29be4a12849aede99b', '0xde7b5e7338f4c3ce2167f12ba8bf0717ea78965c93f6ccbee921a588f70bfd5c', '0x757e1b4633a36ff43ab8c9383710bb4a57d4d052123e319734894c68e7afae30', '0x616718fc2e21067af6af15626e6bc718f4f51da61a936cd6b19e37975238053b', '0xe8f265d7a2cc6baf8a3914e31555cf7d675d6a7012a84355c542380059f75349', '0x53527934680e8c17b67a4e8a7b2299fc5258c626c7133c59203b28a5566f72cf', '0x4bf2843c79ff85ca5fe2ac14257cbde6c14226c73511fd7c98d36820201d56c6', '0x260191d44a805f529a49b4fab2ca8da126df5fa7cf9fdbdf06bcb2704c8788da', '0x246ac57f5fea115cdafbfc83c1c97ce635d7011b5dad13d63bd59b47273e3144', '0xa29e10c7c1810668816a1b98171bb67717b6f28d1a2a7c052ac5b8bf8c686e7e', '0xc1c93e417440f33dfe65a2027deb39e7804b34cc250679e07b04a2f339c7d18b', '0x1efbb6ab252589e9a5203375de7acfade60e0df449c495496898d099ca4ae45e', '0x5d0f1b5a883c00f6c3cde54455554c3a0281d19f21e66af40e63e2ba23af1438', '0xb3e3c3068d7845e69972c3185efbeda3acf3a9423a0dac05805e762cf0883233', '0x8017f9153308af465cabe31a75d538180c01540961b7ad7a5aef0b088b65ba3a', '0x5974b94b122ea1e1866405b203a1f072a9a322b8793dcb2a678fc43798f09f84', '0x1cc65190e39275c616c796d0882e603e80bafed23536c7d5c90d77299334cbea', '0x3ac1956d99ba1369591a3c54b9dc7f2656bffd99bf3b3ff7322a729ffb66478d', '0xc39568d5360b004067602a2f23c4eadb691ab09a0e18d468a65a6301ba30ea0c', '0x715ee0f8f105500be5b1103dd212b04d987f5317eec85a1de3de375b3ff7beb4', '0x41cb73c59ed2492286bf74530d462469e52c9b8a4d04bf462598906e6cf38702', '0x250cfd69611ec470352f32ed99cb5e730ffc5f9092798658313f8931b7c47bb1', '0x229de6694467bbf4d0dc47fc768294b18cb29198dea5e0546f229d96eddcc147', '0x48feeecd2ed6782b47490f42bff2ef2302b4c99db4aa4a7262fc9dd2d6e76f65', '0x5d11fc155fabf263cc491d9ce9836df5a7698f59ca14f6e16429b4a45faccea1', '0xeb294a51bcbd026d93af259ffae81a54f1e947dd77e519b5e92971dc6ad3cf46', '0xfed0c04ea8c48bc9de5ed38d22f890bae16deb7bb6ba23b442178bc35c0dc29d', '0xfa2cbb92dedaa36b3b8a96bd183dda10613dbe9d6cf3211b54dda30946996e46', '0x50a263f01a38378c40276637bc3740fc104e3f62993cf84ea7bdd65c855684ae', '0x7632cd4eaee923e2c9fd6d72412c5cac44f783234b71ac2398a887754f00aaa8', '0x460d4ae3e89d37a3ff0788f608f4408c039393911b7871ec8a0f230c78264d8a', '0xf9ac843208f5e79a360438f38592b13fd24a9a3e1d7b5fd6c58d1319dec00255', '0x662897d1de4cc514b36f7a45509085fc6ed7b3368a8de1a9d90ac4d291a74d96', '0x4b53bc793a37f450ca0589814ea29dae791af5d5f3d7d8bbac05f1b68d7bf6b9', '0x6ff26b86d1809587eb79259648c930d07dee8229796e51c1529e1b6f3fc49bbd', '0x7e39bf0fd04cf360070d5408b42211f717ee5fc751eb10a8f98444597ffcf6d7', '0x0af20258536307045fcb639c3afb1c5dc26c2acd824fe61d0a598795fb37dee3', '0xf674cbf1aa68eafbbfb0f2e7012f08633283b24df9a6b3badbb97b9e1f47a388', '0x6b047a072299da246124bf6c785500b2a8e79a8b1154a556906e9ee117604818', '0xebceb3897f12948ba2d8b5e26aea7a3d504afd14b42863f03c9473746bbe934e', '0xe732e35c651995182f7f9805caacf7595a72141a388fcf1b5e72507cb1316a1c', '0x11974ec52f3ae271ba4806fbe68d393fe88e375311bab048bc34b737e2fead01', '0x8839e3720fa88fe72d94af3cd026d433cbb3694d9509c6e117979b2cc43d3a9c', '0x110543b8d474fc9e37ec772eec8bfbc3e30bee42d1102f41e540d772d9d862f8', '0x524af3fd92dca05436c43a6f9e3c0e34cc63717570c83fceff5bc3c4fbda70ba', '0x9890a92f53597fcd564fd9a372aea0612baf2c945d4fd1caf1e08417da7f5590', '0xb498c11cca2b0e079e772f508e405168419b325b9f0eb98d05ee21a6473d4533', '0xc2ad389893e7ae125060248d714fb5ff51948fcecb49a5378aa7714ccf71a3b9', '0x5455952a7fe3d497bc4b2826361dce7899737a6cb93862c539c8bf0d2f14f481', '0xc8dc29cd58f923faa344bf4211c3f74b0a1ab583d8234817c1f2527a9baea367', '0x94bce3396b6e2cb8d7f21c5947784e49a4a28f788f9c78d55bbd54da7631bd46', '0x3df9589ef3c0bdff9694acf66ee04dfe9696c9b962c6b2ee94298b5bfd1d443b', '0x230367141ae401fdfb3d0dddd7683f8c50404c2e5b793e0d1196a8832fbfd81b', '0x59ce70e6efde4c8f037dcf3c66754f1773348c06c6356f2f8f4f368f29bd9a7b', '0xf5a1aac6d69c57edb750e7faea74301fc173fd8c8f7f27b2b3bdf72387402a6e', '0x7117a24c9874958b9b1ce722c427cb61e4a5f53ce39931ce092c175aeb102294', '0xf3e0be529d61bb3ac0f2c03fdd01fe6b4b3f8d1e15b7be8777b6850f1357d73d', '0xe28c8c535c2b5b0aacca6d96db7bb7fc45095cc4d39f810142de5c0924cb9a49', '0x82a5c22b1b9cef12a842c3075edc7cc5b3b141e3197000b0fe3132c3721616f4', '0x22512f8faea263d46908a50b1899631f962e8fd42a02c3f08ffa18646fc5ace0', '0xca6cd7c9ab73c2f8c59eb6c16b50745e15f4dd59ca9e11e3cb033322ef2f7446', '0x51e27a0b66eb29ae1f7adc425770bb899943296d0f5c2be3e02468b4887e90e6', '0x1766095ecb96b634ef36df5a6d60e3b7c8e7511ef580bf5aaaf484a3edfe620a', '0xb3e282d18e4dd6767334576e36ee72f70ae69a5c26c6d1bb864e1ae1e0671cb7', '0x8f1f97abea0c084a592e3f610c1f68696a7542fdee08d5be41225d2b113c910b', '0x294681c8b130dee53ca917afcf7db03d31cc145f896b2d6273f464d4c1fbf408', '0xb4b70da601407621a34367f107665a3c092f59e56f91585df794df284a8b8fd1', '0x4a0194ec0ec7973feb0a91e0237e2935149af8c8c18f333f910f10577ffc0c0b', '0x1568f0574994ee9cca391d0c47ac023ea72ca4f0812e7079b0c3ca46813b8508', '0xe937a47d30c736c2f422fd4842103187c39e447e14389fe4cce4356e4d22face', '0x6957ea9ae365b7bbd0d4c0f12c7b5f51060cc6c1e21c4b74a1fa9a7990943da5', '0xbe14ccc6066a78b3de933ecad85e2f5e00424f331539bab01b7c667b048cf0f7', '0x7289d93105209be77fb7f30fdb468a1f44193a7e39c4832af309b792d398240b', '0x650be2eb1c4c0514f71cc47d035bec528cbddfa433d94c6807ead627f7dbbb06', '0xa7be9b9fb933acf4f48d57544fa73c9eea91a41d38621a749996a393342d8656', '0x41e71953a6a82ff7abf82d45b344889f8369ea79f2a4ee5342b04626c195c081', '0x2ae8541e39bffaaf08934f11b68c027613ad6c8bfb7e5600a8ce8acd0b097268', '0xb130ba6c471c03251fa7304c11665f677bd22a383837cd48817756e587c3b79c', '0xbbdf7f2377a80461d094c7e098a4c3c0c2660d9c0adc1868a04567fc84b94362', '0x19a7d44618c16ca5191d0b3e83f89fa9c6be09a1ae9f343354e318d00924eeeb', '0x05ccfa68019b34ae78e05b4f92831cd0116448929f79148411e53a7dc2b36f14', '0x86ae36d4632c94b8a5d46f45d0da595613126f81a7f115573ae8b8226319953b', '0x2d98b1aca653f3a3293799a5132fd115c250ce8326b484d6aa18e477e62cb734', '0x0c34e6c9842bada3b2fcd9d064683981a82543281923bbb31ffb0a09f2b79e95', '0x285ecb9822e1aacfa87eb3893b3895942e2026304b5c041ae046fb7a4bbd95ca', '0x0c3848372820c2e4b8e7463ebfec09b6b9e248aee47d3ad9023db2877daeb836', '0x0602b4fb3ef5e4e0ecdd457d7a6ce5bca55886cdef6cd75e37cc45dde6bee72f', '0x6e1a54a3f5836a67c96b138f3001c16a36acb3c123c9d3fbe42df2b10a3a0de1', '0x0309836c603e111b718764337fcc6fe181b6cc291d6031f2657f60ff9909b129', '0xc735fe143ee0d8936847e828039c3310f60c8e8096ff6b17c3d82bd0ee09ca2d', '0x45487a883062839a6a080179d61db31deb0e9b5f15609ec992da03155925d761', '0x99781487a1a5e5a4bf4078ba7746bf354cd7a3c5c57e0786bf88817f35356bff', '0x29a512be466d50370495843c222fc8983c0ef22b23f2fd237bdfd9f104957a2f', '0xcf87d1f5ff2f42bebc162f4810320367baa87d6a7fe54006e45ca424c672b051', '0x7c577d5ff53dc374bd20dfae642dcba88977ecc35a0b5949ee0f9f665d5b6149', '0x5e4f2fdec471cd2a57bd468c43bd9282162297581d174d1430ac323adf3a2318', '0xa990ab885ceb1c7eebfd75b674490b571c4664299ecbe18f3505e7cce1d4a2f4', '0x1dee05f8b56c79c5b7084dfd772467f3c61267d7ca45a3ae026d586111c4baa6', '0x077501f0121d220aaf440520ddcbe299f8c70b78d496c8f911fc7623b35a4ddc', '0x2bb2824f1083cc98035aacd35bd0bc97e6fbb40a28ab52025ff3134f9bdca683', '0x969455011093cc9b6f5cad8bb7970881e28e5fba1df44147e60a3e88212a53fc', '0x1daf3b32237117d83a75bd7f6a05db994d44542dfc9d974c459eb801161a06f1', '0xa6209d0cdbb736555fc07fd626624526129875cd1ab45b84606d72ba5609cff4', '0xe303b0a8943a06b13f65e7e0f876ff628457b7f5a5392fffca159a7ff556b775', '0xec72d2d355a00e0de3e082e0cb1ab48433a5ae25d99de7b8403a12773eb4f3a1', '0x9fa53c012bc9a208ff1654aa12c2af649b16260a8b67db0ecc1daec635ae4419', '0xa9d0871a386698afd384e5cec168e6311028481994e8795ab3172968845a946a', '0xb651f7eab2d66d5089328167f57af6c606c3cf9d49adca464eb46c2e2ed55be1', '0xa413ad5ee6a30aceea403328a990eff8e8c2be068484cf23274d2e18ea9cee56', '0xe37af18018806bb38435a3684959575e0068f7290e6c8665fce439028543c0ed', '0x5be60972faf1536fe0f9bc96077eb1f9e47ea7ab288358045ffa78b44cbed345', '0x9e607d0133d97676412348f7e466615a58adf9440de38329664e7d895a338b20', '0x7cf2e44e0f817d4cf44aa0d15dba7c8375fe5eb9fcbc867bb64ce66ac8d01ac8', '0x928eec35a111109284dda91ddd3c31a05cb24f68c607a85411ae4a82a2a69e5b', '0x67f0a6fdb7e5b7e19708208a1fa9772e668bb9712549ccfa064dd80378529703', '0x69c95e0636ffe01d8ef03e75c03945371e4e79233bc75339e42ee85f619f3c07', '0x73b3cc4719e093e77f2ace3dbde04dc7be17b9e0338ef775166f1e83b4a2c456', '0xb76239ab1e36d710039b9675907e7e26729afcc81bb929d5f240da2be2c6560f', '0x5d9e72603cbefb0017e516901f833612dfb5f3a322b97c3a5835105b627e0386', '0x4390f817a25b3887d50a25e80c7b872d53d064ebd4f743d87cfb8baf0e711114', '0xcca6f18056524af96493c541be2e4ee239204a3add4255526838428b410c7ded', '0xf48ce62aff52e7f8f07d5016c587b710837cb0b4f96f865c4f2b6d6922ebaf80', '0xc9137cf75f45695591ef65799daf102213c021d498810a0625c38e24c4b5bce1', '0x8c7709a37ad4686dd27b9e7cbaf239857610b977cd69ffdac786e2f916daa60e', '0x3cd17aa5d0530e64bbe625fc69260c1d9ca54ac8a361168b0caa97fe552843a9', '0xdf3a3152fe4191632db5025be2b91e38379f6b852e79dd4d60c8f4d3ec6a202e', '0xacf704d96853979a9e7ea523a1ed4a784e4638b8f74714a7628c86421fe4a317', '0xe0d1232226579cfa7030f172ab39a8877aef2d483f85d937955fa432f3c2aa33', '0xf04df87a4461171e9a74119bd8d80bf729c820d7d0ad279234fdfe2122c3b55a', '0xea3bd821c873231810d5677e3c07bceea14787e28abe5e51f014ac83260d3662', '0xb5ee0dda270cf24eb576669b319606e490cfc22a369758b7dd0aafe2f5d68e4d', '0x0cf777764ef648b7c78b3a39c9abe707f7b361cd9e1a69ed15d1d8116e08d7ba', '0xbc9658cb2c48f58cac3b487d67a750d9482ce4501148c0d2fb7bb2ea5ce78142', '0xd3cebe20216365a2526e4db3869e6a47fbd4463ad99b46e2f86729be94e5eacf', '0xfd82b1b0e3eaed21369add698c458ea7ef0d26ceff4b6f0b344f934a0d75d91b', '0x398d1e4e0b0394f07ae2d4aa4037ad97d790c8bec740314c44fd150d6898b2df', '0x01c1423290e8ef57a2795afc9e160724bd1542dc7ddfaea494f7e88881fb8b15', '0x48a2db31cca6722f11721fcf23a48d06e9047e8877ab53389d3f5d923c8f0ced', '0x29b79737d0776f4a7a9265bb860e73062c89fc9b50e0a8034a8bf14ffdd9f4b9', '0x4e00b89b1b6270310c74e2b3779a2288089caeb12a853f11b3a89b4aa13b6918', '0xc1e04dd8a7b22336726c6fed1e7dde12d9cde5255b35d59c060a994e06e72a16', '0xd8d2b923e069131ce3886ebc9fb741f5f704ce8243bface70c30e86dc28bd0a9', '0x7c630a78fb0dc7b5f20587e97c3b285aad6f2490779b4e9272f4dac28f0dabcf', '0x64f635404325924e5d73e4c547d3d427ef7e94bd5bcac5752114dfc351a8fbb6', '0xbc684aa61be649908a81b492b06599304501434a83b5ca0358807894059f68aa', '0x7e7324e2c76e5bc14c044bf25e3fb1e9541d258a9dac51e0acc62aec6762e637', '0x4d8b3d7dd2eec397ff1af32192e5cdbfecb875067cff69e0a98eb9dce3c5c5d5', '0xc455141095debc28a54569a139dab4c0818b4cedc5de8bbcbdfb307815a7e0df', '0x2873a4b75325c12171021a4ea0689a0aacd4d7ad68e1a4a409b5bd0fe24788b4', '0x673a53aa6fc16875bfca9edf95c6ae7d75919f305848b8dd0bd5fa092a91d2f6', '0x3aa38ce8ec76bced25aac08ae7c623e2de0e41aeae03639b7903ca47d9688eb7', '0x174020d68049eb0e6d4485a12189a9fcf54db64c9c370d8213927c6d211cb70e', '0xa9e9b1616956685e6322da8fe5138fb7ae62034319feb8c6aa2cd6cbcf13d53a', '0x15b8b1d4842786b75d414f6802be2501476e70afb00b73c6eefa5d3abddf2dc3', '0x33af4f0f621b5cdb05df6012275a82aba7746a826c28b05bfbb4e68f32b06ad5', '0x1ed73fbd0c21e76f015594ee5e5549959f22513d0679277918ca0c2266c7e01e', '0x7ca3931158c4202943715e8dc5d09c103a494c5f8a32e9ddee13c0c1df0af6d7', '0xaf65ec85309c12c2a8f848711bb3c249296c79c1615af5536bd740f956cf3cfb', '0xb567e17cbc0914c608e3511f72eb948ae0d024b47bcf22e81ddad1501b9af8ff', '0x87b2a32d838094bd09ca8e3df91b5b8df657a9d09c4d001efe1accc0ce6df7cd', '0xea0cec617b12d149919883e59a706e9172b9579119522759cdbdd88c1e8296fa', '0xc785a1e64a82b343da8b6d8212c5fcb2719a00e7d8235fed2a181bb40672fa34', '0x4fe899d5586b1927377d98fcda028b732ac354571426d725c913c77ded6360b5', '0x8edab249639558bf201873992be7f0db1182599927004ca22af3f5bf16a96b64', '0x58fb17bb45f4e02a2c56a57e4b8b6dd69a23ce0f7c4a1a0fc8284462499b42c2', '0x83607675ce9e5a52dbe771bb8df89a0057f7200f8946adf92bdd4a7a87cce8d3', '0x6ac2ab9765f3fcdf32a9b1704a7c7225841bb1d026d25aa96f89eacac759ba92', '0x08e58f3142bc3598fed4755df19be5e7fc8cde59a83b6dccfaa8c734798cf94a', '0xb3675a3958717b8542a03f179be5347c76e0441d380a70f89203312a3f3ef5af', '0xb6293c3f18690a0a401d86bcfbaad8680889cb5eee02cdf3afda7ade10d0c0f6', '0xffc31ce7390af9c32ad4b4d5de314db5cc74efcfc6bdc6ae50f3e5a793ecf121', '0x4c35b4f9bbec288c22291021c9b5c060b13a870c3bddd02cb18379f80e31c34f', '0xf913bcd90bf26bcd59240fa46c3b4d0a11eb09d585c6fe856b9bbf2456fd68d9', '0xb67284768c5faeb493b6bd4e8fb6345f74ea760fd6df9f3ab5a7e69b95d1e690', '0xb068b58232757e7975ec63f6e6bb55c32587e1934b2113924308e59b77ef0702', '0xb8d747f84efd435c7c79c77b4bd7ec74868f94811302fab68eb6b05ad04b420e', '0xdf107c7eebedd9b4ec55fd16be299b1bcc36d9a77e91a2218ad9ee938c653a3b', '0x9dea3ac9e2b205f39f758562ccbeb6956464b4c71582514a0b922464eb1df904', '0x09b2f586cc1466f0582f21d3ae09bde93cf0ad90a8172694ac94494d1070dc45', '0xd0e7a49253cdde0a32f5337c793544513851af06bbed0b45865eed1e223cef12', '0x779cb9224f27d502d8df968f7062821004fa9fd82235b69eec6de26bb05c187e', '0xe0cf68087231503e3f23f0810d850e66c0509bee08dda9ca7d7e477ad32981ba', '0x382fb95087e92b2d5545c580645259232b23591e2f61971bcba523c9f6579349', '0xb55c5342da7c5bce86e107ad2ea43072dff99f854c2f6b6257851c5db17fbe9c', '0xb726159080411539356133978e6cc62d4152d55d3cc13f7357491f816d26a6bd', '0xfd585b8058cf4ec5fe4283c8b9cadc35f62778ad29bbf7b31ab4a56618a261f0', '0xf489f4435e1068dbc142f884f08c5e86f2e2534d1b9bcde7b6481becf528d84e', '0x472c863a5a226dc1309f6ca4cd5acbb3cd6f82973587719ba622bf5ae8208ed1', '0xd7977ba813c3dbd274c7efa52dce1c2c1c676ef043501803090b09c4e707172e', '0x1554df0f928af2c3635d131646f30670b07c47bc2f4dfaa08ee500463e126e3b', '0x8cc4eba9a4853bd82f7b0cc0bd8bcfc4cb452b85896f3374d9457c92518564fc', '0xd95d4229472fede25ba25df40fa54cbad8f916db5aceee8534616b170283d5a3', '0x09e55bc95a066700eb3b1ed2638acaa945fe42bd0c288a3088a77ba91e8327cc', '0x3d68b0860147938e2c48a4c6d2b8118322f5a5fa07148eef3e4cdd49818d4b13', '0x2955068078b4c1385a529465054e39057011d38b661a7435426421512092a534', '0x5431d9731ed12bed90c3c3cb146453617c0ab7af96048721395e9f7b7df5bf6d', '0x07c20563e1e9dac6f4b46d013299006daef4ea82ba1fce5b1b0d601ee22a7c56', '0xbd8d0b07e1c678c31e9e821f994e1d89a79efc41c7f328d7dc5414b8acf75d93', '0x8f825e71a18ae8766d9ee9a05d5d1269a05e2dbf82556f643df7eb56a0fe4a6e', '0xe494e69fa644191b0897a2e4455063eb8f1698655730919c64448b2d14e14b4b', '0xb8d2f9f83b7b6906b54541e0a8f52130bca88fc81e6fb9676ba99f212255befc', '0x0bb7dd1c0f4419453d817c06f5e4e04adc5cbfec3f4d5971d5dab8f09678cf5f', '0x151a7df30a25a88cfeb6d551ad7f90fe532adecf97c4a4ed38714bf312db22dc', '0x8187fb3a6a417c00f49630ec72084127ea5c33ea468f27aba1bb99647e3086de', '0x9164b9ede742cbeb1698c2719d2bad92209dbf17d5f31b501857bdb1fe45b99e', '0xa9133cbf7035754bd99ee6fb0b2ad9f5af036dd96c077e4f26371a97664f0226', '0xefb945de9a459f852405ed709a751de8ec47e258020904b55634e49d74f37dfb', '0x3d5831a016dbcc14ac1ead16bf93b1eed5b653f0df343172b2204e35dc47697b', '0xd46be0300d7b6cac8b95931e420ab17948e3ecb54d5dfdac6fe3f9470a1c75ee', '0xfed003692f69e65e23d4df371edb024d17f92572cff933987edf3c09ab843371', '0x4d7750dee9e2f6665d45ab037c35bf1f5fc1b7b55bf8a372f26acbde0a9be8e0', '0xc8207783ca90b52309f4f9c1004ec977ca70650b2f96cfd1a3aff2987bab6e6b', '0xe4d453568b04190286f8e54a89ac79ef4b03a2140f843808d4b364355bd6010f', '0xc147cc5ed6759832cb973602fd2e417450be36d3c09a964cea54eb5b7244d7d0', '0x77479499e7ec77fc4db51d3e23d638350e069874043ce9faa6ecc55f3a4cd24d', '0x61ed7a06582bb57793ab3e1ccf8331c2b2321dcd1220aceff7b1a4d900bc6022', '0x87983d74407d38ceb5283ce6573aca2b8ba426dc1e8e286fca103efb35dcf5ac', '0x8cc6007e3dfe3759ff963f75344b6c344a26f28ed2f08e990332697bb65ad2a1', '0x6bac3688f6c10fca3bc41957e21ca0e4161564b63f592ec540c543f317403924', '0xff4cac021d2cbc9f66fdd19f467ed76b540eecc0be20b32ae1352356ed5fea8b', '0x19df496ef0b0a644efeaa8d7568ff0404779e9e5fad9ee1f9fd34118f998e867', '0x5fe3a4051e043776ef2553d94d421572807ca276ed7f33564dab4c9b5919ae29', '0xff2e00ca3b99534b056d13bb32150c9628cf9cb8ffa53cd5bc2dadfddfd0f42d', '0xd99ff98eef0f31025d556d9f204c7d82b4f44b5715eb7f085e64132166ada715', '0xdcc1a08ce5ea471e45c25dcf7b93103c246626dc35c90a1a1eb0dc63e5d8a391', '0x263d2999b4bdd945612e59d83512cdc9b455345e6bed701c5cf8ff23d0cce6f0', '0x3993fb3d02f794a3e34a0154361c142b21341cc3d3717102d3133ecd87d42c33', '0x1508ae273f45ae59d87a21b152ec04d086341cdcaa56f110ad74da4d348ddd41', '0xa84d0e785b063a1d13503baad8c9d7f8c7183d9acb1bffa2611717df4ae1bf10', '0xc41e29bf419f211093b90f584f15be7dcdc22f36ba7842263d94a3552f4155be', '0x0f78e2e5c401d1af3c0802c6e84ea445327a530791a5178d20f6378137538270', '0x03603b8be027b1064a883ff4057a1a7f82995b1d6f35ce4c97db59acc1999b2a', '0x0d3b94edfa612f6d5207171282c0e422a1a6743ec42b5372e20eae4c1fe056e8', '0x94de9bd5da215fe7b0d6eda48b0d831b6cbf848f6cceb6ae4661f1713abf0b77', '0x139dba20088a7abc618b54b0af36d5bfb10a88469c4527184a456e83cacd0a6a', '0xff0a63f25404c4a76c0061e2fd08ec15a330bcce193d1b83a896993a0f7ce018')
Saving the game
All functionality of the ether_real_estate
module works through the Game
object.
When a Game
object is created, there are five directories created under the game_path
directory that is specified during instantiation. A brief summary of each subdiretory is listed here. They will be explored one-by-one deeper into the tutorial.
1. building_bids
: This directory will receive human/AI player bids on unowned buildings. These buildings will have a portfolio of lease agreements as well as potentially some vacant units, and at each time period players can bid on unowned buildings. The Game
object will select the winning bid.
2. firm_bids
: This directory will receive human/AI player bids on firms not currently under a lease contract. At each time period, players can bid (suggest lease contracts) to firms not under contract. The Game
object will select the winning bid, and the winning player assigns the firm to one of the player’s buildings.
3. stats
: Summary data for the state of the economy is output each period to this directory. For each building, a list of which firms currently occupy that building are given. Firm industry membership and lease agreement (if available) are also provided.
4. cash_flows
: Historical cash flow data for each firm is recorded here. Firm cash flows are given by:
\(y_{i,t} = \sum_{k=1}^6 \beta_{i,k} y_{i,t-K} + \epsilon_{i,t} + \nu_{j,t}\)
where $\epsilon_{i,t}$ and $\nu_{j,t}$ are firm and industry-specific shocks. Players should use these historical cash flows to determine rental payments and default risk.
5. blocks
: Each mined block of the Ethereum blockchain on which transactions occur is saved here for easy access by players. Because bidding for buildings and firms is a competitive process, players would do well to review the blockchain and determine the financial strength of their rivals.
Bidding
At the start of the game (period 0
), no buildings are owned. Players must bid for them. Building data is stored in the stats
directory. A snapshot of this data is shown below.
import pandas as pd
building_stats = pd.read_csv(g.path + '/stats/0/buildings.csv')
building_stats.head()
building | size | firm | industry | firm_size | rent | maturity | cash_holdings | |
---|---|---|---|---|---|---|---|---|
0 | B0 | 20 | F0 | 0 | 1 | 4 | 2 | 4.0 |
1 | B0 | 20 | F1 | 1 | 1 | 5 | 2 | 5.0 |
2 | B0 | 20 | F2 | 2 | 1 | 5 | 2 | 5.0 |
3 | B0 | 20 | F3 | 3 | 1 | 4 | 3 | 4.0 |
4 | B0 | 20 | F4 | 4 | 1 | 3 | 3 | 3.0 |
All buildings are given a size of 20
. Firm sizes start at 1
and grow with cash holdings. Firm size increments to 2 when cash holdings exceed 5
at the end of the period. Firm size increments at each multiple of 5
thereafter.
It is possible for the size of all firms in a building to exceed building occupancy. In this case, the Game
object randomly selects from the set of firms that increased in size in that period and removes them from the building until occupancy is within limits. This can create strategic value in reserving some spare occupancy in a building.
Human players create bids for buildings and submit these bids as a .csv file to the building_bids
directory. Once all human players have submitted bids, the game organizer (e.g. instructor) can instruct the Game
object to create AI bids and then select winning bids for each building.
g.get_building_bids()
Property acquisition completed:
player: p0 eth: 14.44375106499403 properties: ['B2', 'B7', 'B8']
player: p1 eth: 204.3377445424868 properties: ['B4', 'B6']
player: p2 eth: 354.48224739631064 properties: ['B5']
player: p3 eth: 153.5332989721354 properties: ['B3', 'B9']
player: p4 eth: 190.28382811566786 properties: ['B12', 'B13']
Here, the 5
AI players have bid on buildings and the winning bids were selected. Note that winning more or fewer buildings at period 0 does not necessarily set the player up for failure. Over many simulations of real estate games, I’ve found players with one building to win the game as well as players with three buildings to win the game. Success depends on building management (contract selection) over the following periods.
A snapshot of bids for player p0
is shown below.
p0_building_bids = pd.read_csv(g.path + '/building_bids/0/p0.csv', header=None)
p0_building_bids.head()
0 | 1 | |
---|---|---|
0 | B2 | 175.342916 |
1 | B7 | 175.131356 |
2 | B8 | 172.942416 |
Once buildings are awarded, players now have a knowledge of the amount of spare occupancy in their buildings. For players with spare space, bids for firms not currently under contract with a building can be bid for.
Human players submit their bids to the firm_bids
directory. After all humans have submitted bids, the game organizer can instruct that Game
object to create AI bids and then select winning bids for each firm.
Bids on firms are a rent-duration pair that specify the terms of the contract. The Game
object will automatically determine the best contract to select a winning bid (based on the expected contract cost). Because some contracts will propose shorter durations than others, the Game
object will make a naive guess at contract renewal rates in order to make short and long-term contracts more comparable.
g.get_firm_bids()
A snapshot of firm bids from player p0
is shown below.
p0_firm_bids = pd.read_csv(g.path + '/firm_bids/0/p0.csv', header=None)
p0_firm_bids.columns = ['firm name', 'rent', 'duration']
p0_firm_bids.head()
firm name | rent | duration | |
---|---|---|---|
0 | F270 | 4 | 2 |
1 | F271 | 5 | 3 |
2 | F272 | 3 | 2 |
3 | F273 | 3 | 3 |
4 | F274 | 4 | 2 |
Players can bid on as many firms as they like (from the set of firms not under contract). The Game
object randomly selects firms from the bid list and awards winners. As soon as a player has completely filled their building occupancy, additional firm bids from that player are discarded.
Saving the Game
The Game
object can be saved so that it can be resumed at a later date. For example, if the game organizer is running the game on Google Colab then Python will time out after so many hours. Before the kernel times out, the organizer should save the game, which pickles a number of features about the game so that it can be resumed later.
g.save_game()
Saving the game
A saved game can be resumed by specifying the path to the saved game.
g = ether_real_estate.load_game(game_path='/home/james/test_game')
Loading the game at path /home/james/test_game
Incrementing the Game
After building and firm bids have been awarded, the remainder of the period runs on autopilot. The following sequence of events occurs:
- Firms earn cash flows
- Firms pay rent
- Players pay taxes (both on income from rent and on property tax for buildings)
- Defaulted firms are evicted from buildings
- Any unowned buildings are randomly allocated more firms
- A new set of subdirectories are created for the next period (e.g.
building_bids/1
is added if the game is incrementing to period1
) - All transactions on the blockchain for the ending period are written to the
blocks
directory for easy inspection
Because the Game
was instantiated with the verbose
option set to True
, the following command will print out lots of details about the incrementation of the game.
g.increment_game()
Collected rent:
player: p0 eth: 236.44375106499402
player: p1 eth: 343.3377445424868
player: p2 eth: 426.48224739631064
player: p3 eth: 285.5332989721354
player: p4 eth: 327.28382811566786
End of stage:
player: p0 eth: 207.0476726336215
B2 ['F36', 'F37', 'F38', 'F39', 'F40', 'F41', 'F42', 'F43', 'F44', 'F45', 'F46', 'F47', 'F48', 'F49', 'F50', 'F51', 'F52', 'F53', 'F283', 'F284'] 20 20
B7 ['F126', 'F127', 'F128', 'F129', 'F130', 'F131', 'F132', 'F133', 'F134', 'F135', 'F136', 'F137', 'F138', 'F139', 'F140', 'F141', 'F142', 'F143', 'F287', 'F288'] 20 20
B8 ['F144', 'F145', 'F146', 'F147', 'F148', 'F149', 'F150', 'F151', 'F152', 'F153', 'F154', 'F155', 'F156', 'F157', 'F158', 'F159', 'F160', 'F161', 'F286', 'F289'] 20 20
player: p1 eth: 324.8122543464084
B4 ['F72', 'F73', 'F74', 'F75', 'F76', 'F77', 'F78', 'F79', 'F80', 'F81', 'F82', 'F83', 'F84', 'F85', 'F86', 'F87', 'F88', 'F89', 'F278', 'F281'] 20 20
B6 ['F108', 'F109', 'F110', 'F111', 'F112', 'F113', 'F114', 'F115', 'F116', 'F117', 'F118', 'F119', 'F120', 'F121', 'F122', 'F123', 'F124', 'F125', 'F276', 'F280'] 20 20
player: p2 eth: 416.9387179845459
B5 ['F90', 'F91', 'F92', 'F93', 'F94', 'F95', 'F96', 'F97', 'F98', 'F99', 'F100', 'F101', 'F102', 'F103', 'F104', 'F105', 'F106', 'F107', 'F275', 'F277'] 20 20
player: p3 eth: 267.167808776057
B3 ['F54', 'F55', 'F56', 'F57', 'F58', 'F59', 'F60', 'F61', 'F62', 'F63', 'F64', 'F65', 'F66', 'F67', 'F68', 'F69', 'F70', 'F71', 'F279', 'F285'] 20 20
B9 ['F162', 'F163', 'F164', 'F165', 'F166', 'F167', 'F168', 'F169', 'F170', 'F171', 'F172', 'F173', 'F174', 'F175', 'F176', 'F177', 'F178', 'F179', 'F273', 'F282'] 20 20
player: p4 eth: 306.8006908607659
B12 ['F216', 'F217', 'F218', 'F219', 'F220', 'F221', 'F222', 'F223', 'F224', 'F225', 'F226', 'F227', 'F228', 'F229', 'F230', 'F231', 'F232', 'F233', 'F271', 'F272'] 20 20
B13 ['F234', 'F235', 'F236', 'F237', 'F238', 'F239', 'F240', 'F241', 'F242', 'F243', 'F244', 'F245', 'F246', 'F247', 'F248', 'F249', 'F250', 'F251', 'F270', 'F274'] 20 20
filling building B0
16 20 182
39 <ether_real_estate.firm.Firm object at 0x7fe3287b0160> 2
filling building B1
filling building B10
filling building B11
filling building B14
A snapshot of the blockchain data is shown below.
block_0 = pd.read_csv(g.path + '/blocks/0/blocks.csv')
block_0.head()
block | from | to | value | |
---|---|---|---|---|
0 | 377 | 0x0CCcC96D89f2C203939CC0629caEd7C59f2543af | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 3.493930 |
1 | 378 | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 0xe637958EdAB4A6b142a9E7a8F1fC27869A4C893c | 6.465874 |
2 | 379 | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 0x50D64774DddCDB8c3346b127d211F93F0e2C4CCA | 2.366918 |
3 | 380 | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 0x2B8a7cE3D79da4a31e175ff360E34B07a3b76b25 | 23.017025 |
4 | 381 | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 0xa553c5C42aCdE9BC5511396FDe73Ce800ff58828 | 7.903728 |
The first set of transaction are all from the same account. This is the “banker” account. Firm cash flows arrive from the banker.
block_0.tail()
block | from | to | value | |
---|---|---|---|---|
540 | 917 | 0x9394090a2eD31Ec8C88b6926f399f8b719b76E8c | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 9.543529 |
541 | 918 | 0xC1656f56829cdDC502B53ccDfaa4e29E65040748 | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 10.636863 |
542 | 919 | 0xC1656f56829cdDC502B53ccDfaa4e29E65040748 | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 7.728627 |
543 | 920 | 0x0eBC438EF99b4Ab21D5633037D6B05e44701185a | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 10.790588 |
544 | 921 | 0x0eBC438EF99b4Ab21D5633037D6B05e44701185a | 0x0D3A4C9538e94fC132701df365e61466B797f17b | 9.692549 |
The final set of transactions all send to the banker. That’s because the banker is responsible for collecting taxes from players.
Ending the Game
The game ends whenever the organizer determines enough periods have passed. The winning player is, of course, the one with the most money at the end.