Ternary funding and joint tokens:
a slightly deeper dive


Ternary funding is a mechanism for not-for-profit causes that relies on a subset of validators to attest to an outcome. A joint token is a procedurally generated NFT with a phenotype derived from the addresses of validators.

A basic familiarity with the paper is recommended before jumping into this post.

A recap

Ternary funding:

Joint tokens:

Other aspects:

Parsing the token

For simplicity, let's map every address to the same value.

[
  {0x27..: 0},
  {0x1f..: 0},
  {0x38..: 0},
  {0xa5..: 0},
  ..
]

Even our seemingly blank canvas has more to it than at first glance. Hovering over each entry reveals each contributor's address or ENS name (the latter is possible when reverse resolution is enabled). The number of times the contributor has participated in previous rounds is also displayed. This is only one way to parse the data structure, and its inherent composability allows it to be parsed in different ways.

Skipping the colour examples in Section 2.4.4 of the paper, let's move on to a more complex mapping.

As the hexadecimal representation of every Unicode character can be stored cheaply in bytes2s (e.g. ╟ → 0x255F), we can map uncommon character sets (such as CP437) to each validator address.

For practical purposes, only four mappings are shown.

[
  {0x27..: ►☼▼▄¬○◄○..},
  {0x1f..: ¬⌂◙⌂░°○○..},
  {0x38..: ◘⌂☼╟▄▄▲╢..},
  {0xa5..: º►░⌂⌂╟┬►..},
  ..
]

►☼▼▄¬○◄○≡◙º▄┬╟⌂♦▲♦▲◘◙┬¬○⌂▄┬╟╟░º°♦☼◙►○¬¬◘ߺ▼░φ◘º╗☼◙¬▲φ▲♦►▄◘º◄○╗░ß►≡≡╟╗┬◙╟◘◄≡▼░º⌂◙╢▄◄⌂⌂╢►◙▼░≡°≡⌂◙¬¬º▲◙▼▄ß♦☼╟☼┬○◙♦ß▄°◄►┬◄º┬♦°╟☼░º▄☼♦▄☼◙╗¬⌂╢▼╗°┬▼⌂°º¬⌂►♦▄╟╗╟⌂φ♦º▄▲╢►▲▄º☼☼◘¬►◙┬╟╢░░☼¬▲▼╗○φ▄⌂⌂☼¬φ♦◘φ◙ß◄◙φ◘◘►►⌂►°φ►░☼░°╗º►☼►≡☼◄◘ß♦○►╟►╟┬┬░◘►♦◘♦╢░╟▄▼▼⌂φ▼▄○○┬▄╗╢░►▼◘φ♦▲≡ ¬⌂◙⌂░°○○▼▲╢◙φ╗≡○φ▼☼ß▼▄╟╗▄○▄╢╟◘▲≡◙≡▼⌂╗░┬φ◙▼►◘ß○¬╗◘≡☼≡⌂☼○⌂°◙╢╗ßφº☼¬º¬⌂┬♦▲◄╢☼╗≡☼▲ß°ß◘◙►►╟▄φ≡░▄╢º╗º¬◙°º○◄°¬▲º▄¬◘◄◄○°►¬○╗ºφφ¬◙¬≡≡┬☼○°╗☼♦◄○▲♦¬⌂▼◘⌂≡≡┬ß╢╗┬┬◄╢☼▼╟♦▼░▄┬◄░┬♦°≡⌂≡◄¬☼≡┬╟▄┬►╢○φº╟¬▼◙☼◙≡░☼►┬▲┬◘╢┬╗▼◄┬☼○φ⌂º╢▼▼◙º°º▼┬°╢╗╢◙¬▄ß╗º▲╟░¬┬º◘╢○╟♦╟º╢┬▄♦☼⌂☼ß┬◄º◘☼≡♦▄⌂►º░ ◘⌂☼╟▄▄▲╢▲☼┬▲▼╢▼ß⌂╗░╗◙◄◄╗▲¬╟♦φ♦◄◘┬◙░φ☼░¬▲☼ß○◘φ╟┬º╟╟▄░►╟¬▄☼φ╢ß┬⌂▄▼º┬░◘ß◄φ⌂º▲◘♦☼☼▲◙◄◙▲░φφ♦º°╗►┬┬º┬╟°▄¬╢°╟┬φß◙☼◄▲♦⌂°►◙φ♦ßφφ⌂▄◘º▄╢▲◙♦⌂╢º°¬◙►╟¬╢◘░¬º☼○◙▲▄▄º☼○►╟≡¬▼◙▼░╟▼☼╟☼○◙╗φ≡φß◙╢¬░º◘▲◘◄▲▄░◄¬⌂╗°☼◄☼╟⌂◄◄►♦◘▄☼░⌂▲◄◘╗▄┬¬¬╢┬╟♦╢φ▼╗╢♦φ○▼┬◘φφ○┬ß☼▲░░╢♦°◘≡☼◄⌂◘◙º◄º≡¬ß►▼°► º►░⌂⌂╟┬►○ß╢☼░◙╟╗►ß▄φ╗▲φ☼ß◄φ┬╢φ╟▲╢⌂╢╗≡○►☼▄¬○╗φ°¬¬◄⌂¬░º◙▼°○♦◘ºßº¬≡°◘░°◘¬▲╗♦▼φº╟¬☼◘○┬¬◄╗φ≡ß☼≡φß◙◘░≡╗►¬⌂▲►░╢◘▄◄╟○φ░░┬φ○╟º►╗▼░☼⌂°ß○◙⌂≡▲♦╗☼☼◄►░▄¬♦≡¬≡φ╢┬╗╟φ○╟º○φß░¬►▄☼○┬◙►╢┬◙◙◙╗≡╢◙º⌂º○⌂►☼░▲◄◄▄░¬♦≡◘┬▼¬º╗╗╢╗¬♦◘ß╟º╟▄°╟ßφ┬▲▄ßß▼┬▲◙◙≡◙°≡┬╗≡▄▼°┬╟◄☼≡◘╢╟φ◙◘♦▲¬◙≡╟▲╟φφº▲

