The CryptoPunks are the epitome of NFT culture. Therefore, it would only be logical if the premier DAO in NFTs would own one of the most distinguished trophies from this collection, an Alien CryptoPunk. Here I, tycoon.eth, prepared a smart contract that will help the Nouns DAO to acquire an Alien punk token using stETH, and I’m using this blog post to document it.
High level overview of the contract in a paragraph
The contract receives stETH and holds it for up to 69 days. In the meantime, any Alien CryptoPunk owner could sell their punk to the contract, in exchange for the balance of the contract’s stETH. The Alien owner would need to use the “Offer to Address” feature for selling the punk to the contract. After settlement, the punk token will be sent to the Nouns DAO treasury address. If the deal is not closed within 69 days, the entire stETH balance will be sent back to the Nouns DAO treasury.
The contract has been deployed to 0x0260Ba2dAe8b85b5A1Bd492829738BDCC7956F35
The contract has been simulated on block 17781581 using this simulation test posted to Github.
L21 defines the `aliens` lookup table for the 9 alien punk ids. We use that to avoid an ugly if-then-else block in our code when validating the punk id
L22 `punks` will point to the punks contract
L23 `stETH` points to staked ETH. Note that it’s a ‘rebasing’ token, so when dealing with it we must always read our balance using balanceOf.
L24 defines the Nouns DAO address as a constant. Set to `0x0BC3807Ec262cB779b38D65b38158acC3bfedE10` the Nouns treasury. This is the address where the contract will send back the punk after buying it. Also, to where it will return the stETH if contract does not buy the punk after a certain time.
L25 defines a timeout for when will the deal expire. 86400 are the seconds in a day, multiplied by 90. We cast that into a uint64
L26 stores the timestamp for when the contract was deployed.
L28–36 Define the alien punks. We assume that the uninitialized value of punks is ‘false’, and only need to set true. There are 9 of these lines, there are 9 alien punks.
The punk numbers:
L37 init the punks contract https://etherscan.io/address/0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB
L38 Init the Lido Staked ETH ERC20 token contract https://etherscan.io/address/0xae7ab96520de3a18e5e111b5eaab095312d7fe84
L39 record the deployment time. This will be used to measure time for returning the stETH
L47 If the difference between now and the deployment time is greater than 69 days, then…
L49 Transfer the entire balance of stETH held by the contract back to the Nouns DAO. Note that since stETH is a rebasing token, we always need to use `balanceOf` since we can never know what our balance is. `require` also checks the return value of the transfer function, the transfer will revert if it returned false.
L63 We validate that the punk is an Alien.
L64 We remember the punk punk owner’s address before the transfer
L65–66 We read the punk’s offer information, check if it is for sale, get the asking price (minValue) and onlySellTo address.
L67 Validate that the punk is actually for sale
L69 Validate that the punk is for sale only to our contract. This is to prevent front running, by making the sale exclusive to our contract will close this loophole.
L72 Whoever calls this method will also need to send some ETH, whatever the Alien punk owner demanded, can be as low as 1 wei. This is because the punks contract requires some ETH to be transferred, even though we will do the tx in stETH
L73 is when it buys the punk. No return value is returned, but seems like the function reverts if not successful. Note that we forward the ETH we received to the `buyPunk` function.
L74 Just a sanity check to make sure that we have the punk
L75 Punk gets transferred to Nouns DAO|
L77 Transfer the stETH to the owner we recorded on L64. Note that the owner is now the contract, so that’s why we recorded it. Since stETH is a rebasing token, we use `stETH.balanceOf` to get the balance, we cannot record the balance. The `require` checks the return value of of the transfer and will revert if false.