Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define producer APIs #17

Merged
merged 13 commits into from
May 2, 2023
Merged

Define producer APIs #17

merged 13 commits into from
May 2, 2023

Conversation

ethanfrey
Copy link
Collaborator

@ethanfrey ethanfrey commented Apr 27, 2023

Part of #2
Closes #3
Closes #4

Provide Rust APIs for how the contracts interact

@ethanfrey ethanfrey changed the title Define producer API Define producer APIs Apr 27, 2023
Copy link
Collaborator

@hashedone hashedone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly ok, but generated messages would contain obsolete _ signed before names.

.editorconfig Outdated Show resolved Hide resolved
.gitignore Show resolved Hide resolved
Cargo.toml Show resolved Hide resolved
contracts/native-staking/src/contract.rs Show resolved Hide resolved
contracts/native-staking/src/contract.rs Outdated Show resolved Hide resolved
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;

/*** state ***/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would personally split this types.rs into state.rs (for state types) and msg.rs (for message-related-types - especially those are actual response messages).

Copy link
Collaborator Author

@ethanfrey ethanfrey Apr 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of agree.. but when I see lots of files of < 30 lines, it seems easier to join.

Can split them later on when they grow.

contracts/vault/src/contract.rs Show resolved Hide resolved
@ethanfrey ethanfrey marked this pull request as ready for review April 28, 2023 10:09
// instantiate or call stake on existing
todo!();
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of want a query to look up my proxy contract if it exists.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question. account seems wrong here, as this proxy handles only one address (that of the owner) over only one chain (that corresponding to denom).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The native-staking contract is a look up between owners and proxy contracts (and visa versa).
It will need to store that state, I will add queries for that

/// TODO: can we do that with contract API?
/// Or better they use cosmjs native delegation queries with this proxy address
#[msg(query)]
fn unbonding(&self, _ctx: QueryCtx, _account: String) -> Result<ClaimsResponse, ContractError> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need the account argument? Only one per contract?

}

/// Returns the maximum percentage that can be slashed
/// TODO: any way to query this from the chain? or we just pass in InstantiateMsg???
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could probably do this with Stargate queries? A bit torn on what to do here... IMO querying it could help reduce edge cases. Perhaps we could make it an enum and have a struct that can handle the query logic?

Just spit-balling here...

pub enum MaxSlashPercentage {
    /// A fixed value, this cannot be changed for the life of the contract
    Hardcoded  { max_slash: Decimal },
   /// Queries the max percentage that can be slashed via Stargate
    StargateQuery { },
}

pub struct MaxSlash {
    max_slash: MaxSlashPercentage
}

impl MaxSlash {
    fn get_max_slash_percentage (&self, ctx: ExecCtx) -> Result<Decimal, ContractError> {
        match self.max_slash {
            // If hardcoded we just return it
            MaxSlashPercentage::HardCoded { max_slash } => Ok(max_slash)
            // If not we do the stargate query
            MaxSlashPercentage::StargateQuery {} => {
                 // do stargate query and return value
            }
        }
    }
}

My hesitation with Stargate Queries is that they wouldn't work for chains using CosmWasm but not the SDK...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StargateQueries don't work for SDK chains either. They have been disabled for over a year since someone found non-determinism in them and halted Juno.

I will leave it as hardcoded for now, and make an issue for v1 to revisit this

}

#[cw_serde]
pub struct BalanceResponse {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit on name, but this is returning more info than just a balance. Maybe AccountResponse and QueryMsg::Account?

Copy link
Collaborator

@JakeHartnell JakeHartnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few minor comments, but this is the right direction from my perspective.

Copy link
Collaborator

@maurolacy maurolacy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Reviewed the native-staking-proxy contract. Will review the rest in another iteration.

@@ -0,0 +1,17 @@
# Native Staking Proxy
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 'proxy' staking contract would be the one referred as 'External Staking' in the Architecture doc, right?

I'll do a small PR on the Arch doc with some clarifications / details.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not yet reflected in that doc. We should probably update the flow charts to include it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just reference "Local Staking" in the doc, which is an interface.

"Native Staking" + "Native Staking Proxy" group would together implement the "Local Staking" functionality.

}
}

/// The caller of the instantiation will be the native-staking contract.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the Architecture doc, the caller will be the vault contract. Can you clarify?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so the way this works is: vault -> native-staking -> native-staking-proxy.

