Catallax and Enabling Peaceful Financial Violence Against the State

The events of the last couple have been fascinating to watch. I spend a lot of time thinking about how a Catallax based society would approach some of these same issues.  Specifically #DefundThePolice is fundamentally built into the underlying Catallax System. 

Catallax isolates State Accounts in the system in a way that financial violence can be used against the state by the people in a couple of ways.  First of all, State Accounts cannot have any kind of privacy in how funds are used.  The inflows and outflows are public record by default.

In a Catallax based system each government domain has a State Account. They collect taxes via the systematic decay of currency in accounts that elect that domain.  These Domain Accounts can create Agency Accounts for the various agency accounts that their collected taxes fund. The police department would be one of these agency accounts.  Citizens that pay taxes into the Domain Level account get a Democratic Veto right to all agency accounts.  The democratic veto is described as follows in my book Immortality:

VTO. Democratic Veto

... How can the (CTZ), using selective citizenship (SCZ) and the public ledger (PLG) keep the state's power in check?

Power corrupts and the citizen must have tools to regulate out of control power without the use of force.

When a citizen pays taxes they should get a vote in that 'state'. We will do this via the democratic veto.

This veto is a 3 phase vote. Citizens can vote 'abstain', 'deny', 'override' on a state account.

This gives power to small minorities to stop the payment from state accounts until their concerns are addressed or their negative vote is overridden by other citizens.

We also don't want small issues gumming up the general working of the state. As a result we should provide for agency accounts that can be selectively vetoed when particular issues arise in the running of those agencies.

Therefore:

Establish the democratic veto for state accounts and selective veto for agency accounts.

This system allows small groups to have their voice heard and amplified.  Larger groups must be proactive in overriding the veto and while this proactivity certainly hasn’t kept people from being oppressed in the past, it at least puts the burden of action on those that would seek to not meet the needs of the minority.

In a practical application, communities across the US could use the Democratic Veto to freeze the accounts of police departments across the nation and keep those accounts frozen until the departments make the demanded changes.

Catallax could soften the economic impact of pandemic

The Catallax project has been on ice for a while as we wait for the technology to catch up to the vision.  ETH 2.0 and DFINITY currently are pushing forward with scalability advancements and ZK tech will have some interesting things to say about how to deal with the ‘privacy problem.’  As frustrating as it is to wait on these technologies to mature, it is even harder watching the current spread of Covid-19 and the associated recession knowing that a world with Catallax would have significantly more economic tools to help weather the storm.  I’ll rip through a few of them, but if you want to know more you can check out http://catallax.info or read my book on the subject here https://amzn.to/39894up.

Cash Decays

In a Catallax based economy cash decays overtime backward through the blockchain.  This means that if you hold cash, it eventually is returned to the people that paid it to you.  Now this happens slowly and it is very likely that you will have spent the cash before that happens.  In scenarios like this economic trumpdown the governing system can print a lot of cash and ramp up the decay rate so that it is available to get the economy ginning again, but also decays back out of the economy quickly so that inflation is avoided.

Cash Decays to you

The backflow of cash in a Catallax economy flows to the people who have spent money in proportion to how that money is used to build more value in the economy. As you spend more money over time you build up an earned basic income.  The amount of your basic income payment depends on how you’ve spent your money. If you’ve spent it with sustainable and profitable businesses your income will be higher than if you spend it with companies that fail to build sustainability.  Math dictates that this basic income will likely not come close to compensating for your entire income, but it is enough to help people make it through times like these with reduced employment.

Grassroots agencies

A portion of decay goes to support government agencies that are selected by the participants in a Catallax economy.  In times like this groups can coordinate to fund new agencies with their tax dollars and cash starts flowing to those agences immediately.

Holding Government Accountable

In a Catallax economy, the people have the ability to shut off the account access of government agencies in order to pressure those agencies to act.  Government inaction can lead to swift organization by those that participate in the system and pay taxes to those government agencies.

Conclusion