Hovering over each quadrant displays each validator's details.

At this point, we’re still using relatively little gas by mapping each validator to 256 Unicode characters. In the next example we push closer to the limit of what can be realistically stored on layer 1 at relatively low cost.

By modifying the pseudorandom function in Section 2.4.4 of the paper, we can provide the values for each rect in our next example, while preserving the use of the validator address as part of the seed. This also produces something more cohesive than an assortment of Unicode characters.

function rand(address _validator, uint256 _shape) internal view returns(uint256) {
  uint256 seed = uint256(keccak256(abi.encodePacked(_validator, _shape, block.timestamp)));
  return seed % max;
}

Storing XML on-chain would be incredibly inefficient (even as bytecode), so a better solution is to only store an array of values corresponding to each variable, and then map it on the client side to a rect template.

< rect
   x=""
   y=""
   width=""
   height=""
   opacity=""
   fill=""
   id=""
   style=""
/>

It's important to note that most of the above variables correspond to floats, which Solidity obviously doesn't support, therefore need to be stored on-chain as integers together with the appropriate factor. It's also worth pointing out that unlike in previous examples, rand() is called multiple times for the same validator, hence the addition of _shape to ensure that rects associated with a single validator are not homogeneous.

Once the array of rects corresponding to each validator is populated off-chain, the final SVG can be constructed.

Similar to the previous example, each quadrant displays each validator's details, however we take advantage of the greater complexity by assigning additional traits off-chain such as luminance and variance.

Implications

The locking mechanism of ternary funding not only allows for criteria to be met before release, but for the implicit mapping of endorsements and expenditures within a single non-fungible token. Use of the latter also often leads to greater funding efficiency as the majority of validators are expected to receive their stake back at the end of a round.

A by-product of the trustlessness introduced by attestation is the enabling of anonymous development — unlike a regular grant, ternary funding is contingent on delivery, encouraging more radical projects.


Link to the paper