跨模块通过install-capability安装managed capability是否可行
问题
是否可在不对交易数据中的capability进行签名的前提下,在定义某managed capability的模块外部安装该能力?
场景说明
需要在自定义模块实现的函数中调用coin.transfer-create,完成模块控制账户向用户账户的转账操作,该函数受coin.TRANSFER managed capability的权限保护。
- 若交易签名时在capabilities列表中声明
coin.TRANSFERcapability,即可正常调用内部会触发coin.transfer-create的自定义模块函数。 - 目标实现效果:任意用户账户都可向模块账户申领KDA,无需用户在交易的capabilities列表中提供
coin.TRANSFERcapability(用户并不掌握模块账户的私钥,该合约仅部署用于测试网)。
测试时使用的实现逻辑如下,在REPL环境运行触发keyset failure报错:
(defun my-fn (user-account:string amount:decimal) ; install the capability, without relying on it being in the capabilities list (install-capability (coin.TRANSFER "contract-account" user-account amount)) ; grant the capability (with-capability (coin.TRANSFER "contract-account" user-account amount) <execute transfer>))
解答
不可以在定义managed capability的模块外部,通过install-capability接口安装该能力绕过签名校验,你遇到的keyset failure是合约权限机制的正常表现:
install-capability仅对定义目标capability的模块内部调用生效,外部模块调用该接口无法获得对应capability的授予权限,该设计的核心目的就是防止跨模块越权绕过内置的权限校验逻辑。coin.TRANSFER是coin模块定义的托管capability,默认会校验转出账户的守卫权限,你在自定义模块中直接调用install-capability安装coin.TRANSFER属于跨模块无效调用,执行到with-capability逻辑时依然会触发转出账户的keyset校验,没有对应签名就会抛出错误。
要实现测试网任意用户无签名申领KDA的领水功能,不需要强行跨模块安装capability,正确实现路径如下:
- 不要使用普通keyset守卫创建合约控制的账户,改用模块principal作为账户守卫,即通过
(create-principal (my-contract.module-hash))生成模块专属principal作为账户的守卫规则。 - 当转出账户的守卫是你的自定义模块时,只要转账逻辑在你的自定义模块内部执行,coin模块会自动认可模块守卫的权限,不需要交易签名额外声明
coin.TRANSFERcapability,也不需要用户持有模块账户私钥,任意用户调用你公开的申领函数即可完成转账。
内容的提问来源于stack exchange,提问作者trh
相关产品推荐
相关产品推荐