It is never fun to have to think about how to react to these things while in the midst of the emergency.  Previously I dreamed up Harveycoin (http://catallax.info/news/2017/9/8/devlog-10-harveycoin-decentralized-disaster-relief) when it was the only thing I could do when I was evacuated from my home after the hurricane that hit Houston.  Hopefully these ideas will inspire others that are currently social distancing and who have the time and ability to code these things in the new and scalable tech that is emerging.  Please reach out if you’d like to talk more about these things or if you’d like to try to come up with some solutions.

DevLog 15 - State minimized implementation on current evm

Cross posted from https://ethresear.ch/t/state-minimized-implementation-on-current-evm/1255

In an effort to implement the functionality described in the post https://ethresear.ch/t/state-minimised-executions/748/26 , I've worked up the following contract for a 'virtual token' that allows for the holding of state in a  Double-batched Merkle log accumulator  as proposed by @JustinDrake.

This is a toy implementation to show what I mean by 'virtual functions'. The idea being that users would call the Transfer() function to emit an event that indicates that they want to transfer.  The Collators respond to that call bo collecting witnesses from the provided dataHash(perhaps via IPFS) and using the vTransfer() function to calculate the logs.

My original thought was to have the virtual function emit logs as it was run in an off chain evm, but with current tooling those logs are discarded or ignored so instead accumulate the new logs in the results bytes.  This makes the code messier, but it generally works.

pragma solidity ^0.4.18;

import "./BytesLib.sol";

contract VirtualToken {

address public owner;
uint256 public totalSupply;

event NewBranch(bytes32 indexed addressFrom, bytes32 amountFrom, bytes32 indexed addressTo, bytes32 amountTo, bytes32 indexed parent);
event SwapLeaf(bytes32 indexed oldLeaf, bytes32 indexed newLeaf);

function VirtualToken() public{
    owner = msg.sender;
    totalSupply = 1000000 * 10**18;
    DataLog(keccak256(address(this), "balance", msg.sender),1,0, bytes32(totalSupply));
}

function getKeyProof(bytes32 key, bytes data) pure returns(bytes32[] result){
    result = new bytes32[](8);
    uint bytePosition = 0;
    while(bytePosition <= data.length){
        uint length = uint256(BytesLib.toBytes32(BytesLib.slice(data, bytePosition, 32)));
        bytes32 thisKey = BytesLib.toBytes32(BytesLib.slice(data, bytePosition + 32, 32));
        if(thisKey == key){
            for(uint thisGroup = 1; thisGroup < length; thisGroup++){
                bytes32 aGroup = BytesLib.toBytes32(BytesLib.slice(data,bytePosition + (32 * thisGroup), 32));

                result[thisGroup - 1] = aGroup;
            }
            return ;
        }
        bytePosition = bytePosition + (32 * length);
    }
}

event DataLog(bytes32 path, uint logType, uint nonce, bytes32 value);

bytes32[8192] public bottomLayer;
uint bottomLayerPosition;
bytes32[] public topLayer;

function pushLog(uint logType, uint nonce, bytes32 value, bytes32[] proof, bytes startBytes) internal returns(bytes result) {
  result = startBytes;
  result = BytesLib.concat(result, BytesLib.fromBytes32(proof[0]));
  result = BytesLib.concat(result, BytesLib.fromBytes32(bytes32(logType)));
  result = BytesLib.concat(result, BytesLib.fromBytes32(bytes32(nonce)));
  result = BytesLib.concat(result, BytesLib.fromBytes32(value));
  //DataLog(proof[0], logType, uint(proof[2]) + 1, value);
}

function pushDel(bytes32[] proof, bytes startBytes) internal returns(bytes result){
    result = startBytes;
    result = pushLog(2, uint(proof[2]), proof[3], proof, result);
}

function pushAdd(bytes32 newValue, bytes32[] proof, bytes startBytes) internal returns(bytes result){
    result = startBytes;
    result = pushLog(1, uint(proof[2]) + 1, newValue, proof, result);
}

function publishCollation(bytes32 newBottomCollation, bytes32 newTopCollation) public {
    if(newTopCollation == 0x0){
        bottomLayer[bottomLayerPosition] = newBottomCollation;
        bottomLayerPosition++;
    } else {
        topLayer.push(newTopCollation);
        bottomLayerPosition = 0;
    }

}


function vTransfer(bytes data) view returns(bytes results){

    address sender = address(getKeyProof(keccak256("msg.sender"), data)[1]);
    bytes32[] memory senderProof = getKeyProof(keccak256(address(this), "balance", sender), data);
    require(verifyProof(keccak256(address(this), "balance", sender), senderProof));
    uint senderBalance =  uint(senderProof[3]);

    address destination = address(getKeyProof(keccak256("destination"), data)[1]);
    bytes32[] memory destinationProof = getKeyProof(keccak256(address(this),"balance", destination), data);
    require(verifyProof(keccak256(address(this), "balance", destination), destinationProof));
    uint destinationBalance = uint(destinationProof[3]);

    uint amount = uint(getKeyProof(keccak256("amount"), data)[1]);

    require(senderBalance >= amount);

    //invalidate existing proofs
    //todo: what if an item goes to 0

    results = pushDel(senderProof, results);
    if (destinationBalance > 0) {
     results = pushDel(destinationProof, results);
    }

    //publish new proofs
    destinationBalance = destinationBalance + amount;
    senderBalance = senderBalance - amount;

    if(senderBalance > 0){
        results = pushAdd(bytes32(senderBalance), senderProof, results);
    }

    if(destinationBalance > 0){
        results = pushAdd(bytes32(destinationBalance), destinationProof, results);
    }

    return results;

}

/* things that need to be in the log
    inputDataHash: -> maybe put everything but signature here
        sender:
        gasPrice:
        maxGas:
        timeOut:
        contract:
        function:
        data:
        value:
        nonce:
    signatureInputDataHash: -> to ecrecover sender

    //value will need to be stored in escrow until the op can be proven to have run and a reciept generated

    //structure of data passed to a function

    [length][variableName][loghash][value][map][map][map][map][proof]...[proof]

    [length][path][nonce][type][value][proff]...[proof]


*/

event Transfer(bytes32 dataHash, bytes signature);

function transfer(bytes32 dataHash, bytes sig) public{
    Transfer(dataHash, sig);
}

 //utility function that can verify merkel proofs
//todo: can be optimized
//todo: move to library
function calcRoot(bytes32 path,  bytes32[] proof) constant public returns(bytes32 lastHash, uint logType, uint nonce, bytes32 proofPath, bytes32 value){
   for(uint thisProof = 0; thisProof < proof.length; thisProof++){
    if(thisProof == 0){
       //path
       require(path == proof[thisProof]);
       proofPath = path;
     } else if(thisProof == 2){
         nonce = uint(proof[thisProof]);
     } else if(thisProof == 1){
         //type
         logType = uint(proof[thisProof]);
         if(logType == 3){
             //null
             return;
         }
     } else if(thisProof == 3){
       value = proof[thisProof];
       lastHash = keccak256(path,logType, nonce, value);
     } else if(proof[thisProof] == 0x0){
        return;
     } else{
       if(proof[thisProof] == lastHash){
        if(proof[thisProof + 1] != 0x0) {
          lastHash = keccak256(lastHash, proof[thisProof + 1]);
        } else {
          lastHash = keccak256(lastHash);
        }

         thisProof++;
       } else {
         require(proof[thisProof + 1] == lastHash);
         lastHash = keccak256(proof[thisProof], lastHash);
         thisProof++;
       }
     }
    }
    return;
}

//utility function that can verify merkel proofs
//todo: can be optimized
//todo: move to library
function verifyProof(bytes32 path,  bytes32[] proof) constant public returns(bool){
   bytes32 lastHash;
   bytes32 emptyBytes;
   bytes32 value;
   uint nonce;
   uint logType;

   (lastHash, logType, nonce, path,  value) = calcRoot(path, proof);

   if(nonce == 3){
       return true;
   }

   for(uint thisLayer; thisLayer < bottomLayer.length; thisLayer++){
       if(bottomLayer[thisLayer] == lastHash){
           return true;
       }
   }

   for(thisLayer = 0; thisLayer < topLayer.length; thisLayer++){
       if(topLayer[thisLayer] == lastHash){
           return true;
       }
   }
   return false;
 }



}

   

The following code builds a little tree generator that helps manage the state of a tree and to produce Merkle proofs.  These proofs can probably be streamlined as I'm including derived hashes in the proofs for simplicity's sake.  Although since we are doing these virtually the size of the proofs only affects the bandwidth for collators, and the proofs aren't that big.

class DataLogTree
  constructor: ()->
    @web3Utils = require('web3-utils')
    @root = null
    @layers = []
    @layers.push([])
  addItem: (logType, nonce, path, value)=>
    @layers[0].push [logType, nonce, path, value]
  getVar: (key, value)=>
    map = []
    map.push(@web3Utils.padLeft(@web3Utils.toHex(3),64))
    map.push(key)
    map.push(value)
    return map
  getNullProof: (key)=>
    map = []
    map.push(@web3Utils.padLeft(5,64))
    map.push key
    map.push(@web3Utils.padLeft(@web3Utils.toHex(3),64))
    map.push(@web3Utils.padLeft(@web3Utils.toHex(0),64))
    map.push(@web3Utils.padLeft(@web3Utils.toHex(0),64))
    return map
  proofBytes: (items)=>
    bytes = "0x"
    items.map (item)=>

      item.map (subItem)=>
        bytes = bytes + subItem.slice(2)
        return
      return
    return bytes
  proofBytesArray: (myBytes)=>
    @web3Utils.hexToBytes(myBytes)
  parseLogs: (logsBytes)=>
    logsBytes = logsBytes.slice(2)
    position = 0
    logs = []
    while position < logsBytes.length
      logs.push [
        "0x" + logsBytes.substring(position,position + 64)
        "0x" + logsBytes.substring(position + 64,position + 128)
        "0x" + logsBytes.substring(position + 128,position + 192)
        "0x" + logsBytes.substring(position + 192,position + 256)
      ]
      position = position + 256
    return logs
  getProof: (type, nonce, path)=>
    map = []
    seek = null
    console.log type
    console.log nonce
    console.log path
    # 'looking for ' + key
    # to produce a proof we look through each layer from bottom to top looking for first the
    # passed in key and then the hash combination
    for thisLayer in [0...@layers.length]
      console.log 'seeking layer '+ thisLayer
      for thisItem in [0...@layers[thisLayer].length]
        console.log 'inspecting:' + thisItem
        console.log @layers[thisLayer][thisItem]
        if thisLayer is 0
          console.log 'in 0'
          if @layers[thisLayer][thisItem][0] is path and @layers[thisLayer][thisItem][1] is type and @layers[thisLayer][thisItem][2] is nonce
            console.log 'found 0'
            map.push @layers[thisLayer][thisItem][0]
            map.push @layers[thisLayer][thisItem][1]
            map.push @layers[thisLayer][thisItem][2]
            map.push @layers[thisLayer][thisItem][3]
            console.log map
            seek = @hasher map[0], map[1], map[2], map[3]
            console.log 'new seek is ' + seek
            break
        else
          # The found item will be either on the left or right hand side
          if @layers[thisLayer][thisItem][0] is seek
            # console.log 'found seek in position 0'
            # push the item onto the proof and find the next item
            map.push seek
            if @layers[thisLayer][thisItem][1]?
              map.push @layers[thisLayer][thisItem][1]
              seek = @hasher @layers[thisLayer][thisItem][0], @layers[thisLayer][thisItem][1]
            else
              map.push @web3Utils.padLeft(0,64)
              seek = @hasher @layers[thisLayer][thisItem][0]
            console.log 'new seek is ' + seek
            console.log map
            break
          if @layers[thisLayer][thisItem][1] is seek
            #console.log 'found seek in position 1'
            # push the item onto the proof and find the next item
            map.push @layers[thisLayer][thisItem][0]
            map.push seek
            seek = @hasher @layers[thisLayer][thisItem][0], @layers[thisLayer][thisItem][1]
            console.log 'new seek is ' + seek
            console.log map
            break
          if thisItem is @layers[thisLayer].length
            throw 'seek not found'
    if seek is @root
      map.unshift(@web3Utils.padLeft(@web3Utils.toHex(map.length + 1),64))
      return map
    else
      throw 'root not found'
  hasher:(val1, val2, val3, val4) =>
    if val4?
      hash = @web3Utils.soliditySha3({t:"bytes",v:val1},{t:"bytes",v:val2},{t:"bytes",v:val3},{t:"bytes",v:val4})
    else if val2?
      hash = @web3Utils.soliditySha3({t:"bytes",v:val1},{t:"bytes",v:val2})
    else
      hash = @web3Utils.soliditySha3({t:"bytes",v:val1})
    return hash
  buildTree: ()=>
    if @layers[1]?.length > 0
      @layers = [@layers[0]]
    console.log @layers[0].length
    pair = []
    currentLayer = 0
    console.log 'currentLayer:' + currentLayer
    console.log 'currentLayer Length:' + @layers[currentLayer].length

    if @layers[currentLayer].length is 1
      console.log @layers[currentLayer]
      hash = @hasher @layers[currentLayer][0][0], @layers[currentLayer][0][1], @layers[currentLayer][0][2], @layers[currentLayer][0][3]
      @root = hash
      console.log @root
      return

    while @layers[currentLayer]? and @layers[currentLayer].length > 1
      console.log 'in layer loop'
      console.log currentLayer
      console.log @layers[currentLayer]
      console.log 'end'

      @layers.push []
      console.log @layers
      #console.log @layers[currentLayer]

      for thisItem in @layers[currentLayer]
        console.log thisItem
        #console.log 'odd item' if thisItem.length != 2

        if currentLayer is 0
          console.log 'building 0 layer'
          hash = @hasher thisItem[0], thisItem[1], thisItem[2], thisItem[3]
          console.log hash
        else
          console.log 'building layer ' + currentLayer
          if thisItem[1]?
            hash = @hasher thisItem[0], thisItem[1]
          else
            hash = @hasher thisItem[0]

        #console.log hash
        pair.push hash
        console.log 'update pair'
        console.log pair.length

        if pair.length is 2
          console.log 'pushing hash'
          @layers[currentLayer + 1].push [pair[0],pair[1]]
          pair = []

      if pair.length is 1
        console.log 'pushing leftover hash'
        @layers[currentLayer + 1].push [pair[0]]
        pair = []
      console.log 'advancing layer'
      currentLayer = currentLayer + 1
      if currentLayer > 16
        throw new Error('yo')
    console.log 'done'
    console.log @layers

    @root = @hasher @layers[@layers.length - 1][0][0], @layers[@layers.length - 1][0][1]
    console.log @root


exports.DataLogTree = DataLogTree

    

Here is a truffle scenario that runs three transactions

console.log 'hello'
web3Utils = require('web3-utils')
VirtualToken =  artifacts.require('./VirtualToken.sol')
DataLogTree = require('../src/DataLogTree.js')



contract 'VirtualToken', (paccount)->
  owner = paccount[0]
  firstPayee = paccount[1]
  secondPayee = paccount[2]

  setUpNetwork = (options)=>
    return new Promise (resolve, reject)=>
      results = {}
      console.log 'creating virtual token'
      tree = new DataLogTree.DataLogTree()
      web3.eth.getBlockNumber (err, result)=>
        startBlock = result
        console.log startBlock
        token = await VirtualToken.new(from: owner)
        resolve
          token: token
          startBlock: startBlock
          tree: tree

  it "can set crete token", ->
    network = await setUpNetwork()
    logs = await new Promise (resolve, reject)=>
      network.token.DataLog({},{fromBlock: network.startBlock,toBlock:'latest'}).get (err, foundLogs)=>
        resolve foundLogs



    console.log logs

    genesisLog = null
    logs.map (o)->
      console.log o
      if o.event is 'DataLog'
        genesisLog = o
        #console.log [o.args.logType]#, web3Utils.padLeft(web3Utils.toHex(o.nonce),64), o.path, o.value]
        network.tree.addItem(o.args.path, web3Utils.padLeft(web3Utils.toHex(o.args.logType),64), web3Utils.padLeft(web3Utils.toHex(o.args.nonce),64), o.args.value)
        #console.log o.args

    console.log 'building tree'
    network.tree.buildTree()

    console.log network.tree.root

    console.log 'getting proof'
    proof = network.tree.getProof(web3Utils.padLeft(web3Utils.toHex(genesisLog.args.logType),64), web3Utils.padLeft(web3Utils.toHex(genesisLog.args.nonce),64), genesisLog.args.path)
    console.log proof

    expectedRoot = web3Utils.soliditySha3(proof[1],proof[2],proof[3],proof[4])

    assert.equal expectedRoot, network.tree.root

    txn = await network.token.publishCollation(expectedRoot, "0x0")

    transactionBytes = []
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("msg.sender"), web3Utils.padLeft(owner, 64))
    transactionBytes.push proof
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("amount"), web3Utils.padLeft(web3Utils.toHex(1000), 64))
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("destination"), web3Utils.padLeft(firstPayee,64))
    transactionBytes.push network.tree.getNullProof(web3Utils.soliditySha3(network.token.address,"balance", firstPayee))

    console.log transactionBytes
    myBytes = network.tree.proofBytes(transactionBytes)

    console.log myBytes

    console.log '["' + network.tree.proofBytesArray(myBytes).join('","') + '"]'

    txn = await network.token.vTransfer.call(myBytes)

    console.log ' trying second transaction ********'

    logs = network.tree.parseLogs txn

    console.log logs

    state1Tree = new DataLogTree.DataLogTree()


    for thisItem in logs
      state1Tree.addItem(thisItem[0], thisItem[1], thisItem[2], thisItem[3])

    console.log 'building state1Tree'

    state1Tree.buildTree()

    txn = await network.token.publishCollation(state1Tree.root, "0x0")

    console.log 'getting proof'
    proof = state1Tree.getProof(web3Utils.padLeft(web3Utils.toHex(1),64), web3Utils.padLeft(web3Utils.toHex(1),64), web3Utils.soliditySha3(network.token.address,"balance", firstPayee))
    console.log proof

    transactionBytes = []
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("msg.sender"), web3Utils.padLeft(firstPayee, 64))
    transactionBytes.push proof
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("amount"), web3Utils.padLeft(web3Utils.toHex(500), 64))
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("destination"), web3Utils.padLeft(secondPayee,64))
    transactionBytes.push network.tree.getNullProof(web3Utils.soliditySha3(network.token.address,"balance", secondPayee))

    console.log 'transaction bytes for second transaction'
    console.log transactionBytes

    myBytes = network.tree.proofBytes(transactionBytes)


    txn = await network.token.vTransfer.call(myBytes)

    console.log 'second transaction results'

    logs = network.tree.parseLogs txn

    console.log logs

    console.log ' trying third transaction ******************************************'

    state2Tree = new DataLogTree.DataLogTree()

    for thisItem in logs
      state2Tree.addItem(thisItem[0], thisItem[1], thisItem[2], thisItem[3])

    console.log state2Tree.layers[0]

    state2Tree.buildTree()

    txn = await network.token.publishCollation(state2Tree.root, "0x0")

    proof = state2Tree.getProof(web3Utils.padLeft(web3Utils.toHex(1),64), web3Utils.padLeft(web3Utils.toHex(1),64), web3Utils.soliditySha3(network.token.address,"balance", secondPayee))
    console.log proof

    secondProof = state1Tree.getProof(web3Utils.padLeft(web3Utils.toHex(1),64), web3Utils.padLeft(web3Utils.toHex(1),64), web3Utils.soliditySha3(network.token.address,"balance", owner))


    transactionBytes = []
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("msg.sender"), web3Utils.padLeft(secondPayee, 64))
    transactionBytes.push proof
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("amount"), web3Utils.padLeft(web3Utils.toHex(250), 64))
    transactionBytes.push network.tree.getVar(web3Utils.soliditySha3("destination"), web3Utils.padLeft(owner,64))
    transactionBytes.push secondProof

    myBytes = network.tree.proofBytes(transactionBytes)


    txn = await network.token.vTransfer.call(myBytes)

    logs = network.tree.parseLogs txn

    console.log logs

    assert.equal 1, 0, "hello"

   