The user story behind this is simple: as a user, I want to cross-stake my native asset as well as stake it to secure the native chain.

Why do we have the proxy? Because we want the user to be able to manage their native-stake just like they would normally (with the ability to vote, etc.). If all assets are sitting in one giant contract, this becomes difficult.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caller of this proxy contract will be the native staking contract.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. It's called 'proxy' because it's an agent that acts on behalf of the user for some actions like unbonding, etc.

Thanks for the clarifications.

&self,
ctx: InstantiateCtx,
denom: String,
owner: String,
Copy link
Collaborator

@maurolacy maurolacy Apr 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this imply one proxy contract per user / address? This would be the original owner / provider of the funds, if I understand correctly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. One proxy contract per user.

Flow:

  1. I deposit 1 $Juno into the vault
  2. I decided to stake it to secure the Juno chain (not cross-staking yet)
  3. A proxy account that I control is created for me where by I will be able to manage my stake

ctx: InstantiateCtx,
denom: String,
owner: String,
validator: String,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed because of auto-staking, below. I think it makes sense for robustness, that any initially sent funds here are already being staked. As this is the entire purpose of this impl.


// set owner as recipient of future withdrawls
let set_withdrawl = DistributionMsg::SetWithdrawAddress {
address: config.parent.into_string(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
address: config.parent.into_string(),
address: config.owner.into_string(),

?

If I understand this properly:

  • sender would (typically) be the vault contract, and becomes parent here.
  • owner would be (typically) set by the vault to the original user, the provider of the funds.

In principle it should be possible to instantiate one of these contracts directly, and that is not a problem. The vault would be just a convenient way to do it, AFAIK.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, typo. And good catch (why we need tests and real implementation). I just started sketching it out

// instantiate or call stake on existing
todo!();
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question. account seems wrong here, as this proxy handles only one address (that of the owner) over only one chain (that corresponding to denom).

Co-authored-by: Mauro Lacy <maurolacy@users.noreply.github.com>
Copy link
Collaborator

@maurolacy maurolacy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Only minor syntax / naming stuff.

@@ -0,0 +1,42 @@
[package]
name = "mesh-native-staking-proxy"
description = "Per-user proxy contract to manage your stake deposited into native-staking"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏼


The user then interacts directly with the proxy up to the point of a complete unbonding, when they can send the now-liquid tokens
to `native-staking`, which will immediately release those on the vault. This makes `native-staking` more a pass-through node and
"air traffic controller", while logic to interact with staking and governance is placed inside the `native-staking-proxy`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏼 Good explanation.

contracts/vault/src/types.rs Outdated Show resolved Hide resolved
Comment on lines +25 to +26
#[error("The leinholder doesn't have any claims")]
UnknownLeinholder,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere, do you mean 'lien'?

Suggested change
#[error("The leinholder doesn't have any claims")]
UnknownLeinholder,
#[error("The lien holder doesn't have any claims")]
UnknownLienholder,

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems leinholder is an actual word from a quick search...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it seems to me that the right or more common expression is 'lien holder'.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mauro is correct. Lien is what I intended:

"a right to keep possession of property belonging to another person until a debt owed by that person is discharged"

Comment on lines +28 to +29
#[error("The leinholder doesn't have enough claims for the action")]
InsufficientLein,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[error("The leinholder doesn't have enough claims for the action")]
InsufficientLein,
#[error("The lien holder doesn't have enough claims for the action")]
InsufficientLien,

Comment on lines +22 to +23
pub struct LeinAddr {
pub leinholder: Addr,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct LeinAddr {
pub leinholder: Addr,
pub struct LienAddr {
pub lien_holder: Addr,

contracts/vault/src/types.rs Outdated Show resolved Hide resolved
Comment on lines +58 to +59
pub struct Lein {
pub leinholder: String,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct Lein {
pub leinholder: String,
pub struct Lien {
pub lien_holder: String,

Co-authored-by: Mauro Lacy <maurolacy@users.noreply.github.com>
@JakeHartnell JakeHartnell merged commit ada7fd9 into main May 2, 2023
@JakeHartnell JakeHartnell deleted the define-producer-apis branch May 2, 2023 20:30
@ethanfrey ethanfrey mentioned this pull request May 3, 2023
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide contract stubs Define all contract interfaces / APIs as Rust Files
4 participants