verida / blockchain-contracts

Smart contracts, part of the protocol powering the Verida Network
https://www.verida.network
Apache License 2.0
7 stars 2 forks source link

[vda-reward] Support XP points #152

Closed tahpot closed 4 months ago

tahpot commented 7 months ago

We need to either modify our existing vda-reward contract, or create a new one that supports the following requirements:

  1. Every month, VDA is deposited into the smart contract as reward tokens
  2. Every month, Verida users can provide a proof of a signed data record containing XP points
  3. Data will be signed by a trusted Verida whitelisted DID
  4. Users can claim more than one XP proof at a time
  5. XP proofs are generated in one month, and can only be claimed in the following month
  6. Users that don't claim their XP in the correct month, forfeight their XP rewards
  7. Each month will have a different XP to VDA conversion rate
  8. Only the contract owner can change the XP to VDA conversion rate
  9. Any unclaimed VDA will be included in the next month reward pool
  10. Each proof can only be used once
  11. If a uniqueId is specified, it can only be claimed once for a given combination of typeId and uniqueId

Here's an example schema of XP rewards:

{
  didAddress: string (ie: 0xabc...)
  typeId: string (ie: 'gamer31')
  xp: number (ie: 50)
  issueYear: number (id: 2024)
  issueMonth: number (ie: 12=december)
  uniqueId: string (ie: abc123) (optional)
  proof: string (ie: 0xabc...)
}
ITStar10 commented 7 months ago

Questions :

ITStar10 commented 6 months ago

About the proof

Parameters for claim() function

function claimXPReward(didAddress, xp, issuedYear, issuedMonth, proof)

Is this enough?

In the Reward contract, the parameters for claim() function are as following:

function claim(didAddress, ... , signature, proof)

Here, the proof is as following:

proof = trustedSigner.sign(`${trustedSignerAddress}${userAddress}`)

In the VDAVerificationBase contract, the proof of the verifyData() function should be defined as the one in the Reward contract. But the proof in the VDAXPReward contract is different.

tahpot commented 6 months ago
  • What happened if there is insufficient VDA when a user requested a claim()?

Return an error Insufficient tokens available to complete this claim

  • Can a user claim multiple times in a month? In other words, can a user have multiple proofs in a month?

No. Users will always be claiming for the previous month, so are expected to claim all their proofs at once.

  • The input parameter did should be only the address not including the prefix did:xx:xx. Till now, we didn't use the whole did as a input parameter in the smart contract because string operation involves gas consumption in the Solidity. Also string operations is a bit complicated in the Solidity.

Understood, is there a question here?

We will need to ensure only mainnet DIDs can claim, so will need to confirm the didAddress exists in the DID Registry.

tahpot commented 6 months ago
  • What information is there in the proof.
proof = trustedSigner.sign(didAddress, xp, issuedYear, issuedMonth)

Is this correct?

Yes, except it's signing a string, so all those variables will need to be concatenated with a separator

tahpot commented 6 months ago
function claimXPReward(didAddress, xp, issuedYear, issuedMonth, proof)

Is this enough?

No. We need to support multiple claims at once (See requirement 4).

It needs to be something like:

function claimXPReward(didAddress, claims) {}

claims = [{
  xp: 50,
  issuedYear: 2024,
  issuedMonth: 4,
  proof: "0xabc..."
}, {
  xp: 100,
  issuedYear: 2024,
  issuedMonth: 4,
  proof: "0xabc..."
}]

As per the example schema in the scope.

I added a new requirement to the scope for clarity. Each proof can only be used once per month.

ITStar10 commented 6 months ago

Just 2 questions:

I added a new requirement to the scope for clarity. Each proof can only be used once per month.

Between 2 proofs, If the xp, issuedYear, issuedMonth values are the same and they're signed by the same trusted signer , these 2 proof values would be the same. So the user can call as following:

claimXPReward(didAddress, [
 {xp: 10, issuedYear: 2024, issuedMonth: 4, proof: '0x1234'},
 {xp: 10, issuedYear: 2024, issuedMonth: 4, proof: '0x1234'} 
])

By the way, you mentioned that, one proof can be used once per month.

tahpot commented 6 months ago
  • In the claimXPReward() function, the proofs can be signed by different trusted signers, correct?

Yes

What happened if the proof values are the same?

The same proof can only be claimed once per month. So in your example it should reject the claim and produce an error.

ITStar10 commented 6 months ago

The same proof can only be claimed once per month. So in your example it should reject the claim and produce an error.

This means that a user will not get received the same proof in a month? Users can get received several proofs in a month. But there won't be any same proofs. Here, the issuedMonth and issuedYear should be the same. So between the proofs, the xp value or trustedSigner might be different. correct?

tahpot commented 6 months ago

The same proof can only be claimed once per month. So in your example it should reject the claim and produce an error.

This means that a user will not get received the same proof in a month? Users can get received several proofs in a month. But there won't be any same proofs. Here, the issuedMonth and issuedYear should be the same. So between the proofs, the xp value or trustedSigner might be different. correct?

Good point.

We probably need a proofType (ie: gamer31, zkpass-binance-kyc) added to the proof data

tahpot commented 6 months ago

@ITStar10

I have updated the spec, Item (11) is new and also added typeId and uniqueId to the schema.