Apologies for the coffeescript...it is 2.0 now so you get all the ES6 goodies.

So far only the red highlighted areas are working:

Scalable Stateless Contracts on Today's EVM Diagram step1.png

 

There are obviously a ton of areas that have big questions:

1.  Can we create a viable consensus amongst collators?
2.  How do we incentivize them?
3.  How to handle no ops?
4.  Have we really just put ethereum inside of ethereum and erased a lot of the checks that ethereum puts on run away gas costs?

I'm open to suggestions for 1-3.

For number four I think it is valuable to keep pushing this string.  There are certainly times where one would want the current EVM to do bigger things.  For example:  Using this I could write an air drop contract that loads up 1,000 balances for way less gas than it would currently cost...if I can get the collators to validate the transaction for me.

*The proof format here is [length, path, type(1=add, 2=del, 3=null), nonce, value, left leaf0, right leaf0.... left leafn, right leafn] where odd layers have an 0x0 on the end but the hash for those odd layers is calculated as the hash of just the left item.  Open to better suggestions.

DevLog 14 - Using a Catallax Trust to Pay Bug Bounties

Fresh off DevCon 3 we have our first bug submitted on the Catallax Trust.  Github user NickErrant pointed out in this github issue that a franchisee could lock up funds by pointing their payment address to a contract that throws on the fall back function.

