Skip to content

Commit

Permalink
feat(contracts): add rewards staking example (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
aelesbao authored Oct 12, 2023
2 parents 08aa855 + 2b41715 commit 7e1cd26
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 107 deletions.
4 changes: 4 additions & 0 deletions .archway/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"chain-id": "constantine-3",
"contracts-path": "./contracts"
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ artifacts/
.vscode/
.idea/
*.iml

# Local network history
.archway/local-1.json
11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ members = ["packages/*", "contracts/*"]
resolver = "2"

[profile.release]
rpath = false
lto = true
overflow-checks = true
opt-level = 3
codegen-units = 1
debug = false
debug-assertions = false
incremental = false
lto = true
opt-level = 3
overflow-checks = true
panic = 'abort'
rpath = false

[workspace.dependencies]
cosmwasm-schema = "1.4.0"
Expand Down
45 changes: 0 additions & 45 deletions contracts/increment/config.json

This file was deleted.

86 changes: 60 additions & 26 deletions contracts/increment/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
use archway_bindings::types::gov::VoteResponse;
use archway_bindings::types::rewards::{
ContractMetadataResponse, FlatFeeResponse, RewardsRecordsResponse, WithdrawRewardsResponse,
};
use archway_bindings::{ArchwayMsg, ArchwayQuery, ArchwayResult, PageRequest};
use cosmwasm_std::{
coin, entry_point, to_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response,
StdError, StdResult, SubMsg, Uint128,
StakingMsg, StdError, StdResult, SubMsg, Uint128,
};
use cw2::set_contract_version;
use cw_utils::NativeBalance;

use archway_bindings::types::gov::VoteResponse;
use archway_bindings::types::rewards::{
ContractMetadataResponse, FlatFeeResponse, RewardsRecordsResponse, WithdrawRewardsResponse,
};
use archway_bindings::{ArchwayMsg, ArchwayQuery, ArchwayResult, PageRequest};

use crate::error::ContractError;
use crate::helpers;
use crate::msg::{CountResponse, ExecuteMsg, InstantiateMsg, OutstandingRewardsResponse, QueryMsg};
use crate::state::{State, STATE};
use crate::state::{State, STAKE_REWARDS_VALIDATOR, STATE};

// version info for migration info
const CONTRACT_NAME: &str = "crates.io:increment";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

const REWARDS_WITHDRAW_REPLY: u64 = 1001;
const STAKE_WITHDRAWN_REWARDS: u64 = 1001;

#[entry_point]
pub fn instantiate(
Expand Down Expand Up @@ -57,7 +58,9 @@ pub fn execute(
ExecuteMsg::SetFlatFee { amount } => {
set_flat_fee(deps.as_ref(), env.contract.address, amount)
}
ExecuteMsg::WithdrawRewards {} => withdraw_rewards(),
ExecuteMsg::WithdrawRewards { stake_to_validator } => {
withdraw_rewards(deps, env, stake_to_validator)
}
}
}

Expand Down Expand Up @@ -115,43 +118,73 @@ fn set_flat_fee(
Ok(res)
}

fn withdraw_rewards() -> ArchwayResult<ContractError> {
fn withdraw_rewards(
deps: DepsMut<ArchwayQuery>,
env: Env,
stake_to_validator: Option<Addr>,
) -> ArchwayResult<ContractError> {
let msg = ArchwayMsg::withdraw_rewards_by_limit(0);
let withdraw_rewards_msg = if let Some(validator_addr) = stake_to_validator {
let tx_index = env.transaction.map(|tx| tx.index).unwrap_or(0);
STAKE_REWARDS_VALIDATOR.save(
deps.storage,
(env.block.height, tx_index),
&validator_addr,
)?;
SubMsg::reply_always(msg, STAKE_WITHDRAWN_REWARDS)
} else {
SubMsg::new(msg)
};

let res = Response::new()
.add_submessage(SubMsg::reply_on_success(msg, REWARDS_WITHDRAW_REPLY))
.add_submessage(withdraw_rewards_msg)
.add_attribute("method", "withdraw_rewards");

Ok(res)
}

#[entry_point]
pub fn reply(deps: DepsMut<ArchwayQuery>, _env: Env, msg: Reply) -> StdResult<Response> {
pub fn reply(deps: DepsMut<ArchwayQuery>, env: Env, msg: Reply) -> StdResult<Response> {
match msg.id {
REWARDS_WITHDRAW_REPLY => after_rewards_withdrawn(deps, msg),
STAKE_WITHDRAWN_REWARDS => stake_contract_rewards(deps, env, msg),
id => Err(StdError::not_found(format!("Unknown reply id: {}", id))),
}
}

fn after_rewards_withdrawn(_deps: DepsMut<ArchwayQuery>, msg: Reply) -> StdResult<Response> {
fn stake_contract_rewards(
deps: DepsMut<ArchwayQuery>,
env: Env,
msg: Reply,
) -> StdResult<Response> {
let tx_index = env.transaction.map(|tx| tx.index).unwrap_or(0);
let validator_addr =
STAKE_REWARDS_VALIDATOR.load(deps.storage, (env.block.height, tx_index))?;

STAKE_REWARDS_VALIDATOR.remove(deps.storage, (env.block.height, tx_index));

let data = helpers::parse_reply_data(msg)?;
let withdraw_response: WithdrawRewardsResponse =
serde_json_wasm::from_slice::<WithdrawRewardsResponse>(&data.0)
.map_err(|e| StdError::generic_err(e.to_string()))?;

let mut rewards_balance = NativeBalance(withdraw_response.total_rewards);
rewards_balance.normalize();

let total_rewards: Vec<String> = rewards_balance
.into_vec()
let staking_denom = deps.querier.query_bonded_denom()?;
let rewards_amount = withdraw_response
.total_rewards
.iter()
.map(|coin| coin.to_string())
.collect();
.find(|coin| coin.denom == staking_denom)
.ok_or_else(|| StdError::generic_err("Could not find coin with staking denom"))?;

let staking_msg = StakingMsg::Delegate {
validator: validator_addr.to_string(),
amount: rewards_amount.clone(),
};

let res = Response::new()
.add_attribute("method", "after_rewards_withdrawn")
.add_message(staking_msg)
.add_attribute("method", "stake_withdrawn_rewards")
.add_attribute("records_num", withdraw_response.records_num.to_string())
.add_attribute("total_rewards", total_rewards.concat());
.add_attribute("staked_rewards", rewards_amount.to_string())
.add_attribute("validator", validator_addr);

Ok(res)
}
Expand Down Expand Up @@ -232,13 +265,14 @@ fn gov_vote(

#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{coins, from_binary, ContractResult, QueryResponse};

use archway_bindings::testing::{mock_dependencies, mock_dependencies_with_balance};
use archway_bindings::types::rewards::RewardsRecord;
use archway_bindings::PageResponse;

use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{coins, from_binary, ContractResult, QueryResponse};
use super::*;

#[test]
fn proper_initialization() {
Expand Down
2 changes: 1 addition & 1 deletion contracts/increment/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub enum ExecuteMsg {
Reset { count: i32 },
UpdateRewardsAddress { rewards_address: Option<Addr> },
SetFlatFee { amount: Uint128 },
WithdrawRewards {},
WithdrawRewards { stake_to_validator: Option<Addr> },
}

#[cw_serde]
Expand Down
4 changes: 3 additions & 1 deletion contracts/increment/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use cosmwasm_std::Addr;
use cw_storage_plus::Item;
use cw_storage_plus::{Item, Map};

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
Expand All @@ -11,3 +11,5 @@ pub struct State {
}

pub const STATE: Item<State> = Item::new("state");
// Map with key (block height, tx index) and value validator address
pub const STAKE_REWARDS_VALIDATOR: Map<(u64, u32), Addr> = Map::new("stake_rewards_validator");
39 changes: 17 additions & 22 deletions scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,35 @@
set -euo pipefail

SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
ROOT_DIR="$(dirname "${SCRIPT_DIR}")"

echo ":: Build"
archway build --optimize
CHAIN_ID="${CHAIN_ID:-constantine-3}"

pushd ${SCRIPT_DIR}/../contracts/increment
echo ":: Build"
#archway contracts build

echo ""
echo ":: Switching network"
archway network -m -e 'local'
archway config chains use "${CHAIN_ID}"

echo ""
echo ":: Store"
archway store --from alice --no-confirm --no-verify
archway contracts store increment --from deployer --no-confirm

echo ""
echo ":: Instantiate"
archway instantiate --no-confirm --from alice --default-label --args '{ "count": 0 }'

# CONTRACT_ADDRESS="$(jq -r '[.developer.deployments[] | select(.type == "instantiate")] | .[0].address' config.json)"
archway contracts instantiate increment --from deployer --no-confirm --skip-validation --args '{ "count": 0 }'

# echo ""
# echo ":: Metadata"
# archway metadata --no-confirm --from alice \
# --owner-address "${CONTRACT_ADDRESS}" \
# --rewards-address "${CONTRACT_ADDRESS}"

# echo ""
# echo ":: Increment"
# archway tx --no-confirm --from alice --args '{ "increment": {} }'
CONTRACT_ADDRESS="$(jq -r '[.deployments[] | select(.action == "instantiate")] | .[0].contract.address' "${ROOT_DIR}/.archway/${CHAIN_ID}.json")"

echo ""
echo ":: Get proposals"
archway query contract-state smart --args '{ "gov_proposals": {} }'
archway query contract-state smart --args '{ "gov_vote": { "proposal_id": 1, "voter": "archway1qfj2k2al6wvyp7fghtw70exv8dlw2lykutcg2x" } }'
echo ":: Metadata"
archway contracts metadata increment --from deployer --no-confirm --owner-address "${CONTRACT_ADDRESS}" --rewards-address "${CONTRACT_ADDRESS}"

git checkout config.json
echo ""
echo ":: Increment"
archway contracts execute increment --from deployer --no-confirm --skip-validation --args '{ "increment": {} }' --gas-adjustment 1.4

popd
echo ""
echo ":: Get Rewards"
archway rewards query "${CONTRACT_ADDRESS}"
8 changes: 0 additions & 8 deletions scripts/optimize.sh

This file was deleted.

0 comments on commit 7e1cd26

Please sign in to comment.