From 079b0833316b4b5dd9b9e637be394c6b1a5baf31 Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:18:51 -0400 Subject: [PATCH 1/9] use loops to find token id as defined in compile time constants --- contracts/v1/ergonames_v1_collection.es | 35 +++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/contracts/v1/ergonames_v1_collection.es b/contracts/v1/ergonames_v1_collection.es index 2f53327..6dcd1e6 100644 --- a/contracts/v1/ergonames_v1_collection.es +++ b/contracts/v1/ergonames_v1_collection.es @@ -28,6 +28,8 @@ // ===== Compile Time Constants ($) ===== // // $revealErgoTreeBytesHash: Coll[Byte] // $revealProxyErgoTreeBytesHash: Coll[Byte] + // $ergonameCollectionSingletonTokenId: Coll[Byte] + // $ergonameCollectionTokenId: Coll[Byte] // ===== Context Variables (_) ===== // // None @@ -37,8 +39,9 @@ // ===== Relevant Variables ===== // val minerFeeErgoTreeHash: Coll[Byte] = fromBase16("e540cceffd3b8dd0f401193576cc413467039695969427df94454193dddfb375") - val ergonameCollectionTokenId: Coll[Byte] = SELF.tokens(1)._1 - val ergonameCollectionTokenAmount: Long = SELF.tokens(1)._2 + val ergonameCollectionTokenAmount = SELF.tokens.fold(0L, { (sum: Long, t: (Coll[Byte], Long)) => + if (t._1 == $ergonameCollectionTokenId) sum + t._2 else sum + }) val isRefund: Boolean = (OUTPUTS.size == 3) if (!isRefund) { @@ -56,11 +59,27 @@ val validSelfRecreation: Boolean = { + val validSingletonTransfer: Boolean = { + + ergonameCollectionBoxOut.tokens.exists({ (t: (Coll[Byte], Long)) => + t._1 == $ergonameCollectionSingletonTokenId + }) + + } + + val validCollectionTokensTransfer: Boolean = { + + ergonameCollectionBoxOut.tokens.exists({ (t: (Coll[Byte], Long)) => + t == ($ergonameCollectionTokenId, ergonameCollectionTokenAmount - 1L) + }) + + } + allOf(Coll( (ergonameCollectionBoxOut.value == SELF.value), (ergonameCollectionBoxOut.propositionBytes == SELF.propositionBytes), - (ergonameCollectionBoxOut.tokens(0) == SELF.tokens(0)), - (ergonameCollectionBoxOut.tokens(1) == (ergonameCollectionTokenId, ergonameCollectionTokenAmount - 1L)) + validSingletonTransfer, + validCollectionTokensTransfer )) } @@ -71,8 +90,8 @@ allOf(Coll( (blake2b256(revealBoxOut.propositionBytes) == $revealErgoTreeBytesHash), - (revealBoxOut.tokens(0) == (ergonameCollectionTokenId, 1L)), - (revealBoxOut.R7[Coll[Byte]].get == ergonameCollectionTokenId), // For artwork standard v2 (EIP-24). + (revealBoxOut.tokens(0) == ($ergonameCollectionTokenId, 1L)), + (revealBoxOut.R7[Coll[Byte]].get == $ergonameCollectionTokenId), // For artwork standard v2 (EIP-24). )) } @@ -105,7 +124,7 @@ (ergonameCollectionBoxOut.value == SELF.value), (ergonameCollectionBoxOut.propositionBytes == SELF.propositionBytes), (ergonameCollectionBoxOut.tokens(0) == SELF.tokens(0)), - (ergonameCollectionBoxOut.tokens(1) == (ergonameCollectionTokenId, ergonameCollectionTokenAmount + 1L)) + (ergonameCollectionBoxOut.tokens(1) == ($ergonameCollectionTokenId, ergonameCollectionTokenAmount + 1L)) )) } @@ -114,7 +133,7 @@ allOf(Coll( (blake2b256(revealBoxIn.propositionBytes) == $revealErgoTreeBytesHash), - (revealBoxIn.tokens(0) == (ergonameCollectionTokenId, 1L)) + (revealBoxIn.tokens(0) == ($ergonameCollectionTokenId, 1L)) )) } From 73486d7ce779ef8d1fb60186c8b1285aaa7bffb7 Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:21:07 -0400 Subject: [PATCH 2/9] ensure age threshhold and price map are preserved, suggestion for fee payment --- contracts/v1/ergonames_v1_registry.es | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contracts/v1/ergonames_v1_registry.es b/contracts/v1/ergonames_v1_registry.es index e904793..04e9a9f 100644 --- a/contracts/v1/ergonames_v1_registry.es +++ b/contracts/v1/ergonames_v1_registry.es @@ -160,7 +160,7 @@ val validErgoNameInsertion: Boolean = { - val newRegistry: AvlTree = previousRegistry.insert(Coll((_ergoNameHash, ergoNameTokenId)), _insertionProof).get + val newRegistry: AvlTree = previousRegistry.insert(Coll((_ergoNameHash, ergoNameTokenId)), _insertionProof).get allOf(Coll( (registryBoxOut.R4[AvlTree].get.digest == newRegistry.digest), @@ -174,7 +174,9 @@ allOf(Coll( (registryBoxOut.value == SELF.value), (registryBoxOut.propositionBytes == SELF.propositionBytes), - (registryBoxOut.tokens(0) == SELF.tokens(0)) + (registryBoxOut.tokens(0) == SELF.tokens(0)), + (registryBoxOut.R6[(Int, Int)].get == ageThreshold), + (registryBoxOut.R7[Coll[BigInt]].get == priceMap) )) } @@ -213,7 +215,7 @@ if (isDefaultPaymentMode) { - val validFeePayment: Boolean = (ergoNameFeeBoxOut.value.toBigInt >= equivalentNanoErg) + val validFeePayment: Boolean = (10921937550L == equivalentNanoErg) // this needs to have buffer of maybe 5% each side since there can be changes to oracle price val validFeeAddress: Boolean = (blake2b256(ergoNameFeeBoxOut.propositionBytes) == $ergoNameFeeContractBytesHash) allOf(Coll( From d54291a18aca881c1ed4ef273b273046b548d09b Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:26:02 -0400 Subject: [PATCH 3/9] removed txOperatorFeeAmount since it actually comes from commit box --- contracts/v1/ergonames_v1_reveal.es | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/v1/ergonames_v1_reveal.es b/contracts/v1/ergonames_v1_reveal.es index 010743c..ec96340 100644 --- a/contracts/v1/ergonames_v1_reveal.es +++ b/contracts/v1/ergonames_v1_reveal.es @@ -142,7 +142,7 @@ val validRevealBoxInValue: Boolean = { - val validErgValue: Boolean = (SELF.value == subNameRegistryAmount + ergoNameIssuanceAmount + ergoNameFeeErgAmount + minerFeeAmount + txOperatorFeeAmount) + val validErgValue: Boolean = (SELF.value == subNameRegistryAmount + ergoNameIssuanceAmount + ergoNameFeeErgAmount + minerFeeAmount) val validTokenValue: Boolean = { if (isPayingWithToken) { From c56e3ec70c2891472d81347920ab05b0ef5dfecb Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:27:04 -0400 Subject: [PATCH 4/9] fix unused props --- contracts/v1/ergonames_v1_reveal.es | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/v1/ergonames_v1_reveal.es b/contracts/v1/ergonames_v1_reveal.es index ec96340..dabaee9 100644 --- a/contracts/v1/ergonames_v1_reveal.es +++ b/contracts/v1/ergonames_v1_reveal.es @@ -202,6 +202,8 @@ validCommitBoxIn, validSubNameRegistryAmount, validErgonameIssuanceAmount, + validErgoNameMint, + validCollectionTokenBurn, validMinerFeeBoxOut, validTxOperatorFeeBoxOut, (OUTPUTS.size == 6) From 95448ecca8f9ff8fa0e11b2a3b67b7fa6ce20b78 Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:28:46 -0400 Subject: [PATCH 5/9] use loop to check for collection singleton --- contracts/v1/ergonames_v1_reveal_proxy.es | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contracts/v1/ergonames_v1_reveal_proxy.es b/contracts/v1/ergonames_v1_reveal_proxy.es index 981038f..e31f9da 100644 --- a/contracts/v1/ergonames_v1_reveal_proxy.es +++ b/contracts/v1/ergonames_v1_reveal_proxy.es @@ -48,7 +48,13 @@ val minerFeeBoxOut: Box = OUTPUTS(2) val txOperatorFeeBoxOut: Box = OUTPUTS(3) - val validCollection: Boolean = (ergonameCollectionBoxIn.tokens(0)._1 == $ergoNameCollectionSingletonTokenId) + val validCollection: Boolean = { + + ergonameCollectionBoxIn.tokens.exists({ (t: (Coll[Byte], Long)) => + t._1 == $ergoNameCollectionSingletonTokenId + }) + + } val validReveal: Boolean = { From 2ea068077216beee7714030e5149782ad7cc03c5 Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Mon, 16 Sep 2024 20:29:17 -0400 Subject: [PATCH 6/9] fix payment token index inconsistency --- contracts/v1/ergonames_v1_reveal_proxy.es | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/v1/ergonames_v1_reveal_proxy.es b/contracts/v1/ergonames_v1_reveal_proxy.es index e31f9da..7f56ac2 100644 --- a/contracts/v1/ergonames_v1_reveal_proxy.es +++ b/contracts/v1/ergonames_v1_reveal_proxy.es @@ -59,7 +59,7 @@ val validReveal: Boolean = { val revealHash: Coll[Byte] = blake2b256(revealBoxOut.bytesWithoutRef) // Bytes of box contents without transaction id and output index. - val validPaymentToken: Boolean = if (isPayingWithToken) (revealBoxOut.tokens(0) == SELF.tokens(0)) else true + val validPaymentToken: Boolean = if (isPayingWithToken) (revealBoxOut.tokens(1) == SELF.tokens(0)) else true allOf(Coll( (revealBoxOut.value == SELF.value - minerFee - txOperatorFee), From e4d803447dd50fc8009af71a124fb8b68a07def8 Mon Sep 17 00:00:00 2001 From: Luca D'Angelo Date: Fri, 20 Sep 2024 02:35:01 -0400 Subject: [PATCH 7/9] Add slippage check to registry. --- contracts/v1/ergonames_v1_registry.es | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/contracts/v1/ergonames_v1_registry.es b/contracts/v1/ergonames_v1_registry.es index 04e9a9f..7b58ad4 100644 --- a/contracts/v1/ergonames_v1_registry.es +++ b/contracts/v1/ergonames_v1_registry.es @@ -215,7 +215,25 @@ if (isDefaultPaymentMode) { - val validFeePayment: Boolean = (10921937550L == equivalentNanoErg) // this needs to have buffer of maybe 5% each side since there can be changes to oracle price + val validFeePayment: Boolean = { + + val amount: BigInt = revealBoxIn.value.toBigInt // Reveal box contains target price when reveal was created + 5% slippage. + val target: BigInt = (amount * 100.toBigInt) / 105.toBigInt // 5% slippage + val slippage: BigInt = (amount - target) + val difference: BigInt = (equivalentNanoErg - target) + val isWithin: Boolean = (difference >= 0 && difference < slippage) || (difference <= 0 && difference > -1.toBigInt * slippage) + + val validFee: Boolean = (ergoNameFeeBoxOut.value.toBigInt >= equivalentNanoErg) + val validChange: Boolean = (ergoNameIssuanceBoxOut.value.toBigInt >= (amount - equivalentNanoErg)) + + allOf(Coll( + isWithin, + validFee, + validChange + )) + + } + val validFeeAddress: Boolean = (blake2b256(ergoNameFeeBoxOut.propositionBytes) == $ergoNameFeeContractBytesHash) allOf(Coll( From d337aaadc7f64e31053e00623a9059c99ade40b9 Mon Sep 17 00:00:00 2001 From: Luca D'Angelo Date: Fri, 20 Sep 2024 03:00:36 -0400 Subject: [PATCH 8/9] Add refund tx to reveal proxy. --- contracts/v1/ergonames_v1_commit.es | 2 +- contracts/v1/ergonames_v1_reveal_proxy.es | 148 ++++++++++++++++------ 2 files changed, 111 insertions(+), 39 deletions(-) diff --git a/contracts/v1/ergonames_v1_commit.es b/contracts/v1/ergonames_v1_commit.es index a8a8e0b..6c3d56b 100644 --- a/contracts/v1/ergonames_v1_commit.es +++ b/contracts/v1/ergonames_v1_commit.es @@ -125,7 +125,7 @@ } - sigmaProp(validRefundTx) + sigmaProp(validRefundTx) && userPKSigmaProp } diff --git a/contracts/v1/ergonames_v1_reveal_proxy.es b/contracts/v1/ergonames_v1_reveal_proxy.es index 7f56ac2..580725a 100644 --- a/contracts/v1/ergonames_v1_reveal_proxy.es +++ b/contracts/v1/ergonames_v1_reveal_proxy.es @@ -13,6 +13,7 @@ // R4: Coll[Byte] RevealBoxHash // R5: Long MinerFee // R6: Long TxOperatorFee + // R7: GroupElement UserPKGroupElement // ===== Relevant Transactions ===== // // 1. Reveal @@ -20,6 +21,11 @@ // Data Inputs: None // Outputs: ErgoNameCollection, Reveal, MinerFee, TxOperatorFee // Context Variables: None + // 2. Refund Reveal Proxy + // Inputs: RevealProxy + // DataInputs: None + // Outputs: UserPKBoxOut, MinerFee + // Context Variables: None // ===== Compile Time Constants ($) ===== // // $ergoNameCollectionSingletonTokenId: Coll[Byte] @@ -28,68 +34,134 @@ // None // ===== User Defined Functions ===== // - // None + // def isSigmaPropEqualToBoxProp: ((SigmaProp, Box) => Boolean) + + def isSigmaPropEqualToBoxProp(propAndBox: (SigmaProp, Box)): Boolean = { + + val prop: SigmaProp = propAndBox._1 + val box: Box = propAndBox._2 + + val propBytes: Coll[Byte] = prop.propBytes + val treeBytes: Coll[Byte] = box.propositionBytes + + if (treeBytes(0) == 0) { + + (treeBytes == propBytes) + + } else { + + // offset = 1 + + val offset = if (treeBytes.size > 127) 3 else 2 + (propBytes.slice(1, propBytes.size) == treeBytes.slice(offset, treeBytes.size)) + + } + + } // ===== Relevant Variables ===== // val minerFeeErgoTreeHash: Coll[Byte] = fromBase16("e540cceffd3b8dd0f401193576cc413467039695969427df94454193dddfb375") val revealBoxHash: Coll[Byte] = SELF.R4[Coll[Byte]].get val minerFee: Long = SELF.R5[Long].get val txOperatorFee: Long = SELF.R6[Long].get + val userPKGroupElement: GroupElement = SELF.R7[GroupElement].get + val userPKSigmaProp: SigmaProp = proveDlog(userPKGroupElement) val isPayingWithToken: Boolean = (SELF.tokens.size == 1) + val isRefund: Boolean = (OUTPUTS.size == 2) - val validRevealTx: Boolean = { + if (!isRefund) { - // Inputs - val ergonameCollectionBoxIn: Box = INPUTS(0) + val validRevealTx: Boolean = { - // Outputs - val ergonameCollectionBoxOut: Box = OUTPUTS(0) - val revealBoxOut: Box = OUTPUTS(1) - val minerFeeBoxOut: Box = OUTPUTS(2) - val txOperatorFeeBoxOut: Box = OUTPUTS(3) + // Inputs + val ergonameCollectionBoxIn: Box = INPUTS(0) - val validCollection: Boolean = { + // Outputs + val ergonameCollectionBoxOut: Box = OUTPUTS(0) + val revealBoxOut: Box = OUTPUTS(1) + val minerFeeBoxOut: Box = OUTPUTS(2) + val txOperatorFeeBoxOut: Box = OUTPUTS(3) - ergonameCollectionBoxIn.tokens.exists({ (t: (Coll[Byte], Long)) => - t._1 == $ergoNameCollectionSingletonTokenId - }) + val validCollection: Boolean = { - } + ergonameCollectionBoxIn.tokens.exists({ (t: (Coll[Byte], Long)) => + t._1 == $ergoNameCollectionSingletonTokenId + }) - val validReveal: Boolean = { + } - val revealHash: Coll[Byte] = blake2b256(revealBoxOut.bytesWithoutRef) // Bytes of box contents without transaction id and output index. - val validPaymentToken: Boolean = if (isPayingWithToken) (revealBoxOut.tokens(1) == SELF.tokens(0)) else true + val validReveal: Boolean = { - allOf(Coll( - (revealBoxOut.value == SELF.value - minerFee - txOperatorFee), - validPaymentToken, - (revealHash == revealBoxHash) - )) + val revealHash: Coll[Byte] = blake2b256(revealBoxOut.bytesWithoutRef) // Bytes of box contents without transaction id and output index. + val validPaymentToken: Boolean = if (isPayingWithToken) (revealBoxOut.tokens(1) == SELF.tokens(0)) else true - } + allOf(Coll( + (revealBoxOut.value == SELF.value - minerFee - txOperatorFee), + validPaymentToken, + (revealHash == revealBoxHash) + )) + + } + + val validMinerFee: Boolean = { - val validMinerFee: Boolean = { + allOf(Coll( + (minerFeeBoxOut.value == minerFee), + (blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash) + )) + + } + + val validTxOperatorFee: Boolean = (txOperatorFeeBoxOut.value == txOperatorFee) + + allOf(Coll( + validCollection, + validReveal, + validMinerFee, + validTxOperatorFee, + (OUTPUTS.size == 4) + )) + + } + + sigmaProp(validRevealTx) + + } else { + + val validRefundTx: Boolean = { + + // Outputs + val userPKBoxOut: Box = OUTPUTS(0) + val minerFeeBoxOut: Box = OUTPUTS(1) + + val validUser: Boolean = { + + val propAndBox: (SigmaProp, Box) = (userPKSigmaProp, userPKBoxOut) + + allOf(Coll( + (userPKBoxOut.value == SELF.value - minerFee), + isSigmaPropEqualToBoxProp(propAndBox) + )) + + } + + val validMinerFee: Boolean = { + + allOf(Coll( + (minerFeeBoxOut.value == minerFee), + (blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash) + )) + + } allOf(Coll( - (minerFeeBoxOut.value == minerFee), - (blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash) + validUser, + validMinerFee )) - + } - val validTxOperatorFee: Boolean = (txOperatorFeeBoxOut.value == txOperatorFee) - - allOf(Coll( - validCollection, - validReveal, - validMinerFee, - validTxOperatorFee, - (OUTPUTS.size == 4) - )) + sigmaProp(validRefundTx) && userPKSigmaProp } - sigmaProp(validRevealTx) - } \ No newline at end of file From 01eb3de0ab4de8251b79c12c62f456aae12cdb2a Mon Sep 17 00:00:00 2001 From: Luca D'Angelo Date: Fri, 20 Sep 2024 13:42:15 -0400 Subject: [PATCH 9/9] Add token preservation checks. --- contracts/v1/ergonames_v1_reveal.es | 7 +++++-- contracts/v1/ergonames_v1_reveal_proxy.es | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/contracts/v1/ergonames_v1_reveal.es b/contracts/v1/ergonames_v1_reveal.es index dabaee9..7d36efb 100644 --- a/contracts/v1/ergonames_v1_reveal.es +++ b/contracts/v1/ergonames_v1_reveal.es @@ -231,10 +231,12 @@ val validUser: Boolean = { val propAndBox: (SigmaProp, Box) = (userPKSigmaProp, userPKBoxOut) + val validPaymentTokenTransfer: Boolean = if isPayingWithToken (userPKBoxOut.tokens(0) == SELF.tokens(1)) else (userPKBoxOut.tokens.size == 0) allOf(Coll( (userPKBoxOut.value == SELF.value - minerFee), - isSigmaPropEqualToBoxProp(propAndBox) + isSigmaPropEqualToBoxProp(propAndBox), + validPaymentTokenTransfer )) } @@ -243,7 +245,8 @@ allOf(Coll( (minerFeeBoxOut.value == minerFee), - (blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash) + (blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash), + (minerFeeBoxOut.tokens.size == 0) )) } diff --git a/contracts/v1/ergonames_v1_reveal_proxy.es b/contracts/v1/ergonames_v1_reveal_proxy.es index 580725a..ba3592d 100644 --- a/contracts/v1/ergonames_v1_reveal_proxy.es +++ b/contracts/v1/ergonames_v1_reveal_proxy.es @@ -139,7 +139,8 @@ allOf(Coll( (userPKBoxOut.value == SELF.value - minerFee), - isSigmaPropEqualToBoxProp(propAndBox) + isSigmaPropEqualToBoxProp(propAndBox), + (userPKBoxOut.tokens == SELF.tokens) )) }