Generally you can trust that people that want to get paid by a contract won’t do this, but in the case of a Catallax Trust the franchisee could be disgruntled about their payout or choose to protest for some other reason and lock up the contract.

The reason this can happen is that if address.transfer function fails then the function will throw.  Because our withdraw() function pays out to the franchisee if they exist they can block the payment.  The simple fix (and the one we’ve taken at the moment) is to use address.send instead.  If this fails it just returns false and the rest of the function continues to function.

A better solution is to use the withdraw pattern and just set the money aside for the franchisee to come get later.  This requires another storage variable in the contract so it has some cost.

We haven’t deployed the factory to produce this new contract yet so don’t set up a franchise contract until we do so. If you are interested in setting one of these up, please reach out to us and we will work with you to get everything setup correctly.

Nick raised a good point when reporting the bug that bug bounty contracts where you just try to steal the funds have pretty poor incentives for bug hunters.  As a result, we’ve made Nick the beneficiary of the bug bounty contract.  On 11/16 he’ll be able to call withdraw and get out 1/24th of the current balance.

We will leave Nick as the beneficiary until we get our next valid bug report.  At that time, provided the bug is as serious as Nick’s, we will unlock the beneficiary and transfer it to the new bug hunter 36 days later.

Of course, if you'd like to try to steal the money out of the trust you can do that too.

