Check if a box is guarded by a script

Hi devs, I need to check if a box is currently locked (guarded) in a smart contract. I basically need to distinguish when a box comes from a wallet and when it comes from a smart contract. Is there an easy way to do it in ErgoScript? Thanks!
20 Replies
Cheese Enthusiast
Cheese Enthusiast•3y ago
Use the .propositionBytes call on Box's to get the guarding script of the box. Use .propBytes call on SigmaProps to get the propositionBytes of the Sigma Proposition. Then check equality against the proposition bytes of whatever you wish to compare.
MetaMatt
MetaMattOP•3y ago
Hey @Cheese Enthusiast , thanks for the reply! What I need to do is to ensure a Box is currently NOT guarded by a script (so it means it comes from a user utxo). Does a box have .propositionBytes defined only when it's being guarded by a script?
Cheese Enthusiast
Cheese Enthusiast•3y ago
All boxes have scripts, including p2pk / user boxes. Your goal is to check specifically for a p2pk box?
MetaMatt
MetaMattOP•3y ago
Yes, basically it is to avoid the "double spending" attack with a clone contract It's an important vulnerability that in Cardano is addressed ensuring that only 1 input comes from a smart contract (so only the input currently being guarded)
Cheese Enthusiast
Cheese Enthusiast•3y ago
So by this I assume you're talking about having two inputs under the contract you are writing in the same transaction? There is likely an easier way to solve it then to check for p2pk boxes only, but I suppose both ways are fine.
MetaMatt
MetaMattOP•3y ago
not only that, among all the inputs only 1 input must come from a contract. If 2 inputs come from different contracts it should give an error. If all inputs except 1 come from a contract then it should pass I'm still not super expert on Ergo terminology, so I'm not sure p2pk boxes mean they come from smart contracts addresses?
Cheese Enthusiast
Cheese Enthusiast•3y ago
That is a strange notion in Ergo, as everything is a contract here 🙂 P2PK - Pay to Public Key, the type of contract which guards your wallet address. I suppose there are ways to ensure that some of your input boxes are only p2pk / wallet utxos, but to be honest I see very little reason to ever check for this. I would say that doing this is usually unnecessary, and that maybe there is some misunderstanding of how ErgoScript works if you are trying to do this. What vulnerability do you forsee from having potential smart contracts in your inputs? If your smart contract and one of the inputs have conflicting propositions, then the transaction simply won't go through. If the issue is clone contracts, then one simple fix is to check for SELF.id on R4[Coll[Byte]] of OUTPUTS(0) or whichever outputs your specific smart contract is dealing with Adding this check would ensure only one of your contracts would successfully execute. Adding more inputs with the same contract would cause the transaction to fail.
MetaMatt
MetaMattOP•3y ago
Could be, this is why your knowledge is very valuable for me! 🙂 Let me explain with an example: I'm building the typical NFT marketplace. As seller I lock my NFT in a utxo in the marketplace address and if you send me the correct amount of ERG you can buy my NFT. Now another NFT marketplace is there and the same seller creates another NFT listing there. The first smart contract checks that enough ERG are sent to the seller and the second marketplace has the same identical check. This means that an attacker (the buyer) can pay the highest of the 2 amounts and get both listings with 1 transaction. The only way to avoid this is to ensure only 1 input in the tx comes from a smart contract (so you cannot spent 1 listing for each marketplace paying only for the highest listing)
Cheese Enthusiast
Cheese Enthusiast•3y ago
In this case, I would do the check I mentioned above. Lets assume that both contracts are looking at OUTPUTS(0) as the UTXO with ERG being sent to the seller. The check in this case would be the following: OUTPUTS(0).R4[Coll[Byte]].get == SELF.id If both contracts are used as inputs to the transaction, the above condition cannot satisfy both contracts. If the id of the first input is put on OUTPUTS(0), then the second input will evaluate to false. If the id of the second input is put on OUTPUTS(0), then the first input will evaluate to false.
MetaMatt
MetaMattOP•3y ago
That makes sense, so the idea is to use one of the free registers to write down the id of the contract?
Cheese Enthusiast
Cheese Enthusiast•3y ago
Id of the input utxo, but yes. Since the id is unique, it would be impossible to have both contracts be true at the same time.
MetaMatt
MetaMattOP•3y ago
Oh so the first output of the tx must have in R4 the id of the input utxo being guarded
Cheese Enthusiast
Cheese Enthusiast•3y ago
Yep, that's correct
MetaMatt
MetaMattOP•3y ago
That's a very cool solution and probably very clean, unluckily currently I'm already using all the 6 registers for the contract state, so are we 100% sure there's no easy way to distinguish between P2PK and custom smart contracts?
Cheese Enthusiast
Cheese Enthusiast•3y ago
You are using all 6 registers on the output utxo already? There is a way to distinguish between them, you would want to input a standard p2pk contract and use substBytes, I just think it is likely over-complicated and unnecessary in most cases.
MetaMatt
MetaMattOP•3y ago
Yes, because what I'm actually doing is moving a utxo from one SC to another
Cheese Enthusiast
Cheese Enthusiast•3y ago
As for using all 6 registers, you can always use a pair on one of the registers to store an additional data type
MetaMatt
MetaMattOP•3y ago
That's true, that may do the trick 👀
Cheese Enthusiast
Cheese Enthusiast•3y ago
For example if you have R4 of type Int, make it of type (Int, Coll[Byte]) and check for SELF.id == OUTPUTS(0).R4[(Int, Coll[Byte])].get._2 This would just about achieve the same results
MetaMatt
MetaMattOP•3y ago
It makes sense, I will try this way, many thanks @Cheese Enthusiast !

Did you find this page helpful?