Skip to content

Commit 35a3292

Browse files
committed
trackerIdCorrect check fix, more comments in contract
1 parent ecd4db3 commit 35a3292

1 file changed

Lines changed: 21 additions & 9 deletions

File tree

contract/basis.es

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// * onchain contract based redemption with prevention of double redemptions
1818

1919
// How does that work:
20-
// * a tracker holds A -> B debt (as positive number), along with ever increasing (on every operation) timestamp.
20+
// * a tracker holds ever created A -> B debt (as positive ever increasing number), along with ever increasing (on every operation) timestamp.
2121
// A key->value dictionary is used to store the data as hash(AB) -> (amount, timestamp, sig_A), where AB is concatenation of public
2222
// keys A and B, "amount" is amount of debt of A before B, timestamp is operation timestamp (in milliseconds), sig_A is signature of A for
2323
// A for message (hash(AB), amount, timestamp).
@@ -26,15 +26,15 @@
2626
// * tracker is periodically committing to its state (dictionary) by posting its digest on chain
2727
// * at any moment it is possible to redeem A debt to B by calling redemption action of the reserve contract below
2828
// B -> timestamp pair is written into the contract box. Calling the contract after with timestamp <= written on is
29-
// prohibited. Tracker signature is needed to redeem. On next operation with tracker, debt of A is decreased.
29+
// prohibited. Tracker signature is needed to redeem.
3030
// If not, A is refusing to sign updated records. Tracker cant steal A's funds as A's signature is checked.
3131
// * if tracker is going offline, possible to redeem without its signature, when at least one week passed
3232
// * always possible to top up the reserve, to redeem, reserve holder is making an offchain payment to self (A -> A)
3333
// and then redeem
3434

3535

3636
// Data:
37-
// - token #0 - identifying singleton token
37+
// - token #0 - identifying singleton (NFT) token
3838
// - R4 - signing key (as a group element)
3939
// - R5 - tree of timestamps redeemed (to avoid double spending, it should have insert-only flag set)
4040
// - R6 - NFT id of tracker server (bytes) // todo: support multiple payment servers by using a tree
@@ -47,14 +47,16 @@
4747
// - R4 - tracker's signing key
4848
// - R5 - commitment to credit data
4949

50+
// action and reserve output index. By passing them instead of hard-coding, we allow for multiple notes to be
51+
// redeemed at once, which can be used for atomic mutual debt clearing etc
5052
val v = getVar[Byte](0).get
5153
val action = v / 10
52-
val index = v % 10
54+
val index = v % 10 // reserve output position
5355

5456
val ownerKey = SELF.R4[GroupElement].get // reserve owner's key
5557
val selfOut = OUTPUTS(index)
5658

57-
// common checks for all the paths (not incl. ERG value check)
59+
// common checks for all the paths (not incl. ERG value and R5 check)
5860
val selfPreserved =
5961
selfOut.propositionBytes == SELF.propositionBytes &&
6062
selfOut.tokens == SELF.tokens &&
@@ -63,22 +65,31 @@
6365

6466
if (action == 0) {
6567
// redemption path
68+
// context extension variables used:
69+
// #1 - receiver pubkey (as a group element)
70+
// #2 - reserve owner's signature for the debt record
71+
// #3 - current debt amount
72+
// #4 - timestamp
73+
// #5 - proof for insertion into reserve's AVL+ tree
74+
// #6 - tracker's signature
6675

6776
// Tracker box holds the debt information as key-value pairs: AB -> (amount, timestamp)
6877
val tracker = CONTEXT.dataInputs(0) // Data input: tracker box containing debt records
6978
val trackerNftId = tracker.tokens(0)._1 // NFT token ID identifying the tracker
7079
val trackerPubKey = tracker.R4[GroupElement].get // Tracker's public key for signature verification
7180
val trackerTree = tracker.R5[AvlTree].get // AVL tree storing debt commitments from tracker
7281
val expectedTrackerId = SELF.R6[Coll[Byte]].get // Expected tracker ID stored in reserve contract
73-
val trackerIdCorrect = trackerNftId == expectedTrackerId // Verify tracker identity matches
82+
83+
// Verify that tracker identity matches
84+
val trackerIdCorrect = trackerNftId == expectedTrackerId
7485

7586
val g: GroupElement = groupGenerator // Base point for elliptic curve operations
7687

7788
// Receiver of the redemption (creditor)
7889
val receiver = getVar[GroupElement](1).get
7990
val receiverBytes = receiver.getEncoded // Receiver's public key bytes
8091

81-
val ownerKeyBytes = ownerKey.getEncoded // Reserve owner's public key bytes
92+
val ownerKeyBytes = ownerKey.getEncoded // Reserve owner's public key (from R4 register) bytes
8293

8394
// Create key for debt record: hash(ownerKey || receiverKey)
8495
val key = blake2b256(ownerKeyBytes ++ receiverBytes)
@@ -156,6 +167,7 @@
156167

157168
// Combine all validation conditions
158169
sigmaProp(selfPreserved &&
170+
trackerIdCorrect &&
159171
properTimestampTree &&
160172
properReserveSignature &&
161173
properlyRedeemed &&
@@ -164,8 +176,8 @@
164176
// top up
165177
sigmaProp(
166178
selfPreserved &&
167-
(selfOut.value - SELF.value >= 1000000000) && // at least 1 ERG added
168-
selfOut.R5[AvlTree].get == SELF.R5[AvlTree].get
179+
selfOut.R5[AvlTree].get == SELF.R5[AvlTree].get && // R5 register preservation is not checked in selfPreserved
180+
(selfOut.value - SELF.value >= 1000000000) // at least 1 ERG added
169181
)
170182
} else {
171183
sigmaProp(false)

0 commit comments

Comments
 (0)