If you’d like to use a Catallax Trust for one of your own bug bounties please reach out to us and we can help you set it up.  The trust supports ETH and ERC20 tokens.

You can find the source code for the contracts here: https://github.com/skilesare/catallaxtrust

Pull down the repo and load them up in remix to interact with the contracts.

If this is interesting to you and you'd like to see where we are going with Catallax, please pick up my book Immortality (Purchase of a physical or kindle copy helps support this project).

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0

If you would like more code articles like this please consider becoming a patron on patreon.

You can discuss this article and more at our reddit page r/Catallax.

Bug Bounty Doubled - $400 - Truffle Tests Released

We are back from DevCon 3 in Cancun.  It was a great week.  We learned a lot and had some great conversations.  We are really excited about moving Catallax forward and getting our decaying currency up and running on the main net.

In the meantime, we've doubled the bug bounty on the Catallax Trust to $400.  We are getting closer to our first opportunity to do a withdrawal on November 16th.

I've also released the truffle tests source.  Reviewing these should give you some idea of how the contract works.

You can find the source code for the contracts here: https://github.com/skilesare/catallaxtrust

Pull down the repo and load them up in remix to interact with the contracts.

If this is interesting to you and you'd like to see where we are going with Catallax, please pick up my book Immortality (Purchase of a physical or kindle copy helps support this project).

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0

