This document explains how to use FormSI060719, which is part of the show "Garage Politburo" at Susan Inglett Gallery in New York, which is open from June 7, 2019 - July 26, 2019. Let's be honest folks: FormSI067019 is part of a tabletop bureaucracy, so for those not familiar with Ethereum, the instructions below will be at least as confusing as anything the IRS puts out. And the interfaces for using the program here and here are not user friendly. Please submit any complaints by clicking on the "Issues" tab above.
FormSI060719 is a solidity program on the ethereum mainnet at address 0x6B9d46a223fFa343f8b14D855A8314B0EfF7fcb7. It is a form with 13 question, any of which can be answered by any user. The questions and answers that are submitted are state variables (stored on the blockchain), and behave as non-fungible tokens (see the ERC721 standard for more information). The code is published in this repository, and at etherscan.
The ERC721 portion of the program is based on code by OpenZeppelin.
The market portion of the program is based on CryptoPunks by Larva Labs.
Text snippets in FormSI060719 are taken from Masha Gessen, Nisi Shawl, Margaret Thatcher, Fredric Jameson, Leni Zumas, Philip Roth, Omar El Akkad, Wayne La Pierre, David Graeber, Walt Whitman, George Orwell, Rudyard Kipling, and Donna Haraway.
There are three types of functions in FormSi060719: form functions (for reading and answering form questions), market functions (for bidding on question and answers, or putting them up for sale), and standard ERC721 functions.
Returns text of one of the 13 form questions, identified by
questionId, which varies between 0 and 12. For example, going to https://etherscan.io/address/0x6b9d46a223ffa343f8b14d855a8314b0eff7fcb7#readContract, and calling
FormSI060719 :: freeAssociationAndResponse :: Section 0-2b :: When we ask ourselves "How are we? " :: we really want to know ::
FormSI060719 :: freeAssociationAndResponse :: Section2-TINA :: The Secret Joys of Bureaucracy :: Ministry of Splendid Suns :: Ministry of Plenty :: Crime Bureau :: Aerial Board of Control :: Office of Tabletop Assumption :: Central Committee :: Division of Complicity :: Ministry of Information ::
and so on....
answerQuestion(uint256 questionId, string answer)
Allows user to answer a question, identified by
questionId. The string
answer will be associated with this question, and stored on the blockchain. Like all the questions, each entered answer behaves as an ERC721 non-fungible token.
Returns number of answers that have been entered for question
getFormAnswers(uint256 questionId, uint256 answerId)
Returns text of an answer to a question. The question is identified by
questionId (which goes from 0 to 12), and the answer for the question is identified by
answerId (which goes from 1 to the number of answers for that particular question). If there are no answers to the question, this function throws.
getIndexfromQA(uint256 questionId, uint256 textId)
Provides conversion between the two types of indices the program uses.
The section of FormSI060719 that deals with with the form refers to question and answer text with a pair of numbers, which will be referred to as a QA pair (
questionId, textId). The index
questionId identifies the question and varies from 0 to 12. When the index
textId is zero, the question itself is selected. When the index
textId is greater than zero, it selects an answer associated with
However, the ERC721 section of the program (see below) refers to a question or answer with a single token index (
tokenId). The token indices 0 through 12 contain the questions, the first entered answer will receive token index 13, the second question entered will receive token index 14, etc.
getIndexfromQA(uint256 questionId, uint256 textId) takes in a QA pair, and returns the ERC721 token index. The function
getQAfromIndex(uint256 tokenId) takes in the ERC721 token index, and returns a QA pair. If any of the indices are out of bounds (using 14 for
questionId, for example), the function throws.
There are three groups of functions here. The "For Sale" functions enable the token owner to put a token (really a question or answer) up for sale at a price (
minPriceWei). If someone chooses to buy the token, the token and ether change hands. Information about whether a token is up for sale, and if so what its price is, can be obtained from
The "Bid" functions enable anyone to put a bid up for any token. The token owner may choose to accept the bid, resulting in an exchange of the token for the amount of ether bid. Information about whether or not there's a bid on a token, and if so what the bid amount is, can be obtained from
The "Withdraw" functions handle the withdrawal of ether after a transaction. All money amounts are in wei (1 wei = 1e18 ether)
Only the token owner (and not other authorized users from the ERC721 section of the code) can put a token up for sale, or accept a bid.
For Sale Functions
marketDeclareForSale(uint256 tokenId, uint256 minPriceInWei)
Declare a token (identified by the ERC721 index
tokenId) for sale, at a price
minPriceInWei. Only the token owner can call this function.
marketDeclareForSaleToAddress(uint256 tokenId, uint256 minPriceInWei, address to)
Declare a token (identified by the ERC721 index
tokenId) for sale to a specific address
to, at a price
minPriceInWei. Only the address
to can buy this token. Only the token owner can call this function.
Remove a "For Sale" declaration. Only the token owner can call this function.
Shows the "For Sale" status of a specific token (identified by the ERC721 index
tokenId). The structure
marketForSaleInfoByIndex(tokenId) contains a boolean indicating whether or not the token is for sale (
isForSale), the ERC721 index of the token (
tokenId), the current owner and seller of the token (
seller), the price of the token (
minValue) in wei, and the address of the designated recipient (
onlySellTo), if there is one. Note that this function is a getter that directly accesses the structure, so it does not throw if the token
tokenId does not exist, unlike the other "For Sale" functions.
Enables a user to buy a token (identified by the ERC721 index
tokenId) that is up for sale. If
marketForSaleInfoByIndex(tokenId).onlySellto returns the zero address, then any user can buy the token. If
marketForSaleInfoByIndex(tokenId).onlySellto returns a non-zero address, then only that user can buy the token. The purchaser must send an amount of wei at least equal to the sale price (
marketForSaleInfoByIndex(tokenId).minValue) with the function call to complete the transaction.
Enables a user to declare a bid for a token (identified by the ERC721 index
tokenId). The user must send the amount of the bid with the function call. If there is already a bid on the token (check
marketBidInfoByIndex(uint256 tokenId)), the bid must be larger than
marketDeclareBid(tokenId) throws. Assuming it is larger, the previous bid is overwritten, and the amount of the previous bid is made available for withdraw by the previous bidder through
Enables a user to remove a bid on a token (identified by the ERC721 index
tokenId) already made. Only the bidder
marketBidInfoByIndex(tokenId).bidder can call this function. The bid is not automatically refunded: the user must call
marketAcceptBid(uint256 tokenId, uint256 minPrice)
Enables a token owner to accept a bid, and transfer the token (identified by the ERC721 index
tokenId) to the bidder in exchange for the ether bid. Only the token owner can call this function. The parameter
minPrice must be smaller than or equal to
marketBidInfoByIndex(tokenId).value. After calling this function, the bid is not automatically transferred to the former owner: the former owner must call
Shows the "Bid" status of a specific token (identified by the ERC721 index
tokenId). The structure
marketBidInfoByIndex(tokenId) contains a boolean indicating whether or not a bid for the token exists (
hasBid), the ERC721 index of the token (
tokenId), the current bidder for the token (
bidder), and the bid in wei (
value). Note that this function is a getter that directly access the structure, so it does not throw if the token
tokenId does not exist, unlike the other "Bid" functions.
Shows the amount of ether (in wei) avaiable for the address
holder to withdraw using
Enables a user to withdraw ether after a successful sale, after accepting a bid, after withdrawing a bid, or after another address outbids. When a user (identified by
marketWithdrawWei(), the amount
marketPendingWithdrawals(address) is transferred to the user address.
The standard ERC721 functions are implemented with OpenZeppelin code (specifically, FormSI060719 uses the Jan 4 2019 Open Zeppelin package 76abd1a41ec7d96ef76370f3eadfe097226896a2). The Open Zeppelin code is untouched, except for changes to the function
transferFrom(address from, address to, uint256 tokenId), which ensures that, if necessary, the function correctly resets any outstanding bids or for sale declarations when a token is transferred.
name() totalSupply() symbol() supportsInterface(bytes4 interfaceId) balanceOf(address owner) ownerOf(uint256 tokenId) approve(address to, uint256 tokenId) setApprovalForAll(address to, bool approved) isApprovedForAll(address owner, address operator) transferFrom(address from, address to, uint256 tokenId) safeTransferFrom(address from, address to, uint256 tokenId) safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data)