Intercoin / CommunityContract

Smart contract for managing community membership and roles
https://intercoin.org
GNU Affero General Public License v3.0
1 stars 2 forks source link

Inviting people using Intercoin app #1

Closed EGreg closed 1 year ago

EGreg commented 3 years ago

We need a way for people with certain roles in the community to invite people who aren't yet in the community, and assign roles to them. The invitation is being sent off-chain in a side channel. The people who are being invited might install a totally new wallet and not have any gas in their new wallet. Here are the details.

  1. When used by an admin A of the community, our Intercoin app will generate a payload P and generate the standard hash and signature Psig. P is a string that serializes some basic invite instructions, such as contract: 0x918aff...aec8 roles: judge member where the spaces are tabs \t. For now just support an array of role strings, but we might have other fields in the future, with ranges for allowed values. The serialization format (such as the one suggested in the example here) should be something that can be easily parsed and unserialized with solidity-stringutils or seriality. Send these to recipient R by any method.

  2. R installs the Intercoin client app, receives P and Psig, and the Intercoin app helps them view the payload P, including the community and roles info from the blockchain. His app generates an ethereum wallet and uses its private key to sign a payload RP, which includes his wallet address and any other parameters he might have set in the app interface when accepting invite. Something like this: address: 0xac8178...fa8c name: Greg Magarshak (the last space here is a space, not a tab character). It generates the standard hash and signature RPsig

  3. Any Intercoin client apps (some are owned by us) will be available to work with any web servers X (some are owned by us) where X controls an EOA with some ether. R sends three variables to X: contract (address of CommunityContract), Psig (signed by A) and RPsig (signed by R) to X. Then X reads CommunityContract mapping called inviteSignatures which is used to map Psig => RPsig. If it is not empty, X will complain to the client.

  4. If it was empty, X will now continue to with a "commit and reveal" scheme on the blockchain. X tells its EOA account to spend some gas and do a simple transaction XT1 which calls method invitePrepare(Psig, RPsig) on the indicated CommunityContract address. All that happens in this method is assigning invitesPrepared[Psig] = RPsig.

Since Psig is practically impossible to guess in advance, it can be used as a key for the "commit" part of the scheme, and the most a rogue X EOA account could do is spam the inviteSignatures mapping. Each CommunityContact can optionally maintain a whitelist of such EOA accounts, which e.g. only the owner can add and remove.

  1. Once the transaction XT1 has been mined, X notifies R of the transaction hash (or block number and transaction index) so R can verify it for themselves. Once R is satisfied that the correct Psig => RPsig mapping has been committed, it reveals P and RP to X (it may as well send along the signatures again, if the R<=>X communication is stateless).

  2. Now, X will post a transaction XT2 which calls inviteAccept(P, Psig, RP, RPsig). This method will compute the hashes and verify the signatures match the ones in the invitesPrepared mapping, namely Psig => RPsig. If something doesn't match, roll back the transaction with a message like "Signatures don't match." Any other server X can try again with its EOA, until the signatures check passes correctly. Then, inviteAccept continues to the next step.

  3. After the signatures matched, update mapping invitesAccepted[Psig] = P. Now if another attempt is made by anyone to call inviteAccept it will roll back saying "This invite was already accepted". Now it goes about the business of accepting the invite.

  1. If everything worked well, the acceptInvite() method calls _reimburseCaller() and _rewardCaller() which will reward the EOA which initiated this XT2 transaction, with enough gas to cover both prepareInvite() and acceptInvite() processing. Since this may be a variable cost, look at the difference in msg.gas between start and end of function, and estimate the gas cost of prepareInvite which always has same cost. See this StackExchange answer and its code.

The _rewardCaller() will send some INTR tokens to this EOA, as "payment" for operating the X node. Paying nodes to help invite users in a user friendly way, is one of the organic ways in which demand for INTR tokens is generated.

  1. The CommunityContract acceptInvite() method will also call the replenish(address) method at the end. This method will check the token balance of R address, and check the minimumGas[role] mapping (default for all roles: 0) of CommunityContract. It will get max over all roles of R in commmunity, of minimumGas. If replenish = max - balance > 0 then this replenish amount of ETH is sent to R address, so it can afford to make some some calls. This method is also supposed tot be called at the end of addRole() after it adds a new member to a community.

  2. In the future, the acceptInvite method might call hooks on approved smart contracts, which may execute various actions correspond to additional instructions sent in RP.

Result: CommunityContract paid gas to reimburse X, and INTR to reward it. It also gave gas to R for an additional transaction, and may reimburse R in the future for more transactions. Meanwhile, R had no gas to start, but some X was online as a web server and its EOA paid the initial amount and got reimbursed. Now, R can participate in the community.

We can allow any contract to call the replenish() method of our CommunityContract. This method will top up ETH gas every time they use any of our contracts and are below a threshold amount. But if it runs out of gas, then it will have to buy more, ask someone to send, or use X mechanism to execute transactions on its behalf.

NOTES:

If ITR or INTR is used to pay for friendly invites, then it will become more expensive per invite if it goes up in price. Usually, the opposite is true - prices of services come down over time. Thus we may want to include some sort of gradually diminishing reward as the block number increases.