If you would like more code articles like this please consider becoming a patron on patreon.

You can discuss this article and more at our reddit page r/Catallax.

Bug Bounty Doubled - $200

No big update this week. We are getting ready for Dev Con.  Looking forward to visiting with the community.  If you want to hear more about the Catallax Trust and the next phase of our project where we'll have a decaying currency working on the blockchain please reach out to austin at catallax dot com.

We've sent another $100 worth of ether over to our Bug Bounty.  Try to get it out!

You can find the source code for the contracts here: https://github.com/skilesare/catallaxtrust

Pull down the repo and load them up in remix to interact with the contracts.

If this is interesting to you and you'd like to see where we are going with Catallax, please pick up my book Immortality (Purchase of a physical or kindle copy helps support this project).

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0

If you would like more code articles like this please consider becoming a patron on patreon.

You can discuss this article and more at our reddit page r/Catallax.

DevLog 13 - $100 Catallax Trust Bug Bounty

The plan was to go with a push out to Ropsten today with the web app up and running.  I’ve had a muted response to the application so far so I’m going to try something different.  I really need some more eyes on this contract before I pour a bunch of dev cycles at the dapp.  So I’ve thrown all caution to the wind and deployed the contracts to mainnet.

I’m created a Catallax Trust Custodian(0x1ed1ee3d6cf25754046e8769f4f2feff57ede7a3), Factory(0x6824457c6c5f711b71dc28c804c6ca767fc84046), Trust Storage(0x79244a86de9b499b03d8c0afe29460d029c5e7a6), and Catallax Trust(0xb8c7842b4451c440f14f0ccfa7cc4bb9734e5df5).  The trust is a two year trust that pays out $30,000 a month.  I’ve loaded it up with $100 worth of ETH.  Please do your best to pull this eth out of the trust.  If you can break the trust please let me know what you did to break it at austin at catallax dot com.

You can find the source code for the contracts here: https://github.com/skilesare/catallaxtrust

Pull down the repo and load them up in remix to interact with the contracts.

I have a bit of time off this week and I’m not sure if I’ll make much progress on the dapp or not.  Some positive feedback and some potential customers might light a fire under me to make the contracts easier to interact with.

If you would like to start a trust right now you can do so by calling the Custodian.CreateTrust function,  Funding the created trust, and then calling the Trust.StartTrust function.

If you’d like to start one but want to see more scrutiny on the contract feel free to send ETH to the Trust address at 0xb8c7842b4451c440f14f0ccfa7cc4bb9734e5df5 to increase the bounty.

Have fun exploring the contracts!  Post questions and issues in our github or reddit here.

If this is interesting to you and you'd like to see where we are going with Catallax, please pick up my book Immortality (Purchase of a physical or kindle copy helps support this project).

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0

If you would like more code articles like this please consider becoming a patron on patreon.

You can discuss this article and more at our reddit page r/Catallax.

DevLog 12 - Catallax Trust Contract Code Release

I’m really excited to release our code for the Catallax Trust today.  It has been a long time coming and it will be nice to get some new eyes on the code.

If this is your first time reading about the Catallax Trust you can read the white paper here.  A Catallax Trust is a contract that will hold crypto and pay it out in the future in fiat-based chunks based on the exchange rate at the time of the withdrawal.  I can be used for employment contracts, donating to a charity, securing ICO funds, or simply helping you HODL with a budget.

We have had one code review done and implemented a number of improvements identified in that code review.  Of course, we hope that the contracts are production ready, but if you think otherwise, please let us know by sending the issue to bugs@catallax.com or filing an issue on the github repo:   https://github.com/skilesare/catallaxtrust

The Catallax Trust is made up of the following main contracts:

FiatTrustCustodian.sol - This is the custodian contract that oversees the creation of new trusts and tracks the fiat to crypto conversion rates for supported crypto / fiat pairs.

FiatTrustFactory.sol - This is the factory contract that the custodian uses to create new trusts.  We can swap this out if we create a better trust without having to republish the custodian.

FiatTrust.sol - This contract is the core trust. Users will deposit their ETH and / or ERC20 tokens in these contracts and be able to withdraw from them over time.

The following support contracts are included as well:

DateTime.sol - a date time library

