#error: Missing signing key for account CONTRACT_ID

48 messages · Page 1 of 1 (latest)

crystal galleon
#

I have two contracts: Vaults and Pool

The Vaults contract allows people locking funds and issue debt, this same contract allows random users to liquidate Vaults that are below the min collateral required and this function starts like this:

    fn liquidate(
        env: Env,
        liquidator: Address,
        denomination: Symbol,
        total_vaults_to_liquidate: u32,
    ) -> Vec<Vault> {
        bump_instance(&env);
        liquidator.require_auth();

Now, there is also the contract Pool where hundreds of people can pool their funds and the contract takes care of liquidating vaults in Vault's contract and then distribute profits to depositors once they remove their positions... Now, since contracts can't trigger themselves someone needs to do it and so this Pool contract has a function to trigger this liquidation process, this function looks like this:

    fn liquidate(env: Env, liquidator: Address) {
        bump_instance(&env);
        liquidator.require_auth();

Now here is the issue, with the latest preview I get the error in the title once someone tries to call the liquidate function in Pool's contract

honest yarrow
#

Okay so can you give me a minimal code example. i'm trying to find the example of how to pass the auth vector in the call

crystal galleon
#

I will update the post details with an example

honest yarrow
#

I am sure I have seen this laid out in the docs somewhere

#

I am struggling to find an example

crystal galleon
#

@honest yarrow I just updated the description with the example

honest yarrow
#

i need to get my laptop out

crystal galleon
#

ok so reading that link, I assume is the authorize_as_curr_contract function the one that needs to be used in contract Pool

#

let me try that

honest yarrow
#

I think so. you want someone to be able to call liquidate on pool which calls the liquidator right?

#

but im slightly confused because it is the user address not the contract that it needs auth on the liquidator

#

i have also been sort of struggling with the authorization stuff it takes me many attempts to get it working properly, but adding that authorize_as_curr_contract fixed the issue i was describing in the other channel which sounds similar

crystal galleon
#

Yeah, it goes like this:
User calls Pool's contract method liquidate -> Pool's contract validates the caller signed the call -> Pool's contract calls Vaults' contract method liquidate -> Vaults' contract checks the caller signed the call -> Vaults' contract calls tokens contracts and do everything

honest yarrow
#

oh look

#

Implementation

auth.rs
file of Soroban host contains the implementation for the authorization framework.

account_contract.rs
file of Soroban host contains the implementation of Stellar account authentication as well as the harness for calling the custom contracts.

#

yes it's very close to what mine is doing obviously all different purposes but

#

the main govenor gets called with execute proposal, which calls the vote to see if the execution is authorized, then that needs to call execute proposal which requires the vote auth not the govenors auth, but actually requires both

#

anyways i'm sorry been sick today and just layin in bed but at some point i'll grab my laptop

#

i wish we could have a runkit like thing for soroban contracts

honest yarrow
#

pool:


fn liquidate(env: Env, liquidator: Address) {
    bump_instance(&env);
    liquidator.require_auth();

    let auth_entry = InvokerContractAuthEntry::Contract(
      SubContractInvocation {
        context: ContractAuthorizationContext {
            contract: env.self_address,  // Pool's contract address
            fn_name: Symbol("liquidate".into()), // Function name
            args: vec![], // Additional arguments, if any
        },
        sub_invocations: vec![], // Further nested authorizations
    });

    authorize_as_curr_contract(vec![auth_entry]);

    // Call Vault's liquidate function
}

#

you will likely need to modify your vault contract to have a list of authorized pools for example though

#

not sure how the vault works but something like that should be how you pass the auth from the contract

#

from what i read you can have more than one auth in this so called auth vector

crystal galleon
#

yeah I just tried that but is not working on local test so I'm not really sure this is the way. I'm reading the rest of the CAP to see if something is missing

honest yarrow
#

it's confusing tbh

#

@white anchor knows about this stuff

#

well i donno if env.self_address is actually a thing btw

#

if you just copy and pasted my example that is more pseudocode than working code

crystal galleon
#

Don't worry, I already did it before you posted it haha, with your code I just confirmed we had a similar idea

honest yarrow
#

als o maybe reove that subinvocations

#

and ake sure to include the args in the vec there

#

ah okay

#

good

#

thinking who else i can tag to help us @lunar yoke wrote the CAP so

honest yarrow
#

While authorization is an essential feature of any smart contract protocol, too often it isn’t given the care and attention it requires. Soroban has consolidated all the learnings from the industry and compiled them into a new and novel authorization framework which ensures that security is both paramount and composable. Don't miss diving into t...

▶ Play video
#

perhaps this will help i'll watch it

crystal galleon
honest yarrow
#

oops sorry pprobably i been calling it a vec

#

do you mind postign your pseudocode solution here 😄

crystal galleon
#

yeah once I solve it I will post the solution here, I first need to test on a network and see if everything is working correctly

#

actually I just confirmed it works with both vec! and a tupple so not really sure why it didn't work the first time I used this tree. So here is the solution for those that might face this in the future:

env.authorize_as_current_contract(vec![
    &env,
    InvokerContractAuthEntry::Contract(SubContractInvocation {
        context: ContractContext {
            contract: core_state.deposit_asset.clone(),
            fn_name: symbol_short!("transfer"),
            args: (
                env.current_contract_address(),
                core_state.vaults_contract.clone(),
                total_debt_to_pay.clone() as i128,
            )
                .into_val(&env),
        },
        sub_invocations: vec![&env] as Vec<InvokerContractAuthEntry>,
    }),
] as Vec<InvokerContractAuthEntry>);

So this authorization is placed in the Pool's contract method liquidate before it calls Vaults' contract method liquidate, the idea is only authorizing the calls that come AFTER the function you are calling IE in this case Pool's contract is authorizing Vaults' contract to call the Asset's contract (the "deposit_asset") transfer function so Vault's contract can move funds from Pool to Vault

#

@honest yarrow ^ that's the solution

honest yarrow
#

Thank you!!!

#

Good Work! Thank you for sharing the solution, been struggling with this issue myself

lunar yoke
#

it looks like the issue I had was that I was using a vec in the args parametter but the example uses a tupple that is then converted into Val
that's just a Vec<Val>. I'm also curious as to why do you need to do (seemingly redundant) as Vec<...> casts. is that just for documentation?

crystal galleon