V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gitandgit
V2EX  ›  区块链

Clarity 智能合约开发语言教程|智能索赔 Smart claimant

  •  
  •   gitandgit · 2021-10-19 13:18:38 +08:00 · 702 次点击
    这是一个创建于 1129 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原英文文档: https://book.clarity-lang.org/ch08-02-smart-claimant.html

    在学习本章节内容时建议已经掌握了上一个章节内容: https://book.clarity-lang.org/ch08-01-time-locked-wallet.html

    智能索赔 Smart claimant

    我们在上一节中创建的时间锁钱包非常简单。但是想象一下,在部署合约程序之后,受益人希望将余额分配给多个不同的受益人。也许它是多年前由一位老亲属部署的,受益人现在想与其他家人分享。不管是什么原因,我们显然不能简单地回去更改或重新部署时间锁钱包程序。在某个时间点它会自动解锁,之后唯一的受益人可以获得钱包的全部余额。如何解决这个问题呢?我们可以创建一个最小化的临时智能合约作为受益人!它将调用 claim 函数,如果成功,则将代币平均分配给列表上的委托人。

    本练习的重点是展示智能合约程序如何相互交互,以及如何增强功能或缓解旧合约程序的问题。

    临时智能合约程序示例

    我们会将 smart-claimant 合约程序添加到现有的时间锁钱包项目中,以便于开发和测试。导航到它并使用 clarinet contract new smart-claimant 添加它。

    在这个例子中,我们假设有四个受益人。我们将采用 Clarinet 配置中定义的钱包地址 1 到 4 。 (如果您的 Clarinet 配置不同,请修改地址如下。)

    +------------------------------------------------------+---------+
    | ST1J4G6RR643BCG8G8SR6M2D9Z9KXT2NJDRK3FBTK (wallet_1) | 1000000 |
    +------------------------------------------------------+---------+
    | ST20ATRN26N9P05V2F1RHFRV24X8C8M3W54E427B2 (wallet_2) | 1000000 |
    +------------------------------------------------------+---------+
    | ST21HMSJATHZ888PD0S0SSTWP4J61TCRJYEVQ0STB (wallet_3) | 1000000 |
    +------------------------------------------------------+---------+
    | ST2QXSK64YQX3CQPC530K79XWQ98XFAM9W3XKEH3N (wallet_4) | 1000000 |
    +------------------------------------------------------+---------+
    
    

    自定义 Claim 函数

    Clarity 非常适合创建小型临时智能合约程序。与其想出一个复杂的机制来添加和删除受益人,还不如把问题简单化,把应该收到一部分余额的人放在同一个房间里,并且钱包即将解锁。他们可以见证当前受益人创建合约程序并直接提供他们的钱包地址。

    该自定义 claim 函数将会:

    • 调用时间锁钱包的 claim 函数,如果失败则退出。

    • 读取当前合约程序的余额。我们不会读取时间锁钱包的余额,因为有人可能已经错误地向 smart-claimant 发送了一些代币。我们也想包括这些代币。

    • 通过将总余额除以接收人数量来计算每个接收人的均等的份额。

    • 将计算出的份额发送给每个接收人。

    • 在出现舍入错误的情况下转移余数。 (请记住,整数没有小数点。)

    把它作为一个单一的 hard-coded 函数进行处理是很容易的。

    (define-public (claim)
        (begin
            (try! (as-contract (contract-call? .timelocked-wallet claim)))
            (let
                (
                    (total-balance (as-contract (stx-get-balance tx-sender)))
                    (share (/ total-balance u4))
                )
                (try! (as-contract (stx-transfer? share tx-sender 'ST1J4G6RR643BCG8G8SR6M2D9Z9KXT2NJDRK3FBTK)))
                (try! (as-contract (stx-transfer? share tx-sender 'ST20ATRN26N9P05V2F1RHFRV24X8C8M3W54E427B2)))
                (try! (as-contract (stx-transfer? share tx-sender 'ST21HMSJATHZ888PD0S0SSTWP4J61TCRJYEVQ0STB)))
                (try! (as-contract (stx-transfer? (stx-get-balance tx-sender) tx-sender 'ST2QXSK64YQX3CQPC530K79XWQ98XFAM9W3XKEH3N)))
                (ok true)
            )
        )
    )
    
    

    可以看出。保护 claim 函数是不必要的,因为接收人是硬编码的。如果任何一个代币传输失败,则整个调用将会被恢复。 (想知道如何减少上面看到的重复代码吗?您可以在最佳实践的章节中找到一些提示和技巧。)

    单元测试

    smart-claimant 并不关心时间锁钱包会出错的原因。因此,我们只需要考虑一个成功转账的状态。

    Clarinet.test({
        name: "Disburses tokens once it can claim the time-locked wallet balance",
        async fn(chain: Chain, accounts: Map<string, Account>) {
            const deployer = accounts.get('deployer')!;
            const beneficiary = `${deployer.address}.smart-claimant`;
            const wallet1 = accounts.get('wallet_1')!;
            const wallet2 = accounts.get('wallet_2')!;
            const wallet3 = accounts.get('wallet_3')!;
            const wallet4 = accounts.get('wallet_4')!;
            const unlock_height = 10;
            const amount = 1000; // be sure to pick a test amount that is divisible by 4 for this test.
            const share = Math.floor(amount / 4);
            chain.mineBlock([
                Tx.contractCall('timelocked-wallet', 'lock', [types.principal(beneficiary), types.uint(unlock_height), types.uint(amount)], deployer.address)
            ]);
            chain.mineEmptyBlockUntil(unlock_height);
            const block = chain.mineBlock([
                Tx.contractCall('smart-claimant', 'claim', [], deployer.address)
            ]);
    
            // Take the first receipt.
            const [receipt] = block.receipts;
            // The claim should be successful.
            receipt.result.expectOk().expectBool(true);
    
            // All wallets should have received their share.
            receipt.events.expectSTXTransferEvent(share, beneficiary, wallet1.address);
            receipt.events.expectSTXTransferEvent(share, beneficiary, wallet2.address);
            receipt.events.expectSTXTransferEvent(share, beneficiary, wallet3.address);
            receipt.events.expectSTXTransferEvent(share, beneficiary, wallet4.address);
        }
    });
    
    

    该项目的完整源代码可以在这里找到: https://github.com/clarity-lang/book/tree/main/projects/timelocked-wallet

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3031 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 12:56 · PVG 20:56 · LAX 04:56 · JFK 07:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.