Skip to content

[Bug] Interfaces in submodules not working properly with record inputs #29285

@AleoAlexander

Description

@AleoAlexander

🐛 Bug Report

Source Code

src/iarc20.leo

interface ARC20 {
    mapping balances: address => u128;
    record Token;

    fn transfer_public(public recipient: address, public amount: u128) -> Final;
    fn transfer_private(input: Token, recipient: address, amount: u128) -> (Token, Token);
    fn transfer_private_to_public(input: Token, recipient: address, amount: u128) -> (Token, Final);
    fn transfer_public_to_private(recipient: address, public amount: u128) -> (Token, Final);
    fn transfer_public_as_signer(public recipient: address, public amount: u128) -> Final;
    fn shield(public amount: u128) -> (Token, Final);
    fn unshield(input: Token, amount: u128) -> (Token, Final);
}

src/arc20.leo

// The 'arc20' program.
program arc20.aleo: iarc20::ARC20 {
    mapping balances: address => u128;
    record Token {
        owner: address,
        balance: u128
    }

    fn transfer_public(public recipient: address, public amount: u128) -> Final {
        let sender: address = self.caller;
        return final {
            let sender_balance: u128 = balances.get_or_use(sender, 0u128);
            let recipient_balance: u128 = balances.get_or_use(recipient, 0u128);

            balances.set(sender, sender_balance - amount);
            balances.set(recipient, recipient_balance + amount);
        };
    }
    fn transfer_private(input: Token, recipient: address, amount: u128) -> (Token, Token) {
        let transfer: Token = Token { owner: recipient, balance: amount};
        let change: Token = Token {owner: input.owner, balance: input.balance - amount};
        
        return (transfer, change);
    }
    fn transfer_private_to_public(input: Token, recipient: address, amount: u128) -> (Token, Final){
        let change: Token = Token {owner: input.owner, balance: input.balance - amount};
        return (change, final {
            let recipient_balance: u128 = balances.get_or_use(recipient, 0u128);
            balances.set(recipient, recipient_balance + amount);
        });
    }
    fn transfer_public_to_private(recipient: address, public amount: u128) -> (Token, Final) {
        let sender: address = self.caller;
        let transfer: Token = Token { owner: recipient, balance: amount};

        return (transfer,final {
            let sender_balance: u128 = balances.get_or_use(sender, 0u128);

            balances.set(sender, sender_balance - amount);
        });
    }
    fn transfer_public_as_signer(public recipient: address, public amount: u128) -> Final {
        let sender: address = self.signer;
        return final {
            let sender_balance: u128 = balances.get_or_use(sender, 0u128);
            let recipient_balance: u128 = balances.get_or_use(recipient, 0u128);

            balances.set(sender, sender_balance - amount);
            balances.set(recipient, recipient_balance + amount);
        };
    }
    fn shield(public amount: u128) -> (Token, Final){
        let user: address = self.signer;
        let transfer: Token = Token { owner: user, balance: amount};

        return (transfer,final {
            let sender_balance: u128 = balances.get_or_use(user, 0u128);

            balances.set(user, sender_balance - amount);
        });
    } 
    fn unshield(input: Token, amount: u128) -> (Token, Final) {
        let user = input.owner;
        let change: Token = Token {owner: user, balance: input.balance - amount};
        return (change, final {
            let recipient_balance: u128 = balances.get_or_use(user, 0u128);
            balances.set(user, recipient_balance + amount);
        });
    }

    // Change to desired constructor pattern
    @noupgrade
    constructor() {}

}

Errors

Error [ECHI03712004]: Function `transfer_private` does not match the signature required by interface `arc20.aleo/iarc20::ARC20`.
Expected:
fn transfer_private(input: arc20.aleo::Token, recipient: address, amount: u128) -> (arc20.aleo::Token, arc20.aleo::Token)
Found:
fn transfer_private(input: arc20.aleo::Token, recipient: address, amount: u128) -> (arc20.aleo::Token, arc20.aleo::Token)

Error [ECHI03712004]: Function `transfer_private_to_public` does not match the signature required by interface `arc20.aleo/iarc20::ARC20`.
Expected:
fn transfer_private_to_public(input: arc20.aleo::Token, recipient: address, amount: u128) -> (arc20.aleo::Token, Final<Fn()>)
Found:
fn transfer_private_to_public(input: arc20.aleo::Token, recipient: address, amount: u128) -> (arc20.aleo::Token, Final<Fn()>)

Error [ECHI03712004]: Function `transfer_public_to_private` does not match the signature required by interface `arc20.aleo/iarc20::ARC20`.
Expected:
fn transfer_public_to_private(recipient: address, amount: u128) -> (arc20.aleo::Token, Final<Fn()>)
Found:
fn transfer_public_to_private(recipient: address, amount: u128) -> (arc20.aleo::Token, Final<Fn()>)

Error [ECHI03712004]: Function `shield` does not match the signature required by interface `arc20.aleo/iarc20::ARC20`.
Expected:
fn shield(amount: u128) -> (arc20.aleo::Token, Final<Fn()>)
Found:
fn shield(amount: u128) -> (arc20.aleo::Token, Final<Fn()>)

Error [ECHI03712004]: Function `unshield` does not match the signature required by interface `arc20.aleo/iarc20::ARC20`.
Expected:
fn unshield(input: arc20.aleo::Token, amount: u128) -> (arc20.aleo::Token, Final<Fn()>)
Found:
fn unshield(input: arc20.aleo::Token, amount: u128) -> (arc20.aleo::Token, Final<Fn()>)

Initial Diagnosis

This seems to specific to functions in the interface that take in records. Not sure if this is related to the dyn record issues we were running into before, or if this is a separate issue.

Note: Everything compiles fine if I move the interface into the same file as the implementation.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions