Willidity: Reference Guide

About

Presenting Willidity, a prototype Web3 application for decentralized Will creation and deployment with Solidity. You can deploy wills at a time of your choice, while the will is kept secret before that.

Usage directions:

Follow these steps to deploy the Will

Code snippet

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

contract WillFactory {

    constructor() payable {
         // receive ETH at deployment
    }


    event Deployed(address addr);
    event Hashed(string hash);

    uint256 private thresholdTime=block.timestamp+3 minutes;

    bytes32 private bytecodecheck;

    bytes32 private cidcheck;

    bytes private encryptedCID;

    string public CID="";

    bool commit=false;

    bool locDisclosed=false;

    //TODO: Change address!
    address constant owner=0xC1...;

    modifier onlyOwner() {
        require(msg.sender == owner, "Caller is not the owner");
        _; // Placeholder for the modified function's logic
    }


    function deployBytecode(bytes memory bytecode) external returns (address addr) {
        bytes32 bHash = keccak256(bytecode);
        require(bytecode.length > 0, "Bytecode is empty");
        //require(block.timestamp > thresholdTime, "too early");
        require(locDisclosed, "too early. Did you hack?");
        require(bHash==bytecodecheck, "Do not decieve");

        uint256 startGas = gasleft();
        assembly {
            // create(value, offset, size)
            // value = 0 (no ETH sent)
            // offset = pointer to bytecode data in memory
            // size = length of bytecode
            addr := create(11000000000000000, add(bytecode, 0x20), mload(bytecode))
        }
        if (addr == address(0)) {
        // Possible reasons: revert in constructor, out of gas, invalid bytecode
        uint256 gasUsed = startGas - gasleft();
        revert(
            string(
                abi.encodePacked(
                    "Deployment failed (constructor revert / invalid bytecode / out of gas). Gas used: ", gasUsed
                )
            )
        );
    }
        _reset();
        emit Deployed(addr);
    }


    function bytesToBytes32(bytes memory b) private pure returns (bytes32) {
  bytes32 out;

  for (uint i = 0; i < 32; i++) {
    out |= bytes32(b[ i] & 0xFF) >> (i * 8);
  }
  return out;
}

    function setEncryptedCID(bytes calldata ec, bytes calldata hcid) external onlyOwner{
        encryptedCID = ec;
        cidcheck = bytesToBytes32(hcid);
    }

    function setBytecodeHash(bytes calldata bs) external onlyOwner{
        require(!commit, "can Only set once");
        bytecodecheck = bytesToBytes32(bs);
        commit=true;
    }

    function setThresholdTime(uint256 Seconds) external onlyOwner{
        thresholdTime=block.timestamp+Seconds;
    }

    function getECID() external view returns (bytes memory) {
        return encryptedCID;
    }

    function setCID(string calldata ciid) external {
        require(block.timestamp > thresholdTime, "too early");
        bytes32 chash=keccak256(abi.encodePacked(ciid));
        require(chash==cidcheck, "authentic CID already set");
        CID=ciid;
        locDisclosed=true;
    }

    function deposit() public payable {
            // The ether is sent to the contract here
            // You can add other logic here, for example, updating a user's balance
    }

    function withdraw() public payable onlyOwner{
            // The ether is sent to the contract here
            // You can add other logic here, for example, updating a user's balance
            address payable op = payable(owner);
            op.transfer(address(this).balance-0.0004 ether);
    }

    function reset()  external onlyOwner {
        _reset();
        
    }

    function _reset() internal 
    {
        CID="";
        commit=false;
        encryptedCID="";
        bytecodecheck=bytes32(0);
        locDisclosed=false;
    }
}
      

Deployment Flow: Owner encrypts bytecode and puts it on IPFS, Sets parameters on WF contract

Example Image 1

Deployment Flow: Custodians disclose CID and deploy Bytecode

Executes only after threshold time
Example Image 2

Terminologies

Security and Integrity measures:

Everything on the contract is visible publicly, even private variables. So, its necessary all cryptography happens off chain.

Also, the responsibility of execution has been split between two members to ensure that incase one of them behaves with vested intentions, either the content or the location (CID) is kept secret. The hash of the bytecode ensures that only the bytecode written by the owner is deployed.

Also, the bytecode being encrypted plays a peculiar role. By keeping the will logic secret, it ensures that no party behaves/creates influence via specific behaviours before the execution of the will, so that the will logic favours them.

Bytecode is stored in the IPFS instead of contract storage, since such storage is gas intensive. The CID is hashed as well, to prevent malicious actors from setting the wrong CID, by performing integrity checks.

The reason for resorting to blockchain is to ensure integrity, transparency, accountability and that no one party has full control of the entire process.