"program credits.aleo;\n\nmapping committee:\n    key as address.public;\n    value as committee_state.public;\n\nstruct committee_state:\n    is_open as boolean;\n    commission as u8;\n\nmapping delegated:\n    key as address.public;\n    value as u64.public;\n\nmapping metadata:\n    key as address.public;\n    value as u32.public;\n\nmapping bonded:\n    key as address.public;\n    value as bond_state.public;\n\nstruct bond_state:\n    validator as address;\n    microcredits as u64;\n\nmapping unbonding:\n    key as address.public;\n    value as unbond_state.public;\n\nstruct unbond_state:\n    microcredits as u64;\n    height as u32;\n\nmapping account:\n    key as address.public;\n    value as u64.public;\n\nmapping withdraw:\n    key as address.public;\n    value as address.public;\n\nmapping pool:\n    key as address.public;\n    value as u64.public;\n\nrecord credits:\n    owner as address.private;\n    microcredits as u64.private;\n\nfunction bond_validator:\n    input r0 as address.public;\n    input r1 as u64.public;\n    input r2 as u8.public;\n    assert.neq self.signer r0;\n    gte r1 1_000_000u64 into r3;\n    assert.eq r3 true;\n    gt r2 100u8 into r4;\n    assert.neq r4 true;\n    async bond_validator self.signer r0 r1 r2 into r5;\n    output r5 as credits.aleo/bond_validator.future;\n\nfinalize bond_validator:\n    input r0 as address.public;\n    input r1 as address.public;\n    input r2 as u64.public;\n    input r3 as u8.public;\n    get.or_use withdraw[r0] r1 into r4;\n    assert.eq r1 r4;\n    cast true r3 into r5 as committee_state;\n    get.or_use committee[r0] r5 into r6;\n    assert.eq r3 r6.commission;\n    cast r0 0u64 into r7 as bond_state;\n    get.or_use bonded[r0] r7 into r8;\n    assert.eq r8.validator r0;\n    add r8.microcredits r2 into r9;\n    cast r0 r9 into r10 as bond_state;\n    get.or_use delegated[r0] 0u64 into r11;\n    add r2 r11 into r12;\n    gte r12 10_000_000_000_000u64 into r13;\n    assert.eq r13 true;\n    get account[r0] into r14;\n    sub r14 r2 into r15;\n    contains committee[r0] into r16;\n    branch.eq r16 true to validator_in_committee;\n        set r4 into withdraw[r0];\n        gte r2 100_000_000u64 into r17;\n        assert.eq r17 true;\n        get.or_use metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc] 0u32 into r18;\n        add r18 1u32 into r19;\n        set r19 into metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc];\n        contains unbonding[r0] into r20;\n        assert.eq r20 false;\n    position validator_in_committee;\n    set r6 into committee[r0];\n    set r12 into delegated[r0];\n    set r10 into bonded[r0];\n    set r15 into account[r0];\n\nfunction bond_public:\n    input r0 as address.public;\n    input r1 as address.public;\n    input r2 as u64.public;\n    gte r2 1_000_000u64 into r3;\n    assert.eq r3 true;\n    assert.neq self.caller r0;\n    async bond_public self.caller r0 r1 r2 into r4;\n    output r4 as credits.aleo/bond_public.future;\n\nfinalize bond_public:\n    input r0 as address.public;\n    input r1 as address.public;\n    input r2 as address.public;\n    input r3 as u64.public;\n    get.or_use withdraw[r0] r2 into r4;\n    assert.eq r2 r4;\n    contains bonded[r0] into r5;\n    branch.eq r5 true to continue_bond_delegator;\n        set r2 into withdraw[r0];\n        cast true 0u8 into r6 as committee_state;\n        get.or_use committee[r1] r6 into r7;\n        assert.eq r7.is_open true;\n        get.or_use metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0] 0u32 into r8;\n        add r8 1u32 into r9;\n        lte r9 100_000u32 into r10;\n        assert.eq r10 true;\n        set r9 into metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0];\n    position continue_bond_delegator;\n    cast r1 0u64 into r11 as bond_state;\n    get.or_use bonded[r0] r11 into r12;\n    assert.eq r12.validator r1;\n    add r12.microcredits r3 into r13;\n    gte r13 10_000_000_000u64 into r14;\n    assert.eq r14 true;\n    cast r1 r13 into r15 as bond_state;\n    get account[r0] into r16;\n    sub r16 r3 into r17;\n    get.or_use delegated[r1] 0u64 into r18;\n    add r3 r18 into r19;\n    contains unbonding[r1] into r20;\n    assert.eq r20 false;\n    set r15 into bonded[r0];\n    set r17 into account[r0];\n    set r19 into delegated[r1];\n\nfunction unbond_public:\n    input r0 as address.public;\n    input r1 as u64.public;\n    async unbond_public self.caller r0 r1 into r2;\n    output r2 as credits.aleo/unbond_public.future;\n\nfinalize unbond_public:\n    input r0 as address.public;\n    input r1 as address.public;\n    input r2 as u64.public;\n    add block.height 360u32 into r3;\n    cast 0u64 r3 into r4 as unbond_state;\n    get bonded[r1] into r5;\n    get withdraw[r1] into r6;\n    is.eq r0 r6 into r7;\n    contains withdraw[r5.validator] into r8;\n    get.or_use withdraw[r5.validator] aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc into r9;\n    is.eq r0 r9 into r10;\n    and r8 r10 into r11;\n    or r7 r11 into r12;\n    assert.eq r12 true;\n    is.eq r5.validator r1 into r13;\n    branch.eq r13 true to unbond_validator;\n        get.or_use unbonding[r1] r4 into r14;\n        get delegated[r5.validator] into r15;\n        sub r5.microcredits r2 into r16;\n        lt r16 10_000_000_000u64 into r17;\n        or r11 r17 into r18;\n        ternary r18 r5.microcredits r2 into r19;\n        add r14.microcredits r19 into r20;\n        cast r20 r3 into r21 as unbond_state;\n        set r21 into unbonding[r1];\n        sub r15 r19 into r22;\n        set r22 into delegated[r5.validator];\n        branch.eq r18 true to remove_delegator;\n            cast r5.validator r16 into r23 as bond_state;\n            set r23 into bonded[r1];\n            branch.eq true true to end_unbond_delegator;\n        position remove_delegator;\n            remove bonded[r1];\n            get metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0] into r24;\n            sub r24 1u32 into r25;\n            set r25 into metadata[aleo1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqanmpl0];\n        position end_unbond_delegator;\n            gte r22 10_000_000_000_000u64 into r26;\n            branch.eq r26 true to end;\n    position unbond_validator;\n        contains committee[r5.validator] into r27;\n        nor r13 r27 into r28;\n        branch.eq r28 true to end;\n        get committee[r5.validator] into r29;\n        get bonded[r5.validator] into r30;\n        get delegated[r5.validator] into r31;\n        lt r31 10_000_000_000_000u64 into r32;\n        branch.eq r32 true to remove_validator;\n        sub r31 r2 into r33;\n        sub r30.microcredits r2 into r34;\n        gte r34 100_000_000u64 into r35;\n        gte r33 10_000_000_000_000u64 into r36;\n        and r35 r36 into r37;\n        branch.eq r37 false to remove_validator;\n        get.or_use unbonding[r5.validator] r4 into r38;\n        add r38.microcredits r2 into r39;\n        cast r39 r3 into r40 as unbond_state;\n        set r40 into unbonding[r5.validator];\n        set r33 into delegated[r5.validator];\n        cast r5.validator r34 into r41 as bond_state;\n        set r41 into bonded[r5.validator];\n        branch.eq true true to end;\n    position remove_validator;\n        remove committee[r5.validator];\n        get metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc] into r42;\n        sub r42 1u32 into r43;\n        set r43 into metadata[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc];\n        sub r31 r30.microcredits into r44;\n        set r44 into delegated[r5.validator];\n        remove bonded[r5.validator];\n        get.or_use unbonding[r5.validator] r4 into r45;\n        add r30.microcredits r45.microcredits into r46;\n        cast r46 r3 into r47 as unbond_state;\n        set r47 into unbonding[r5.validator];\n    position end;\n\nfunction claim_unbond_public:\n    input r0 as address.public;\n    async claim_unbond_public r0 into r1;\n    output r1 as credits.aleo/claim_unbond_public.future;\n\nfinalize claim_unbond_public:\n    input r0 as address.public;\n    get unbonding[r0] into r1;\n    gte block.height r1.height into r2;\n    assert.eq r2 true;\n    get withdraw[r0] into r3;\n    get.or_use account[r3] 0u64 into r4;\n    add r1.microcredits r4 into r5;\n    set r5 into account[r3];\n    remove unbonding[r0];\n    contains bonded[r0] into r6;\n    branch.eq r6 true to end;\n    remove withdraw[r0];\n    position end;\n\nfunction set_validator_state:\n    input r0 as boolean.public;\n    async set_validator_state self.caller r0 into r1;\n    output r1 as credits.aleo/set_validator_state.future;\n\nfinalize set_validator_state:\n    input r0 as address.public;\n    input r1 as boolean.public;\n    get committee[r0] into r2;\n    cast r1 r2.commission into r3 as committee_state;\n    set r3 into committee[r0];\n\nfunction transfer_public:\n    input r0 as address.public;\n    input r1 as u64.public;\n    async transfer_public self.caller r0 r1 into r2;\n    output r2 as credits.aleo/transfer_public.future;\n\nfinalize transfer_public:\n    input r0 as address.public;\n    input r1 as address.public;\n    input r2 as u64.public;\n    get account[r0] into r3;\n    sub r3 r2 into r4;\n    set r4 into account[r0];\n    get.or_use account[r1] 0u64 into r5;\n    add r5 r2 into r6;\n    set r6 into account[r1];\n\nfunction transfer_public_as_signer:\n    input r0 as address.public;\n    input r1 as u64.public;\n    async transfer_public_as_signer self.signer r0 r1 into r2;\n    output r2 as credits.aleo/transfer_public_as_signer.future;\n\nfinalize transfer_public_as_signer:\n    input r0 as address.public;\n    input r1 as address.public;\n    input r2 as u64.public;\n    get account[r0] into r3;\n    sub r3 r2 into r4;\n    set r4 into account[r0];\n    get.or_use account[r1] 0u64 into r5;\n    add r5 r2 into r6;\n    set r6 into account[r1];\n\nfunction transfer_private:\n    input r0 as credits.record;\n    input r1 as address.private;\n    input r2 as u64.private;\n    sub r0.microcredits r2 into r3;\n    cast r1 r2 into r4 as credits.record;\n    cast r0.owner r3 into r5 as credits.record;\n    output r4 as credits.record;\n    output r5 as credits.record;\n\nfunction transfer_private_to_public:\n    input r0 as credits.record;\n    input r1 as address.public;\n    input r2 as u64.public;\n    sub r0.microcredits r2 into r3;\n    cast r0.owner r3 into r4 as credits.record;\n    async transfer_private_to_public r1 r2 into r5;\n    output r4 as credits.record;\n    output r5 as credits.aleo/transfer_private_to_public.future;\n\nfinalize transfer_private_to_public:\n    input r0 as address.public;\n    input r1 as u64.public;\n    get.or_use account[r0] 0u64 into r2;\n    add r1 r2 into r3;\n    set r3 into account[r0];\n\nfunction transfer_public_to_private:\n    input r0 as address.private;\n    input r1 as u64.public;\n    cast r0 r1 into r2 as credits.record;\n    async transfer_public_to_private self.caller r1 into r3;\n    output r2 as credits.record;\n    output r3 as credits.aleo/transfer_public_to_private.future;\n\nfinalize transfer_public_to_private:\n    input r0 as address.public;\n    input r1 as u64.public;\n    get account[r0] into r2;\n    sub r2 r1 into r3;\n    set r3 into account[r0];\n\nfunction join:\n    input r0 as credits.record;\n    input r1 as credits.record;\n    add r0.microcredits r1.microcredits into r2;\n    cast r0.owner r2 into r3 as credits.record;\n    output r3 as credits.record;\n\nfunction split:\n    input r0 as credits.record;\n    input r1 as u64.private;\n    sub r0.microcredits r1 into r2;\n    sub r2 10_000u64 into r3;\n    cast r0.owner r1 into r4 as credits.record;\n    cast r0.owner r3 into r5 as credits.record;\n    output r4 as credits.record;\n    output r5 as credits.record;\n\nfunction fee_private:\n    input r0 as credits.record;\n    input r1 as u64.public;\n    input r2 as u64.public;\n    input r3 as field.public;\n    assert.neq r1 0u64;\n    assert.neq r3 0field;\n    add r1 r2 into r4;\n    sub r0.microcredits r4 into r5;\n    cast r0.owner r5 into r6 as credits.record;\n    output r6 as credits.record;\n\nfunction fee_public:\n    input r0 as u64.public;\n    input r1 as u64.public;\n    input r2 as field.public;\n    assert.neq r0 0u64;\n    assert.neq r2 0field;\n    add r0 r1 into r3;\n    async fee_public self.signer r3 into r4;\n    output r4 as credits.aleo/fee_public.future;\n\nfinalize fee_public:\n    input r0 as address.public;\n    input r1 as u64.public;\n    get account[r0] into r2;\n    sub r2 r1 into r3;\n    set r3 into account[r0];\n\nfunction upgrade:\n    input r0 as credits.record;\n    lte r0.microcredits 1_000_000_000_000u64 into r1;\n    assert.eq r1 true;\n    cast r0.owner r0.microcredits into r2 as credits.record;\n    async upgrade r0.microcredits into r3;\n    output r2 as credits.record;\n    output r3 as credits.aleo/upgrade.future;\n\nfinalize upgrade:\n    input r0 as u64.public;\n    get.or_use pool[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc] 0u64 into r1;\n    add r1 r0 into r2;\n    lte r2 4_000_000_000_000u64 into r3;\n    assert.eq r3 true;\n    set r2 into pool[aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc];"