Based on the following Discord conversion, I believe a token-based approach is better. Thanks, @bluesign for the discussion and design pattern.
[7:35 AM] bluesign*:*
problem there is what is malicious transaction, if you have FungibleToken contract, is it ok if you whitelist withdraw?
[7:37 AM] bluesign*:*
technically your public function is what you whitelisted for use.
[8:53 AM] nduplessis*:*
Agreed, the action needs context
[8:54 AM] nduplessis*:*
When is withdraw safe vs unexpected
@bluesign
problem there is what is malicious transaction, if you have FungibleToken contract, is it ok if you whitelist withdraw?
[8:54 AM] kenhuangus*:*
Malicious transactions are the transactions which explorer a security flaw in your contract and with draw funds. For the FungibleToken, it is a protocol level primitives, you certainly do not want to white list the public functions. The case for white list is for a standalone Dapp which sits on the top of other DeFi or NFT primitives, but no other Dapp will be built on top of it. So, the public function in the Contract inside this Dapp will only be used by this Dapp’s transactions or contract within this DAPP only.
@kenhuangus
Malicious transactions are the transactions which explorer a security flaw in your contract and with draw funds. For the FungibleToken, it is a protocol level primitives, you certainly do not want to white list the public functions. The case for white list is for a standalone Dapp which sits on the top of other DeFi or NFT primitives, but no other Dapp will be built on top of it. So, the public function in the Contract inside this Dapp will only be used by this Dapp’s transactions or contract within this DAPP only.
[8:55 AM] bluesign*:*
But don’t you limit this by exposing a signature. MyFunction takes those parameters, returns this.
[8:56 AM] bluesign*:*
Why you will need to whitelist that part?
[8:56 AM] kenhuangus*:*
So, essentially we need to distinguish two types of Dapps. One is the Dapp which is financial primitives, the pub function shall not have any white list in this case. Another one is stand alone Dapp
[8:56 AM] kenhuangus*:*
white list the caller of the function.
[8:57 AM] bluesign*:*
@kenhuangus can you give one example? It is hard to discuss on theory, like kitty items for example, should whitelist what?
[9:00 AM] kenhuangus*:*
for example whitelist the caller of pub fun removeSaleOffer(saleOfferResourceID: UInt64)
@kenhuangus
for example whitelist the caller of pub fun removeSaleOffer(saleOfferResourceID: UInt64)
[9:02 AM] bluesign*:*
to a transaction hash ? like hash of this: https://github.com/onflow/kitty-items/blob/898c1c3178453d83b9f2fe390d34ff347d147277/cadence/transactions/nftStorefront/remove_item.cdc(edited)
[9:03 AM] kenhuangus*:*
Yes, but this is off chain verification. Correct?
[9:04 AM] bluesign*:*
I mean on-chain solution will use some transaction hash. (caller is transaction)(edited)
[9:04 AM] kenhuangus*:*
Yes, this is what I would like to see happening and could be good for the ecosystem
[9:05 AM] bluesign*:*
So if I am using kitty-items, then I have listed 100 sale offers, you are forcing me to remove them 1 by 1 ?
[9:06 AM] kenhuangus*:*
no. the actual parameter value should not be included in the hash.
[9:06 AM] kenhuangus*:*
only the transaction code hash is calculated and validate on chain or somewhat decentalized fashin
[9:06 AM] bluesign*:*
yeah but I am coming from transaction, so it is kind of allow calls from transaction ?
[9:07 AM] bluesign*:*
cause now I have remove_item.cdc, if I hash this, without parameter, it is still removing one by one
[9:07 AM] kenhuangus*:*
Yes, white list the allowed transactions to my contract pub function in a decentalized way
[9:08 AM] bluesign*:*
now I cannot write something like :
for saleOffer in getMySaleOffers(): removeSaleOffer(saleOffer.id)
[9:08 AM] kenhuangus*:*
You can have another function to removeAll
[9:09 AM] bluesign*:*
yeah the problem is , then you need to cover all possible cases, in advance
[9:09 AM] kenhuangus*:*
white listing the caller should not impede the contract developer to develop pub function. it is just provide a tool
[9:09 AM] bluesign*:*
actually then you don’t even need transactions, basically you have functions on contract
@kenhuangus
white listing the caller should not impede the contract developer to develop pub function. it is just provide a tool
[9:11 AM] bluesign*:*
Yeah the problem is people tend to abuse more than use
@bluesign
now I cannot write something like : for saleOffer in getMySaleOffers(): removeSaleOffer(saleOffer.id)
[9:12 AM] kenhuangus*:*
For this use case, your transaction code can do the loop and add the code hash to the whitelist, you actually do not need to implement removeAll fucntion.
@kenhuangus
For this use case, your transaction code can do the loop and add the code hash to the whitelist, you actually do not need to implement removeAll fucntion.
[9:13 AM] bluesign*:*
yeah but you are the contract, I am the user. You need to whitelist me for this. As I said when you used like this, it is better to expose something like ‘stored procedure’ to users, in the end you say only allowed transactions can use my contract function.(edited)
[9:15 AM] bluesign*:*
Actually my point is: if you have some usage limit in your mind, why not expose this limit as a function ? ( I mean the transaction as a function ) instead of whitelisting transaction
[9:16 AM] kenhuangus*:*
Again, I believe that my point of view is from stand alone Dapp perspective what I have limited transactions to implement for my pub function and I do not want to other project to call into my pub function. And your point (which is also valid ) is from building financial primitives so everyone can use it. Both are ok. But on chain white listing hash verification shall be a good tool and a plus. Correct?
[9:16 AM] bluesign*:*
but another dapp can run your transaction ? if you can somehow blacklist dapp to run your transaction maybe can be good, but if I can run your transaction for me there is no added benefit there. But I think you can manage that currently with cadence crypto already.(edited)
@bluesign
Actually my point is: if you have some usage limit in your mind, why not expose this limit as a function ? ( I mean the transaction as a function ) instead of whitelisting transaction
[9:19 AM] kenhuangus*:*
This is good point and I guess that we need the balance of writing transaction as function vs. a function allow limited use by (internal defined) transactions.
[9:20 AM] bluesign*:*
I think what you want in my opinion is verified calling of a function.
[9:20 AM] kenhuangus*:*
right
[9:22 AM] bluesign*:*
I think some token solution can be better, problem is at whitelist.(edited)
[9:23 AM] kenhuangus*:*
I am intrigued by the token solution. please elaborate?
[9:23 AM] bluesign*:*
it is a bit of off-chain permission to take some action on on-chain.
[9:24 AM] bluesign*:*
so you have a function X with parameters a,b,c :
fun X (a,b,c)
[9:24 AM] bluesign*:*
then you add some token to this function :
[9:24 AM] bluesign*:*
fun X (a,b,c,token)
[9:24 AM] bluesign*:*
here you
token = sign(hash(X . a . b. c ))
[9:25 AM] bluesign*:*
and when you are in X you verify if token signature is valid
[9:27 AM] bluesign*:*
so you can allow/deny off-chain usage of the contract
[9:28 AM] bluesign*:*
I oversimplified though
[9:28 AM] bluesign*:*
but gist of it is like this
[9:28 AM] kenhuangus*:*
yes, I see your point. the token here is a kind of like oAuth token with contract owner’s signature. This is a good design.
[9:30 AM] bluesign*:*
Yeah you can have multi calls in a single token also
[9:30 AM] bluesign*:*
like oauth scopes
[9:31 AM] bluesign*:*
I did implement one time scopes like this on a contract for fun, it is pretty powerful
[9:31 AM] kenhuangus*:*
make sense. It is an excellent security usage pattern for critical pub functions in Cadence contract. I will add this to the checklist and the developer can use this as an optional tool to protect the code.