Solidity project for the backend of the CAW social network. Read more about this project in the manifesto: https://caw.is
Testnet NFT contract address: https://rinkeby.etherscan.io/address/0xf6e0033f3b225520d2a8c72c8fa1834dc666ad8f
View NFTS on testnet opensea: https://testnets.opensea.io/collection/caw-name-v3
This contract was written in a way that ensures permanent ownership and permanent pricing for minting Caw Usernames, but allows the deployer to change the metadata and the display image by assigning a new display generating contract address. The current display is generated by this contract: https://rinkeby.etherscan.io/address/0x56f0d5da1bc735e03d6a4cd988784ed498fd9ee3#readContract
In the near future, there will be an interface where you can get a username NFT, but for now,
TO MINT A USERNAME ON TESTNET, follow these instructions:
- You must first set your metamask to 'Rinkeby',
Then mint some MintableCaw (mCAW)
:
- Navigate here: https://rinkeby.etherscan.io/address/0x21121c9f9289cf38ddff7763bb4b0735bf78afcd#writeContract
- Connect web3
- Click MINT
- enter your wallet address in the account field
- enter a large number in the amount field (with 18 decimals)
- Then click 'Write'
Then approve mCAW spending of the NFT contract address.
- navigate here: https://rinkeby.etherscan.io/address/0x21121c9f9289cf38ddff7763bb4b0735bf78afcd#writeContract
- Connect web3
- Click 'approve'
- enter your balance (with 18 decimals) in the 'amount field'
- and this address 0xf6e0033f3b225520d2a8c72c8fa1834dc666ad8f in the 'Spender' field
- Then click 'Write'
Once you do that, you'll be able to mint an NFT username.
- Navigate here: https://rinkeby.etherscan.io/address/0xf6e0033f3b225520d2a8c72c8fa1834dc666ad8f#writeContract
- Connect web3
- Click 'mint'
- enter the username you wish to mint
- Then click 'Write'
A decentralized social network comes with a number of difficult problems, especially when the primary source of truth (the etherum blockchain) requires significant fees to store data.
The proposed approach (as implied by CAW manifesto) is to have a second source of truth, a decentralized database (possibly ARWeave), along side the ethereum blockchain.
Due to the open nature of a decentralized database, anyone will be able to post anything to this database, which allows for many avenues of data injection attacks. The following is a list of security requirements, and their proposed solutions.
... more on this later...
As mentioned in the spec, many actions taken by a user will involve redistributing some funds as rewards to "all other stakers". To accomplish this, an algorithm has been developed which works as follows:
Assume n
number of users (denoted as u1, u2, ... un
) have deposited a total amount of CAW denoted as totalDepositedCaw
When an arbitrary user, ui
, removes X
caw from their balance and distributes this amount as rewards to all other users,
the amount added to the account of any arbitrary user (uj
, where j ≠ i
) will be X
multiplied by percentOwnership(uj)
,
where percentOwnership(uj)
is the ratio of the balance of uj
to the total amount of CAW which has been deposited by all users aside from ui
.
percentOwnership(uj) = balanceOf(uj) / (totalDepositedCaw - balanceOf(ui))
The balanceAfterReward
of uj
can be denoted as follows:
balanceAfterReward(uj) = balanceOf(uj) + X * percentOwnership(uj)
i.e.
balanceAfterReward(uj) = balanceOf(uj) + X * balanceOf(uj) / (totalDepositedCaw - balanceOf(ui))
therefore
balanceAfterReward(uj) = balanceOf(uj) * (1 + X / (totalDepositedCaw - balanceOf(ui))
if
r = (1 + X / (totalDepositedCaw - balanceOf(ui))
then
balanceAfterReward(uj) = balanceOf(uj) * r
Since each amount distributed as rewards can be different, we can denote each amount as Xn
, and
rn = (1 + Xn / (totalDepositedCawn - balancen(ui))
and therefore
balanceOf(n+1)(uj) = balanceOfn(uj) * rn
...
balanceOf3(uj) = balanceOf2(uj) * r2
balanceOf2(uj) = balanceOf1(uj) * r1
balanceOf1(uj) = balanceOf0(uj) * r0
and by substitution, we can compute balance3
as:
balanceOf3(uj) = balanceOf2(uj) * r2
balanceOf3(uj) = balanceOf1(uj) * r1 * r2
balanceOf3(uj) = balanceOf0(uj) * r0 * r1 * r2
To compute the current value of any user at any time,
we just need to multiply it's initial balance by the product of all r0...rn
.
In the solidity contract, we are only ever interested in the current balance,
so we can persist a value, rewardMultiplern
, which is overwritten with with each reward distribution n
as
rewardMultipliern = rewardMultiplier(n-1) * rn
which is equivalent to
rewardMultiplern = r0 * r1 * ... * rn
and therefore, at any time
balanceOfn(uj) = balanceOf0(uj) * rewardMultiplern
--
The one other piece of this algorithm that needs to be considered is the balance of ui
,
after ui
distributes X
from it's balance, it should receive no part of X
, and must be
overwritten as it's pre-distribution balance minus X
. Since the current balance of each un
is computed by multiplying rewardMultipler
, we must overwrite the initial balance of ui
to be in terms of rewardMultiplern
. Namely,
balanceOf0(ui) = (balanceOfn-1(ui) - Xn) / rewardMultiplern
Since the spec requires several transactions to move funds between users while simultaneously redistributing
rewards to all other stakers, the contract uses this process of overwriting balanceOf0
in terms of rewardMultiplern
anytime a user receives, spends, deposits, or withdraws
any CAW from their balance.
...
...
(p.s. I dedicate this proof to my grlfren, who not only endured me writing it, but also helped)