SafeMath.sol - safe arithmetic functions

ERC20.sol - interacting with tokens

TrustStorage.sol - we have to store the historical history of crypto / fiat exchange rates. This is held in a storage contract so that we can easily move the history to upgraded custodians if necessary.

iLicensor.sol - a stub contract for future governance of the custodian

The general process for setting up the contracts follows the following process(this is the code from our test suite):

prepEnvironment = (custodianOwner)->
 return new Promise (resolve, reject)->
   custodian = null
   factory = null
   token = null
   storage = null
   #Create the custodian
   FiatTrustCustodian.new(from: custodianOwner).then (instance)->
     custodian = instance
     #create the factory
     FiatTrustFactory.new(custodian.address, from: custodianOwner)
   .then (instance)->
     console.log 'new factory'
     factory = instance
     #create a datetime library(this has been published previously on mainnet so you can use one of those)
     DateTime.new(from: custodianOwner)
   .then (instance)->
     console.log 'new DateTime'
     #set the date time library
     custodian.SetDateTimeLibrary(instance.address, from: custodianOwner)
   .then (result)->
     console.log 'dt set'
     #set the factory location
     custodian.SetFactory(factory.address, from:custodianOwner)
   .then (result)->
     console.log 'factory set'
     #Create an ERC20 token to test with
     HumanStandardToken.new(tokenStartBalance,"token",0,'tkn', from: custodianOwner)
   .then (instance)->
     console.log 'new token'
     token = instance
     #create a new storage contract
     TokenStorage.new(from: custodianOwner)
   .then (instance)->
     console.log 'new storage'
     storage = instance
     #set the storage contract
     custodian.SetStorage(storage.address, from: custodianOwner)
   .then (instance) ->
     console.log 'storage set'
     #update the owner of the storage to include the custodian contract
     storage.UpdateOwner(custodian.address, true, from: custodianOwner)
   .then (instance)->
     console.log 'first conversion set'
     #set an old conversion for ETH to USD
     custodian.SetConversion(ethTokenAddress, usdCurrencybytes, 1989,1, 1, web3.toWei(0.01,"ether"),1, from: custodianOwner)
   .then (instance)->
     console.log 'conversion set'
     #set an old conversion for ERC20 token to USD
     custodian.SetConversion(token.address, usdCurrencybytes, 1989,1, 1, web3.toWei(0.01,"ether"),1, from: custodianOwner)
   .then (instance)->
     console.log 'max fee set'
     #set the max fee
     custodian.SetMaxFee(usdCurrencybytes, 50, from: custodianOwner)
   .then (instance)->
     console.log 'origination fee set set'
     #set the origination fee
     custodian.SetOriginationFee(usdCurrencybytes, 25, from: custodianOwner)
   .then ->
     resolve
       custodian: custodian
       token: token

Once your custodian is configured you need to create, fund, and start your trust.  The following code will do that and then make time pass so you can do your first withdrawal:

custodian.CreateTrust(ethTokenAddress, usdCurrencybytes, 12, 1, {from: accounts[0]})
   .then (txn)->
     trustAddress = null
     txn.logs.map (o)->
       if o.event is 'TrustCreated'
         console.log 'found new Trust at' + o.args.location
         i = FiatTrust.at(o.args.location)
         trustAddress = o.args.location
     console.log 'have instance'
     #fund the wallet
     web3.eth.sendTransaction({ from: accounts[1], to: i.address, value: web3.toWei(0.44,"ether") })
   .then (result)->
     #Start the Trust
     i.StartTrust(from:accounts[0])
   .then (result)->
     console.log result
     console.log 'sending ether'
     #this function advances time in our test client by 34 days
     return new Promise (tResolve, tReject)->
       web3.currentProvider.sendAsync
         jsonrpc: "2.0",
         method: "evm_increaseTime",
         params: [86400 * 34],  # 86400 seconds in a day
         id: new Date().getTime()
       , (err)->
         tResolve true
   .then (result)->
     #calculate the next withdraw date
     i.NextWithdraw()
   .then (result)->
     console.log 'next ' + result
     nextPayout = result.toNumber()
     aDate = nextPayout * 1000
     aDate = moment.utc(new Date(aDate))
     console.log aDate
     console.log 'conversion set for ' + aDate.year() + (aDate.month() + 1) + aDate.date()
     #set the conversion for that tdate
     custodian.SetConversion(ethTokenAddress, usdCurrencybytes, aDate.year(), aDate.month() + 1, aDate.date(), web3.toWei(0.01,"ether"),1)
   .then (result)->#call the withdraw fucntion.  0.1 eth shold move from the contract to account[0]
     console.log 'conversion set'
     aDate = nextPayout * 1000
     aDate = moment.utc(new Date(aDate))
     console.log aDate
     #check the current balance
     web3.eth.getBalance(custodian.address)
   .then (result)->
     console.log result
     startCustodianBalance = result.toNumber()
     assert.equal 250000000000000000, startCustodianBalance, 'custodian has ether it shouldnt'
     startBalance = web3.eth.getBalance(accounts[0])
     console.log 'Start Balance' + startBalance
     #withdraw from the trust
     i.Withdraw(from: accounts[0])
   .then (result)->
     console.log result
     web3.eth.getBalance(i.address)
   .then (result)->
     console.log 'withdrawl:' + result
     assert.equal result.toNumber(), parseInt(web3.toWei(0.18,"ether")) - parseInt(web3.toWei(0.01,"ether")) * 0.005, 'withdraw wasnt right'
     web3.eth.getBalance(accounts[0])
   .then (result)->
     console.log result
     #since payout is 0 eth per usd we multiply fiatpayout 1
     #we only test .9 eth and 1.1 because gas costs weigh in
     # so much gas cost
     #96 413397700000000000
     #96 502336500000000000
     #
     console.log 'eth increased' + (result.toNumber() - startBalance.toNumber())
     assert.equal result.toNumber() > startBalance.toNumber(), true, 'eth didnt transfer'
     assert.equal result.toNumber() < startBalance.toNumber() + parseInt(web3.toWei(0.01,"ether")), true, 'too much eth transfered'
     web3.eth.getBalance(custodian.address)
   .then (result)->
     console.log 'fee paid' + result
     assert.equal result.toNumber(), 250000000000000000 + parseInt(web3.toWei(0.01,"ether")) * 0.005, 'Fee wasnt paid'

