Close Menu
    Track all markets on TradingView
    Facebook X (Twitter) Instagram
    • Privacy Policy
    • Term And Conditions
    • Disclaimer
    • About us
    • Contact us
    Facebook X (Twitter) Instagram
    WSJ-Crypto
    • Home
    • Bitcoin
    • Ethereum
    • Blockchain
    • Crypto Mining
    • Economy and markets
    WSJ-Crypto
    Home » Unlocking Innovation: A Deep Dive into SchellingCoin and Advanced Contract Programming
    Ethereum

    Unlocking Innovation: A Deep Dive into SchellingCoin and Advanced Contract Programming

    wsjcryptoBy wsjcrypto4 Aprile 2025Nessun commento19 Mins Read
    Share
    Facebook Twitter LinkedIn Pinterest Email

    Developing successful decentralized applications on Ethereum presents both simplicity and complexity. The straightforward aspect is familiar to many: instead of needing to establish your own blockchain, handle intricate database code, manage networking challenges and NAT traversal, or any of the other difficulties that come with building a peer-to-peer application from the ground up, you can craft code using an uncomplicated, high-level programming language such as Serpent or Mutan (or LLL if you prefer to delve into lower-level programming), combining the ease of a basic scripting language with the robustness and security provided by an entire blockchain. A complete implementation of a fundamental name registry can be accomplished in just two lines of code that encapsulate the core logic of the application: if not contract.storage[msg.data[0]]: contract.storage[msg.data[0]] = msg.data[1]. Utilize the first data item in the message as a key and the second as a value; if the key is unoccupied, set it to the desired value. It’s akin to a phone book where you can add entries, but once added, these entries cannot be altered. However, there is also a challenging aspect: decentralized applications are likely to encompass logic that is inherently complex, and no simplifications to the programming environment can remove that reality (although libraries built atop the programming language may mitigate certain specific problems). Moreover, any dapps that aim to perform truly intriguing functions are likely to integrate cryptographic protocols and economics, which we are all aware can be quite complicated.

    This article aims to explore a contract that represents a crucial element of a fully decentralized cryptoeconomic ecosystem: a decentralized oracle. The oracle will be developed employing the SchellingCoin protocol, which is outlined in a previous blog entry. The fundamental concept behind the protocol is that all participants “vote” on a specific value (in this case, we will utilize wei per US cent for illustration, as this will be exceptionally useful in financial contracts), and every participant who casts a vote that lies between the 25th and 75th percentile (i.e., close to the median) receives a reward. The median is regarded as the “true value”. To enhance security, each round is conducted using a two-phase commitment protocol: during the first phase, everyone selects a value P which they will be voting on, and submits H = sha3([msg.sender, P]) to the contract; in the second phase, everyone submits their chosen P, and the contract accepts only those values that correspond with the previously submitted hash. Rewards and evaluations occur at the conclusion.

    The reason this system functions is as follows: during the initial phase, everyone is metaphorically “in the dark”; they are unaware of what others will submit, perhaps only able to see the hashes of differing votes. The sole information they possess is that they must submit the price of a US cent in wei. Therefore, recognizing that the only value other participants’ responses will be inclined toward is the actual wei/US cent, the most rational decision to vote for, in order to optimize the likelihood of being close to the median, is the wei/US cent itself. Consequently, it serves everyone’s best interests to unify their efforts and all offer their best estimate of the wei/US cent price. An intriguing philosophical observation is that this mirrors the functioning of proof-of-work blockchains, except that in that scenario, the votes pertain to the sequence of transactions rather than a specific numerical value, which strongly indicates that this protocol might be applicable for at least certain uses.

    Naturally, various special circumstances and attacks may arise in reality, and the fact that the price of any asset is frequently influenced by a small number of centralized exchanges complicates matters. For instance, one conceivable failure scenario is where there is a market share division between the BTC/USD on Bitstamp, Bitfinex, and MtGox, with MtGox being the most frequented exchange; in such a case, incentives might lead all votes to cluster around the GOX-BTC/USD price specifically. At that stage, it becomes entirely uncertain what would happen if MtGox were to be compromised, causing the price on that exchange alone—and not on the others—to plummet to $100. Ultimately, participants may each follow their personal incentives, culminating in the protocol’s collective downfall. Addressing these situations and assessing their relevance is a matter of empirical investigation; it is challenging to predict real-world outcomes in advance.

    To formalize the protocol, we have the following:

    1. Each set of N blocks (in this case, we set N = 100) constitutes a distinct “epoch”. We define the epoch number as floor(block.number / 100), and denote the block number modulo 100 as the “residual”.
    2. When the residual is less than 50, anyone can submit a transaction with any value V and hash H = sha3([msg.sender, R, P]), where P represents their estimation of the value of 1 US cent in wei (remember, 1 wei = 10-18 ether, and 1 cent = 10-2 USD) and R is a random value.
    3. If the residual exceeds 50, then anyone who submitted a hash can provide their P, and the contract will verify if sha3([msg.sender, P]) corresponds with the hash.
    4. At the conclusion of the epoch (or, more precisely, at the moment of the first “ping” during the subsequent epoch), everyone who submitted a value for P falling between the 25th and 75th percentiles, weighted by deposit, receives their deposit back plus a minor reward; everyone else is returned their deposit less a small penalty, and the median value is deemed the true US cent/wei price. Those who did not submit a valid value for P will receive their deposit back minus a small penalty.

    It’s noteworthy that optimizations for the protocol are feasible; for instance, one might implement a feature enabling anyone with a specific

    P

    value to appropriate the deposit from whomever presented the hash, rendering it impractical to disclose one’s

    P

    to attempt to sway individuals’ votes prior to the residual 50 being reached, followed by the commencement of the subsequent phase. Nevertheless, to prevent this example from becoming overly intricate, we will refrain from doing so; additionally, I am personally doubtful about “compelled private data disclosure” tactics in general, as I anticipate that many will eventually become ineffective with the future emergence of generalized zero-knowledge proofs, fully homomorphic encryption, and obfuscation. For instance, one might conceive of an assailant outsmarting such a scheme by providing a zero-knowledge proof that their

    P

    value lies within a specific 1015 wei-wide interval, granting sufficient data to provide users a target but not enough to feasibly pinpoint the precise value of

    P

    . Considering these apprehensions, and desiring simplicity, the straightforward two-round protocol devoid of unnecessary complications appears most suitable for now.

    Before we commence coding SchellingCoin itself, there exists another contract we must establish: a sorting function. The sole method to derive the median of a number list and ascertain who falls within a specific percentile range is to organize the list, therefore we will require a generalized function to achieve that. For enhanced utility, our sorting function will be made generic: we shall sort pairs rather than integers. Thus, for instance, [30, 1, 90, 2, 70, 3, 50, 4] would transform into [ 30, 1, 50, 4, 70, 3, 90, 2 ]. By employing this function, one can arrange a list comprising any type of object by simply creating an array of pairs, where the first number acts as the key for sorting and the second number serves as a pointer to the object in parent memory or storage. Here’s the code:

    if msg.datasize == 0:
        return([], 0)
    else:
        low = array(msg.datasize)
        lsz = 0
        high = array(msg.datasize)
        hsz = 0
        i = 2
        while i  msg.datasize:
            if```html
     msg.data[i]  msg.data[0]:
                low[lsz] = msg.data[i]
                low[lsz + 1] = msg.data[i + 1]
                lsz += 2
            else:
                high[hsz] = msg.data[i]
                high[hsz + 1] = msg.data[i + 1]
                hsz += 2
            i = i + 2
        low = call(contract.address, low, lsz, lsz)
        high = call(contract.address, high, hsz, hsz)
        o = array(msg.datasize)
        i = 0
        while i  lsz:
            o[i] = low[i]
            i += 1
        o[lsz] = msg.data[0]
        o[lsz + 1] = msg.data[1]
        j = 0
        while j  hsz:
            o[lsz + 2 + j] = high[j]
            j += 1
        return
    ```(o, msg.datasize)
    

    Students of computer science might identify this as a quicksort procedure; the concept is to initially divide the array into two sections, with one segment containing elements less than the initial item and another section containing elements greater than it. Afterwards, we recursively sort the first and second segments (the recursion ultimately halts because the sub-arrays will eventually contain zero or one element, at which point we simply return those elements directly). Finally, we concatenate output = sorted_less_than_list + first item + sorted_greater_than_list and return that collection. Now, integrating this into “quicksort_pairs.se”, let’s construct the code for the actual SchellingCoin. Feel free to visit GitHub to view the complete code; here, we’ll analyze it a few lines at a time.

    To begin with, let’s look at some initialization code:

    init:
        contract.storage[0] = block.number
        contract.storage[3] = create('quicksort_pairs.se')
    
    code:
        HASHES = 2^160
        VALUES = 2^170
    

    The initial code segment assigns the contract storage index 0 to the current block number during initialization, and subsequently generates a quicksort contract, storing it in index 3. It is noteworthy that, in theory, one would generally wish to create the quicksort contract just once and reference it through its address; however, for simplicity and to demonstrate the feature, we are performing an inline creation. In the code, we begin by defining two variables that act as pseudo-constants: HASHES = 2160 serves as the pointer for where we save hashes, and VALUES = 2170 denotes the pointer for where we keep values from the second stage.

    Next, let’s jump to the latter part of the code, as it is more convenient and is the segment that actually executes “first” during the contract’s lifecycle.

    # Hash submission
    if msg.data[0] == 1:
        if block.number % 100  50:
            cur = contract.storage[1]
            pos = HASHES + cur * 3
            contract.storage[pos] = msg.data[1]
            contract.storage[pos + 1] = msg.value
            contract.storage[pos + 2] = msg.sender
            contract.storage[1] = cur + 1
            return(cur)
    # Submission of value
    elif msg.data[0] == 2:
        if sha3([msg.sender, msg.data[3], msg.data[2]], 2) == contract.storage[HASHES + msg.data[1] * 3]:
            contract.storage[VALUES + msg.data[1]] = msg.data[2]
            return(1)
    # Request for balance
    elif msg.data[0] == 3:
        return(contract.balance)
    # Request for value
    else:
        return(contract.storage[2])
    

    The initial significant principle observed here involves utilizing msg.data[0] to denote a “type of message”; messages with a first data item of 1 signify hash submissions, 2 indicate value submissions, 3 correspond to balance requests, and 4 represent inquiries regarding the current UScent/wei price. This serves as a customary interface you are likely to encounter in many contracts. The foremost segment, designated for hash submissions, comes with some complexities, so let’s dissect it methodically. The main aim here is to enable individuals to submit hashes and document those submissions in storage. To achieve this, the contract sequentially stores the data in storage beginning from index 2160. We must keep track of three pieces of information – the actual hash, the amount of the accompanying deposit, and the sender’s address for each hash, which we accomplish. Furthermore, we use storage index 1 to record the number of hashes that have been submitted already. Consequently, if two hashes are recorded, the storage will resemble the following:


    The exact directives within the segment include:

    1. Only proceed if the remainder is below 50.
    2. Assign the variable cur to storage index 1, where we will track the number of hashes already submitted
    3. Assign the variable pos to the storage index for the new hash’s placement
    4. Store the hash (provided as the first data item), the sender’s address, and the value in storage
    5. Update the count of hashes to cur + 1
    6. Return the index of the submitted hash

    Technically, if the only users of SchellingCoin are individuals, step 5 is extraneous;although the index is essential for a subsequent phase, an intelligent client could feasibly just examine the

    cur

    variable right after the transaction, thus eliminating the necessity for the opcodes needed to process the return. Nevertheless, as we anticipate numerous cases in Ethereum involving contracts interacting with other contracts, we will provide the return value as a standard practice for efficient machine interaction.

    The following clause pertains to submitting values. In this instance, we request two data pieces as input: the index where the hash was recorded during the initial step of the protocol (this denotes the return value from the previous clause), and the actual value. Subsequently, we combine the sender and value into a hash, and if the hash corresponds, we store the result in an alternative location within contract storage; a different strategy could involve using a single initial storage location and merely having four slots per hash instead of three. We return 1 upon success, and return nothing for a failure. The third and fourth clauses are just straightforward data inquiries; the third performs a balance verification, while the fourth provides the contract’s present perspective on the price.

    That’s everything for the interface aspect of the contract; however, there remains one section that we still have to address, which is the component that actually consolidates the votes. We will divide that into segments. Initially, we have:

    HASHES = 2^160
    VALUES = 2^170
    if block.number / 100 > contract.storage[0] / 100:
        # Organize all hashes
        N = contract.storage[1]
        o = array(N)
        i = 0
        j = 0
        while i  N:
            if contract.storage[VALUES + i]:
                o[j] = contract.storage[VALUES + i]
                o[j + 1] = i
                j += 2
            i += 1
        values = call(contract.storage[3], o, j, j)
    

    Initially, we utilize storage index 0 to store the most recently accessed epoch, and we verify whether the current epoch surpasses the last accessed epoch. If it does, then this indicates the commencement of a newepoch, so we have to process all the votes and reset the contract for the upcoming epoch. We commence by duplicating the values that have been provided into an array (values that remain unsubmitted, namely zeroes, are excluded from this array). We maintain two ongoing counters, i and j; the counter i traverses all value slots, but the counter j only counts the value slots that contain data. It’s important to note that the array we generate follows the structure [ val1, index1, val2, index2 … ], where index1 etc. represent the indices of the corresponding values in the original values array located in contract storage. Consequently, for instance, the following values would produce the subsequent array:


    Subsequently, we pass that array through the quicksort contract, which organizes the data pairs within the array. After sorting, we arrive at:


    At this point, we possess a sorted compilation of all the values submitted by participants, along with references to where the associated metadata is stored securely. The subsequent segment of the code will manage three tasks concurrently. Initially, it will calculate the total amount deposited; this is vital for determining the median. Secondly, we will create two arrays to denote deposits and their corresponding addresses, and we will expunge that data from the contract. Lastly, we will refund 99.9% of individuals who did not submit a value. In theory, we could implement a 70% refund or a 0% refund, but that might render the contract too hazardous for individuals to invest their life savings in (which is actually our intention in a proof-of-stake-weighted system; the higher the ether contributed by legitimate users, the more difficult it becomes for an attacker to accumulate sufficient resources to execute an attack). Here is the code; feel free to comprehend each line for yourself:

        # Calculate total deposit, refund non-submitters and
        # cleanup
    
        deposits = array(j / 2)
        addresses = array(j / 2)
    
        i = 0
        total_deposit = 0
        while i  j / 2:
            base_index = HASHES + values[i * 2 + 1] * 3
            contract.storage[base_index] = 0
            deposits[i] = contract.storage[base_index + 1]
            contract.storage[base_index + 1```html
    ] = 0
            if contract.storage[VALUES + values[i * 2 + 1]]:
                total_deposit += deposits[i]
            else:
                send(addresses[i], deposits[i] * 999 / 1000)
            i += 1
    

    Now, we arrive at the final segment of the code, which calculates the median and rewards individuals. Based on the guidelines, we are required to reward everyone falling between the 25th and 75th percentiles, while determining the median (i.e., the 50th percentile) as the definitive value. To achieve this, we must first arrange the data; however, with the data now organized, the task simplifies to tracking a continuous total of the “cumulative deposited value of all entries in the list thus far.” If this value lies between 25% and 75% of the overall deposit, we then provide a reward slightly exceeding their contribution; otherwise, a somewhat reduced reward is issued. Below is the code:

        inverse_profit_ratio = total_deposit / (contract.balance / 1000) + 1
        # Rewarding everyone
        i = 0
        running_deposit_sum = 0
        halfway_passed = 0
        while i  j / 2:
            new_deposit_sum = running_deposit_sum + deposits[i]
            if new_deposit_sum > total_deposit / 4 and running_deposit_sum  total_deposit * 3 / 4:
                send(addresses[i], deposits[i] + deposits[i] / inverse_profit_ratio * 3)
            else:
                send(addresses[i], deposits[i] - deposits[i]
    ``` / inverse_profit_ratio)
    
            if not halfway_passed and new_deposit_sum > total_deposit / 2:
                contract.storage[2] = contract.storage[VALUES + i]
                halfway_passed = 1
            contract.storage[VALUES + i] = 0
            running_deposit_sum = new_deposit_sum
            i += 1
        contract.storage[0] = block.number
        contract.storage[1] = 0
    

    Concurrently, you’ll notice that we also reset the values in the contract storage, while updating the epoch and setting the hash count back to zero. The primary value we compute, the “inverse profit ratio”, represents the reciprocal of the “interest rate” you receive on your deposit; if inverse_profit_ratio = 33333, and you contributed 1000000 wei, then you receive 1000090 wei in return if you are near the median and 999970 if you are not (i.e., your anticipated return is 1000030 wei). It’s worth mentioning that although this amount is minimal, it occurs every hundred blocks, making it quite significant. And that summarizes everything. If you wish to experiment, feel free to execute the following Python script:

    import pyethereum
    t = pyethereum.tester
    s = t.state()
    s.mine(123)
    c = s.contract('schellingcoin.se')
    c2 = s.contract('schellinghelper.se')
    vals = [[125, 200], [126, 900], [127, 500], [128, 300],
            [133, 300], [```html
    135, 150], [135, 150]]
    s.send(t.k9, c, 10**15)
    print "Submitting hashes"
    for i, v in enumerate(vals):
        print s.send(t.keys[i], c, v[1], [1] + s.send(t.keys[i], c2, 0, [v[0], 12378971241241]))
    s.mine(50)
    print "Submitting vals"
    for i, v in enumerate(vals):
        if i != 5:
            print s.send(t.keys[i], c, 0, [2, i, v[0], 12378971241241])
        else:
            print s.send(t.keys[i], c, 0, [2, i, 4])
    print "Final check"
    s.mine(50)
    print s.send(t.k9, c, 0, [4])
    

    Prior to executing the script, ensure to populate the ‘schellinghelper.se’ file with return(sha3([msg.sender, msg.data[0], msg.data[1]], 3)); here, we are simply being lazy, utilizing Serpent itself to assist us in constructing the hash; in reality, this operation should certainly be conducted off-chain. If you complete that and execute the script, the final value displayed by the contract ought to yield 127.

    Be aware that this contract, in its current form, is not truly scalable on its own; with over 1000 users, anyone who initiates the first transaction at the beginning of each epoch would have to pay a significant sum.

    “`of gas. The method to resolve this cost-effectively is, naturally, to incentivize the submitter of the transaction and impose a standard fee on every participant to fund the reward. Additionally, the interest rate per epoch is minimal, making it potentially unappealing for users to engage unless they possess a substantial amount of capital; furthermore, the flat fee may exacerbate this issue.

    To enable participation with smaller quantities of ether, the most straightforward solution is to establish a “stake pool” where individuals deposit their ether into a contract for the long haul, and then the pool collectively votes, randomly selecting a participant based on their stake to provide the value to vote for in each epoch. This would alleviate the burden from two transactions per user per epoch to three transactions per pool per epoch (for instance, 1 pool = 1000 users) plus one transaction per user for deposits/withdrawals. It’s important to note that, in contrast to Bitcoin mining pools, this stake pool is entirely decentralized and blockchain-based, posing at most very minor centralization risks. Nonetheless, this serves as a valuable example to illustrate how a single contract or DAO could ultimately foster a whole ecosystem of infrastructure operating on the blockchain with contracts interacting with one another; a specialized SchellingCoin blockchain wouldn’t be able to devise pooling mechanisms retroactively and integrate them so seamlessly.

    In terms of applications, the most pressing one is contracts for difference, and eventually a decentralized cryptographic US dollar; if you’re interested in witnessing an attempt at such a contract, check here, although that code is likely vulnerable to market manipulation schemes (e.g., acquire a very large amount of USD within the system, then purchase USD on the market to shift the price 0.5%, followed by selling the USD within the system for a quick 0.3% gain). The fundamental concept behind the decentralized crypto-dollar is straightforward: maintain a bank with two currencies, USD and ether (or specifically, UScent and wei), with the capacity to hold a positive or negative quantity of dollars, and adjust the interest rate on dollar deposits to keep the contract’s net dollar exposure consistently near zero, thereby avoiding any net obligations in currencies it cannot effectively manage. A more straightforward solution might simply involve having a currency with an expanding supply that modifies its supply function to align with the USD, but this presents a dilemma since there would be no safeguards if the value decreases excessively. However, these types of applications will likely require a considerable amount of time to develop (in crypto terms; quite swiftly in traditional finance terms, of course).



    Source link

    return a list of comma separated tags from this title: Advanced Contract Programming Example: SchellingCoin
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    wsjcrypto

    Related Posts

    Bringing Ethereum Back Together as One Chain

    18 Novembre 2025

    Navigating the Future: Insights from Checkpoint #7 – November 2025

    15 Novembre 2025

    Fusaka Mainnet Launch: A New Era for Ethereum Enthusiasts

    6 Novembre 2025

    Countdown to Devconnect: Your Essential Guide for the Next Two Weeks

    4 Novembre 2025
    Add A Comment

    Comments are closed.

    Top Posts

    Subscribe to Updates

    Get the latest sports news from SportsSite about soccer, football and tennis.

    Top Coins
    # Name Price Changes 24h Market CAPVolumeSupply
    WSJ-Crypto
    Facebook X (Twitter) Instagram Pinterest
    • Privacy Policy
    • Term And Conditions
    • Disclaimer
    • About us
    • Contact us
    ©Copyright 2026 . Designed by WSJ-Crypto

    Type above and press Enter to search. Press Esc to cancel.

    Go to mobile version