“`html
The material presented in this guide is designed to pertain to PoC5. Most of the directives provided beneath will not function in the previous PoC4 versions of AlethZero (C++) and Ethereal (Go)
In the preceding weeks, we have introduced a considerable amount of modifications to the Ethereum protocol. POC4, which brought a significant array of changes initiated by Gavin Wood and myself, was revealed as an informal explanation a fortnight ago and has been formally detailed in Gavin Wood’s “yellow paper” at http://gavwood.com/Paper.pdf. The specification of the protocol did undergo substantial changes, yet concurrently, aspects are becoming more stable; we understand why we wish transactions to incur fees rather than contracts, so that’s unlikely to change, we are aware that code and data will remain distinct, and the byte-based code and memory along with the 32-byte-block-based stack and storage are unlikely to undergo modifications, plus we recognize that the functionalities of the EVM broadly will be comparable to their current state instead of resembling an intricate Merkle-code-tree arrangement. POC4 has granted me what I desired from Ethereum Script 2, presented Gavin a much more optimization-appropriate VM architecture, and offered users a sparkling new currency. Simultaneously, Chen Houwu, Heiko Kees, and Konrad Feldmeier have stepped up as our primary Python developers, and the networking segment of the pyethereum client is progressing towards readiness for communication with Go and C++. Alongside all the administrative duties that come with holding a crucial position in an extensive project, I have taken it upon myself to enhance the pyethereum VM implementation and the compiler for the HLL programming syntax.
The goal of this entry will be to deliver a comprehensive technical guide into the functionalities of pyethereum and Serpent, demonstrating how you can begin creating the instruments to construct your own contracts and applications. The Bitcoin Expo hackathon is occurring today and tomorrow, so feel welcome to make an Ethereum contract your endeavor if you are among those participating.
First and foremost, importantly, HLL has been renamed; the language is now referred to as Serpent. Why? Because it’s fundamentally Python.
With the latest enhancements to the compiler, Serpent is now a highly comprehensive programming language, equipped with powerful capabilities including:
- Arrays (e.g., x[0] = 123)
- Array literals (e.g., x = [ 34, 56, 78 ])
- Nested arrays (e.g., z = [ 34, [ 5, 6 ], y ])
- Hexadecimal support (e.g., receiving_address = 0xb156066c2978d7b9188f2467b815d4c62ae32fe2)
- String support (e.g., x = “cow”)
- Inline message calling (e.g., usdprice = eth * msg(ethcontract,0,tx.gas-100,[500],1))
- Out-of-line message calling (e.g., msg(multifeedcontract,0,tx.gas-100,inparray,5,outarray,5))
- Simple value transfer operation (e.g., send(receiver, value, tx.gas-100))
- Returning values (e.g., return(45) and return([10,20,30,40],4))
- Treating message data and storage as arrays (e.g., contract.storage[1000] = msg.data[0])
- Byte arrays (e.g., x = bytes(100), setch(x,45,”c”)), y = getch(x,45)
The aim of the Serpent language is to simplify the task of programming smart contracts and decentralized applications on Ethereum as easily as coding mundane command line applications is in Python. The language is crafted to be maximally clear and straightforward, merging the advantages of a compiled language with an accessible coding experience. Just the logic, and solely the logic. Regrettably, floating-point numbers are lacking, along with advanced constructs such as list comprehensions and closures, but aside from that, Serpent encompasses practically everything you require.
Initiating the Process
How do you program in Serpent? The initial step is to establish the development and execution setting. To achieve this, first download two libraries: pyethereum and serpent. The easiest method to acquire them is to either grab the zip files from Github and extract them, or execute git clone http://github.com/ethereum/pyethereum and git clonehttp://github.com/ethereum/serpent. Afterwards, navigate to the pyethereum directory, and execute sudo python setup.py install to install pyethereum on your system, and repeat this for serpent.
Now that the software is set up, let’s dive right in. To begin, try this:
serpent compile_to_assembly ‘x = 5’
[“
The compile_to_assembly command translates the code into an intermediate human-readable “assembly language” format instead of standard bytecode. Using the traditional serpent compilation would result in a significantly more difficult, yet compact, output of 6005515b525b600a37f26005600054. In this scenario, the “core” of the code is [5, 0, “MSTORE”], which places the value 5 into memory position 0, while the remainder of the code essentially indicates to return a contract containing that code. Another potentially useful command is serpent get_vars; it provides a list of all variables along with their respective memory indices. Thus, you get {‘x’: 0}, which signifies that the compiler opts to use memory index 0 to hold the variable x. The final intriguing command is parse, utilized to transform Serpent into an intermediate high-level parse tree. Given that Serpent is a programming language, we aim to execute programs, making it imperative to create contracts and run them as swiftly as possible. Let’s proceed with that. First, establish a file named “namecoin.se“ and insert the following code into it:
if !contract.storage[msg.data[0]]:
contract.storage[msg.data[0]] = msg.data[1]
return(1)
else:
return(0)
This is the beloved two-line Namecoin example, enhanced with return values for ease of use in this tutorial. Executing serpent compile namecoin.se should result in:
6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f2
Now, let’s verify if we can indeed run the code. To achieve this, the first action is to create an account for ourselves. The process here closely mirrors that in my Python Bitcoin library pybitcointools; generally, anyone familiar with pybitcointools should find pyethereum quite comfortable, although, regrettably, it was not truly feasible to adhere to pybitcointools’ “no classes” principle throughout the code in pyethereum. The initial step is to produce a private key:
pyethtool sha3 cow
c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4
In actual production code, you should clearly substitute “cow” with a genuinely secure password. If you desire your account to be a “brainwallet” that is easy to remember, my primary suggestion is to prepend a username, e.g., “vbuterin:bl@hbl@hm0nk33y#!$!%”, ensuring that attackers must target you specifically instead of conducting a widespread attack on all users; assuming 10000 brainwallet users, this lowers your risk from a trial-and-error attack by 99.99%.
Should you wish to utilize your key later, on any conventional Linux shell, you can also type in key=pyethtool sha3 cow, after which use$key for subsequent key utilization. We will adopt that format from here onward, so if you are following along, you should also perform both tasks:
key=pyethtool sha3 cow
“`
code=serpent compile namecoin.se
Now, let’s proceed further.
addr=pyethtool privtoaddr $key
echo $addr
cd2a3d9f938e13cd947ec05abc7fe734df8dd826
Next, we generate a new genesis block, setting the primary endowment at 1018 wei (1 ether) for your address.
genesis=pyethtool mkgenesis $addr 1000000000000000000
echo $genesis
f8b2f8aea00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0bcddd284bf396739c224dba0411566c891c32115feb998a3e2b4e61f3f35582a80834000008087038d7ea4c68000830f4240808080a004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829c0c0
Now that this is settled, we can focus on performing actions on the block. The only method to execute anything in a blockchain framework is to create and execute a transaction. Here, we require multiple transactions: the initial one to establish the contract, followed by subsequent ones to actively use it. Here’s how to set up the contract:
unsignedtx=pyethtool mkcontract 0 0 $code
echo $unsignedtx
f83c8085e8d4a510008227108080af6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f2
tx=pyethtool sign $unsignedtx $key
echo $tx
f87f8085e8d4a510008227108080af6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f21ca04565b5a48b29ef623ad2caffe0917a3fc6a6f1b50f1df06876f3caa6fb4957c6a0123c928257c1f248fb3d362c125a0aea091ab08467efb52f8c3676ca73d727bf
Alternatively, the simpler approach:
tx=pyethtool mkcontract 0 0 $code | pyethtool -s sign $key
echo $tx
f87f8085e8d4a510008227108080af6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f21ca04565b5a48b29ef623ad2caffe0917a3fc6a6f1b50f1df06876f3caa6fb4957c6a0123c928257c1f248fb3d362c125a0aea091ab08467efb52f8c3676ca73d727bf
The initial segment in mkcontract is a nonce, which must correspond to the tally of transactions already dispatched from that account. This nonce requirement is intended to avert replay assaults; without it, if one sent Bob 200 ether, he could merely replay that transaction repetitively until the funds deplete. However, with the nonce in place, the transaction may only succeed once. The subsequent field denotes the ether amount to dispatch (in the context of contract creation, the ether amount to initially allocate to the contract), while the final field represents the code. It is important to notice that the Transaction.contractfunction call also includes two additional fields amid value and recipient: gasprice and startgas. Pyethtool helps by initializing these parameters to 1 szabo (i.e., 10^12 wei or one millionth of an ether) for each gas and 10,000 gas, respectively. This provides a theoretical upper limit of 10,000 computational steps for the code to execute, though in practice, it may deplete after 1,000 if numerous costly operations are employed. Lastly, upon generating the transaction, it must be signed with your private key.
Once that task is completed, we simply:
pyethtool applytx tx
{“result”: “da7ce79725418f4f6e13bf5f520c89cec5f6a974”, “block”: “f9017ef8d0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a00bcec36bf7ffc27418b1746986574526efeb09b34f733039749f291f778d4aaca03575f60ad6c929d7c98a50a12ff1ef9b07ecf3182e74962872064648a66f3da0834000008087038d7ea4c68000830f42408204b08080a004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829f8a9f8a7b881f87f8085e8d4a510008227108080af6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f21ca04565b5a48b29ef623ad2caffe0917a3fc6a6f1b50f1df06876f3caa6fb4957c6a0123c928257c1f248fb3d362c125a0aea091ab08467efb52f8c3676ca73d727bfa00bcec36bf7ffc27418b1746986574526efeb09b34f733039749f291f778d4aac8204b0c0”}
This provides you with two outputs. The first is the contract’s address, while the second represents the new block data. Be mindful that the block data does not encompass the complete block; additional state data resides in the statedb directory. Therefore, attempting to deserialize the block on a new machine may not succeed. From the values returned, assign the first output to contract and the second to med for future reference. Following that, we need to devise a transaction to utilize this contract. Let’s say we wish to register “george” with 45. However, to accomplish this, we are required to complete another tedious task: package.up the information. Luckily, the Serpent compiler provides a tool for accomplishing just that:
data=echo ‘[“george”,45]’ | serpent -j encode_datalist
echo $data
000000000000000000000000000000000000000000000000000067656f726765000000000000000000000000000000000000000000000000000000000000002d
The namecoin agreement accepts data in two segments: the key and the value, allowing us to place them into a JSON array and employ Serpent to encode it. The encoder can handle both strings and numbers as the distinct elements within the array. It’s important to note that unfortunately, Python’s JSON decoder mandates double quotes for internal strings; “[‘george’,45]” would not function correctly.
Now, we execute the following:
tx2=pyethtool mktx 1 $contract 0 $data | pyethtool -s sign $key
echo $tx2
f8a50185e8d4a5100082271094da7ce79725418f4f6e13bf5f520c89cec5f6a97480b840000000000000000000000000000000000000000000000000000067656f726765000000000000000000000000000000000000000000000000000000000000002d1ba064363844c718f0f38907d39508adb2c2b9134e52e7d436fb20965044c01f41c2a0e1123d26cf810c4ef9d397974e2fc336d16e452d71df3c3d7245b40ed12c603b
Additionally:
pyethtool applytx tx2
{“result”: “0000000000000000000000000000000000000000000000000000000000000001”, “block”: “f9024ef8d0a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a066d2524d921fadb5056983cf4bb215d339cdaeb7048b8913bfdf8fe867eb5682a0d669d3b5cfb150e4ef7f900cc613b0231abc8551544c389ddcd6668f784c4cb3834000008087038d7ea4c68000830f4240820a8f8080a004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829f90178f8a7b881f87f8085e8d4a510008227108080af6025515b525b600a37f260003556601b596020356000355760015b525b54602052f260255860005b525b54602052f21ca04565b5a48b29ef623ad2caffe0917a3fc6a6f1b50f1df06876f3caa6fb4957c6a0123c928257c1f248fb3d362c125a0aea091ab08467efb52f8c3676ca73d727bfa00bcec36bf7ffc27418b1746986574526efeb09b34f733039749f291f778d4aac8204b0f8cdb8a7f8a50185e8d4a5100082271094da7ce79725418f4f6e13bf5f520c89cec5f6a97480b840000000000000000000000000000000000000000000000000000067656f726765000000000000000000000000000000000000000000000000000000000000002d1ba064363844c718f0f38907d39508adb2c2b9134e52e7d436fb20965044c01f41c2a0e1123d26cf810c4ef9d397974e2fc336d16e452d71df3c3d7245b40ed12c603b
Registration completed successfully! The output consists of two values, just like previously: the first value indicates the new block state and the second is the reply from the contract. According to the contract’s definition above, “1” signifies success. Now, to confirm, let’s establish the end to the block hex received from the preceding command and inspect the state:
pyethtool getstate $end
{‘nonce’: ‘x04x99OgxdcUxb0x9ex81Jxb7xffxc8xdf6x86xb4xafxb2xbbSxe6x0exaex97xefx04?xe0?xb8)’, ‘min_gas_price’: 1000000000000000L, ‘extra_data’: ”, ‘state_root’: ‘fxd2RMx92x1fxadxb5x05ix83xcfKxb2x15xd39xcdxaexb7x04x8bx89x13xbfxdfx8fxe8gxebVx82’, ‘difficulty’: 4194304L, ‘timestamp’: 0L, ‘number’: 0L, ‘gas_used’: 2703L, ‘coinbase’: ‘0000000000000000000000000000000000000000’, ‘tx_list_root’: ‘xd6ixd3xb5xcfxb1Pxe4xefx7fx90x0cxc6x13xb0#x1axbcx85QTL8x9dxdcxd6fx8fxLLxb3’, ‘state’: {‘0000000000000000000000000000000000000000’: {‘nonce’: 0L, ‘balance’: 2703000000000000L, ‘storage’: {}, ‘code’: ”}, ‘da7ce79725418f4f6e13bf5f520c89cec5f6a974’: {‘nonce’: 0L, ‘balance’: 0L, ‘storage’: {113685359126373L: 45L}, ‘code’: ‘60003556601b596020356000355760015b525b54602052f260255860005b525b54602052f2’}, ‘cd2a3d9f938e13cd947ec05abc7fe734df8dd826’: {‘nonce’: 2L, ‘balance’: 997297000000000000L, ‘storage’: {}, ‘code’: ”}}, ‘uncles_hash’: ‘x1dxccMxe8xdexc7]zxabx85xb5gxb6xccxd4x1axd3x12Ex1bx94x8atx13xf0xa1Bxfd@xd4x93G’, ‘prevhash’: ‘x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00’, ‘gas_limit’: 1000000L}
You can observe the contract account near the start of the state outline, with “george” assigned to 45 as anticipated. We have completed the task! As an exercise, attempt crafting two additional transactions; one registering “george” to 60 and another registering “harry” to 80. If you apply them all in the correct order following these two, the transaction registering “george” to 60 should yield 0, while the one registering “harry” to 80 should be successful.
Executing it in Python
This is pyethtool, the command-line tool. Now, how would it function using pyethereum itself? As it turns out, it’s quite straightforward. Here’s the session:
>>> import serpent
>>> from pyethereum import transactions, blocks, processblock, utils
>>> code = serpent.compile(open(‘namecoin.se’).read())
>>> key = utils.sha3(‘cow’)
>>> addr = utils.privtoaddr(key)
>>> genesis = blocks.genesis({ addr: 10**18 })
>>> tx1 = transactions.contract(0,10**12,10000,0,code).sign(key)
>>> result, contract = processblock.apply_tx(genesis,tx1)
>>> tx2 = transactions.Transaction(1,10**12,10000,contract,0,serpent.encode_datalist([‘george’,45])).sign(key)
>>> result, ans = processblock.apply_tx(genesis,tx2)
>>> serpent.decode_datalist(ans)
[1]
>>> genesis.to_dict()
‘nonce’: ‘x04x99OgxdcUxb0x9ex81Jxb7xffxc8xdf6x86xb4xafxb2xbbSxe6x0exaex97xefx04?xe0?xb8)’, ‘min_gas_price’: 1000000000000000L, ‘extra_data’: ”, ‘state_root’: ”, ‘difficulty’: 4194304, ‘timestamp’: 0, ‘number’: 0, ‘gas_used’: 2712L, ‘coinbase’: ‘0000000000000000000000000000000000000000’, ‘tx_list_root’: ‘x17x90x87x966xbdb!x14|Rxb0& xb04x90xb9bsx12x85x90xdaBxedx83n*x8eEx8e’, ‘state’: {‘0000000000000000000000000000000000000000’: {‘nonce’: 0L, ‘balance’: 2712000000000000L, ‘storage’: {}, ‘code’: ”}, ‘da7ce79725418f4f6e13bf5f520c89cec5f6a974’: {‘nonce’: 0L, ‘balance’: 0L, ‘storage’: {113685359126373L: 45L}, ‘code’: ‘60003556601e596020356000355760015b525b54602052f260285860005b525b54602052f2’}, ‘cd2a3d9f938e13cd947ec05abc7fe734df8dd826’: {‘nonce’: 2L, ‘balance’: 997288000000000000L, ‘storage’: {}, ‘code’: ”}}, ‘uncles_hash’: ‘x1dxccMxe8xdexc7]zxabx85xb5gxb6xccxd4x1axd3x12Ex1bx94x8atx13xf0xa1Bxfd@xd4x93G’, ‘prevhash’: ‘x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00’, ‘gas_limit’: 1000000}
>>> genesis.get_balance(addr)
997288000000000000L
>>> genesis.get_storage_data(contract,’george’)
45L
Another crucial command is processblock.debug = 1; this initiates step-by-step printing of code execution, assisting you in identifying errors in your contract code – or within my pyethereum VM or Serpent implementation!
Diving into the Code
So that concludes your primer on utilizing pyethereum. Now, let’s delve into the most enjoyable aspect, crafting contracts. For enhanced readability, let’s present the Namecoin contract again:
if !contract.storage[msg.data[0]]:
contract.storage[msg.data[0]] = msg.data[1]
return(1)
else:
return(0)
What is the purpose of this contract? Essentially, it adopts a name registration database, simply employing that as the exclusive function for the contract’s long-term storage. Theoretically, contract code has three locations for data placement: stack, memory, and storage. Among these, stack and memory are utilized implicitly in Serpent to facilitate arithmetic and variable handling; however, long-term storage is the sole option that endures after execution concludes. In this scenario, when you register “george” with 45, the contract first verifies if contract.storage[“george”] is non-zero, i.e., it is zero. If so, it assigns that storage index the provided value, 45, before returning 1. If it is not, it returns zero. Be aware that this contract does not facilitate access by other contracts; it is primarily usable by external applications. More sophisticated name registries would provide an API for contracts to retrieve data corresponding to a name as well.
Now, let’s proceed to a more complex example:
init:
contract.storage[0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826] = 1000000
code:
if msg.datasize == 1:
addr = msg.data[0]
return(contract.storage[addr])
else:
from = msg.sender
fromvalue = contract.storage[from]
to = msg.data[0]
value = msg.data[1]
if fromvalue >= value:
contract.storage[from] = fromvalue – value
contract.storage[to] = contract.storage[to] + value
return(1)
else:
return(0)
This constitutes the “currency contract”, or specifically a refined version of it that includes return values for simpler debugging. This contract is intriguing for several reasons. Firstly, it contains an initialization procedure, which is invoked when the contract is created. This establishes an account with 1000000 currency units allotted to that account.
Subsequently, there are two pathways in the code. Initially, incoming messages might carry only one data field. In such a case, these messages are interpreted as balance inquiries, simply returning the balance of the specified address. It is noteworthy that msg.data[0] supplies the integer occupying bytes 0…31 of the transaction data, msg.data[1] provides the integer occupying bytes 32…63, and so forth. This convenience was introduced in Serpent; the foundational transaction data is formatted entirely in bytes. Incidentally, this necessity for Serpent’s encode_datalist function to generate transaction data hence arises.
In contrast, incoming messages might comprise two data fields. In that instance, the messages are regarded as requests to transfer to that address. The sender is inferred from the origin of the message, with the recipient and the value derived from the first two fields (i.e., the initial 64 bytes) in msg.data. If there are sufficient funds to execute the transfer, the money is transferred, returning 1; otherwise, it returns 0.
Challenge: devise a currency contract that deducts a fee, denominated in its internal currency, from each transaction, while refunding a small amount of ether to anyone executing a successful transaction, thus alleviating the need for individuals (or contracts) operating in this currency to maintain simultaneous currency and ether balances. This contract would also encompass a third transaction type, potentially taking zero arguments, via which an individual can acquire internal currency units from the contract by sending it ether. The contract should monitor two variables: its own balance in currency and its ether balance, dynamically adjusting the transaction fee and exchange rate to maintain both balances in – well, in an approximate equilibrium.
Contracts Invoking Other Contracts
This is a proprietary data feed contract:
owner = 0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826
if msg.sender == owner and msg.datasize == 2:
contract.storage[msg.data[0]] = msg.data[1]
return(1)
else:
return(contract.storage[msg.data[0]])
This contract is crafted to function as a key/value pair editable solely by its owner while permitting anyone to inquire its contents; the aim is for the owner to utilize various storage indices to document fluctuating data such as the USD price of ether. There are two primary “clauses” in this contract, one for altering storage initiated when a key and value are supplied, and the message is sent by the contract’s owner, alongside another for merely reading storage. The msg.datasize variable signifies the number of 32-byte data fields present in the message data. There are no particularly new features here; this contract remains quite straightforward, and I encourage you to first follow the logic to ensure understanding before experimenting with the contract, initiating it within a block, and subsequently submitting set and query transactions.
However, the intriguing segment unfolds when we utilize this contract within another contract. Introducing this intricate creation, a hedging contract:
if !contract.storage[1000]:
contract.storage[1000] = msg.sender
contract.storage[1002]“`python
= msg.value
contract.storage[1003] = msg.data[0]
contract.storage[1004] = msg.data[1]
return(1)
elif !contract.storage[1001]:
ethvalue = contract.storage[1002]
if msg.value >= ethvalue:
contract.storage[1001] = msg.sender
datasource = contract.storage[1003]
dataindex = contract.storage[1004]
othervalue = ethvalue * msg(datasource,0,tx.gas-100,[dataindex],1)
contract.storage[1005] = othervalue
contract.storage[1006] = block.timestamp + 86400
return([2,othervalue],2)
else:
datasource = contract.storage[1003]
dataindex = contract.storage[1004]
othervalue = contract.storage[1005]
ethvalue = othervalue / msg(dataindex,0,tx.gas-100,[datasource],1)
if ethvalue >= contract.balance:
send(contract.storage[1000],contract.balance,tx.gas-100)
return(3)
elif block.timestamp > contract.storage[1006]:
send(contract.storage[1001],contract.balance – ethvalue,tx.gas-100)
send(contract.storage[1000],ethvalue,tx.gas-100)
return(4)
else:
return(5)
This contract is extensive because it’s structured to be more test-friendly; an efficient implementation is about half its size. The operation of the contract is as follows:
-
Party A inputs X ether along with a data feed contract D and a currency code C as data elements, which are recorded at contract storage index 1000. X, D, and C are documented in storage indices 1002, 1003, and 1004. For instance, if the currency code denotes USD.
-
Party B submits X ether, registering at contract storage index 1001. The contract subsequently invokes D with data C to ascertain the price of ether in the specified currency, applying this to calculate V, the value in USD contributed by each participant. V is allocated at index 1005, along with a due time set for 24 hours ahead stored at index 1006.
-
Perhaps, the price of ether in USD declines by more than 50%. If this occurs, then there isn’t enough ether in the contract overall to satisfy V USD. To avert this, the moment the price drops below the 50% threshold, anyone (typically A) can initiate the contract to retrieve all 2X ether into A’s address, effectively allowing A to recover nearly the entire amount measured in USD that A invested, leaving B with nothing. If this transpires, the contract returns 3.
-
Similarly, after a day has passed, anyone may transmit a transaction to “ping” the contract, triggering it to send V USD’s worth of ether to A and the remaining ether to B, which results in a return of 4.
-
In the absence of a “margin call” or “expiry” event, a ping to the contract produces no effect and returns 5.
The objective of the hedging contract is that A gains by consistently receiving the same amount of USD that he invested, whereas B profits if he anticipates that the value of ether will increase, considering that a 10% increment in the ether price will, under these conditions, yield him a 20% return. USD can certainly be replaced with various alternatives, such as CNY, gold, or the consumer price index.
The notable new features examined here are msg, send, and array literals. Both msg and send serve as methods to transmit messages to other contracts. The syntaxes are:
send(to, value, gas)
out = msg(to, value, gas, datastart, datalength)
msg(to, value, gas, datastart, datalength, outstart, outlength)
Send is more straightforward, presupposing all you need is to transfer funds without any additional complexities involved. The latter two represent equivalent methods of transmitting a message to another contract, differing solely in their handling of the output: the first restricts output to 32 bytes and directly assigns it to a variable, while the second accepts two parameters for the memory location where the output should be stored. The “output” of a message remains empty if the recipient is either nonexistent, an externally owned account, or does not specifically indicate a return value; when a return value is specified, it corresponds to that value (where “value” signifies an arbitrary-length byte array, not a 32-byte number). Therefore, both phrases essentially imply the same concept:
d = array(3)
d[0] = 5
d[1] = 10
d[2] = 15
x = msg(A, B, C, d, 3)
And:
d = array(3)
d[0] = 5
d[1] = 10
d[2] = 15
w = array(1)
msg(A, B, C, d, 3, w, 1)
x = w[0]
In the above contract example, we utilized the data feed contract to deliver the price of ether in USD, directly incorporating it into the equation othervalue = ethvalue * msg(datasource, 0, tx.gas – 100, [dataindex], 1).
Array literals represent another handy convenience feature; the genuinely optimal method to write the preceding code is as follows:
x = msg(A, B, C, [5, 10, 15], 3)
However, it is unfortunate that you still need to specify the array length. Nonetheless, in this instance, the array itself is instantiated and referenced inline, eliminating the need for manual setup. All the magic is executed by the Serpent compiler.
So, that wraps up today’s discussion. What might you consider coding in Serpent? Here are several potential ideas:
-
A contract-driven implementation of JustDice.
-
Some foundational code for a decentralized organization.
-
A board game (e.g., chess, Go)
-
A decentralized exchange, featuring a contract-based order book, between ether and the aforementioned sub-currency contract.
-
Any of the additional examples in our whitepaper
Enjoy, and have a great time! Also, if you discover any bugs in pyethereum or Serpent, please make sure to report them.
See also: list of Serpent language operations
Source link
“`