Have fun exploring the contracts!  Post questions and issues in our github or reddit here.

If this is interesting to you and you'd like to see where we are going with Catallax, please pick up my book Immortality (Purchase of a physical or kindle copy helps support this project).

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0

If you would like more code articles like this please consider becoming a patron on patreon.

You can discuss this article and more at our reddit page r/Catallax.

Give ICO Investors more confidence with a Catallax Trust

The Catallax Trust has been designed to support a number of different scenarios.  I’m outlining each one of these in a different post over the next few weeks as we move toward the release.

Today we are going to talk about how to use a Catallax Trust increase investor confidence in your ICO.

An ICO can funnel the proceeds of their token sale into a Catallax Trust and have it pay out a set fiat denominated amount of those proceeds to cover costs.  They can further increase confidence by assigning ownership of the trust to a multi-sig account overseen by trusted members of the community.

For example, ZkCoin is holding a token sale to raise money for their ZkSnark based token.  They expect to need $50,000 USD per month for the first year to get the project launched.  Excitement is high and they expect to raise much more than is required.  Some in the community do have some fear that the team is untrustworthy and will run off with the raised funds.  To increase confidence in the token sale and project ZkCoin can create a Catallax Trust that pays out $50,000 of raised ETH each month for the first year.  At the end of the year, they don’t know how much they are going to need so they assign ownership of the trust to a group of community member including members of the Ethereum Foundation.  Once the trust matures these members will need to sign the withdraw function that pushes remaining funds into a new trust with an agreed upon monthly budget. If the price of ETH fluctuates wildly one of two things will happen:

  1. If the price of ETH goes up he the trust will pay out less ETH and at the end of the contract ZkCoin will get the remaining ETH back and it can be assigned to a new Trust with the agreement of the community.

  2. If the price of ETH goes down, the trust will auto adjust the payout down so that the cash flows continue for the entire two years with funds equal to less than the desired $50,000.

Using a trust for increasing confidence in your IC to a charity has a number of advantages:

  1. Investors know that a Token owner will only be able to get a set amount of ETH out of the trust per month and won’t be able to blow the full raised amount before proper learning in the marketplace has occurred.

  2. Trust Ownership can be handed to other governing contracts like multi-sig contacts or other governance contracts like Aragon or Colony.

  3. The trust owners can reassign the beneficiary of the trust if the project goes off the rails or dies, perhaps redirecting funds to the Ethereum Foundation.

A Catallax Trust can also be used to help reduce the market manipulation risk for the issued ZkCoin by creating a ZkCoin to USD denominated Catallax Trust.  Many ICOs hold back large amounts of coins to give to developers and investors in the project.  By issuing these coins to a Catallax Trust that only allows a certain amount to be paid out per month the risk to investors is limited.  For example, if 30% of the coins are held back to pay to developers a Catallax Trust could hold these coins and only let $10,000 worth be issued each month.  As the market price of these new ZkCoins fluctuate the amount released will adjust each month and only $10,000 worth could be dumped on the market each month.

Creating the Trust and Assigning it to an ICO requires the following steps:

  1. ICO owner calls the Custodian.CreateTrust function to create a new Catallax Trust contract.  This function takes a token(ETH or ERC20), a currency(USD, EUR, ect.), term(number of months), and fiat payout(amount of currency per term to pay out).

  2. ICO Owner calls the Trust.ChangeBeneficiaryOwner function to set the beneficiary of the trust to their own address.

  3. ICO Owner calls the Trust.ChangeOwner function and assigns ownership of the trust to a governance contract.

  4. The ICO contract uses the trust address as the deposit location for funds raised during the token sale.

  5. Optional:  The ICO contract uses another trust address as the destination of generated developer and investor tokens.

  6. The owning governance contract starts the trust after the crowd sale by calling the Trust.StarTrust function.

  7. During the month the Custodian will be publishing the exchange rates between the token and the currency to the blockchain.

  8. After one month the ICO  can call the Trust.Withdraw function to get the exchange rate adjusted amount of ETH sent to their beneficiary address.

If you are interested in using a Catallax Trust to manage your employment contracts please reach out to us so that we can make sure that we support the Token / Currency combinations that you would like to use.

Please head over to this thread on our Reddit to pick the white paper apart and ask questions.  You can download the Catallax Trust white paper here.

If this is interesting to you and you'd like to see where we are going with Catallax, please pick up my book Immortality (Purchase of a physical or kindle copy helps support this project).

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0

If you would like more code articles like this please consider becoming a patron on patreon.

You can discuss this article and more at our reddit page r/Catallax.