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

fix: claim rewards #4

Merged
merged 1 commit into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
"contract/valory/uniswap_v3_non_fungible_position_manager/0.1.0": "bafybeieljamerttxyo7z2yokwripnnhzkn4zply5lz457vsixf5wfu5px4",
"contract/valory/uniswap_v3_pool/0.1.0": "bafybeidglijnyueahpgivaykbhio2r3ovfeo23a256y3yb6g7be4hngx3a",
"contract/valory/merkl_distributor/0.1.0": "bafybeifctofnyhdic2sxmkqujvf3j2wwydhtvzhi6kdeutykenymplf4e4",
"skill/valory/liquidity_trader_abci/0.1.0": "bafybeihml6udc4leqoexdbqrjchxj4nlymqky5ejh6vlnqg7mlh64jp2zi",
"skill/valory/optimus_abci/0.1.0": "bafybeia3bmcjh2xyfqqlxkapegfkuy4fdezvsjhmu5ans33gdcexlr54ha",
"agent/valory/optimus/0.1.0": "bafybeihiq4tplmbmlodqnfyojrnvyzkdoz25c667v6gocpv3r5chohnlgm",
"service/valory/optimus/0.1.0": "bafybeic6ohhyrjk7yxtllxfhepd35boyqqqolevnxnftftv6by2qhnypcu"
"skill/valory/liquidity_trader_abci/0.1.0": "bafybeia6pmuwqvpb6bdk75uywqxgr3puarikzcfkxj5xvwbyu7lxqzmkgi",
"skill/valory/optimus_abci/0.1.0": "bafybeifaid4m5y6nr6zhqhoyonl34gjq4sloajvnwfxp6odybb5tzdepnm",
"agent/valory/optimus/0.1.0": "bafybeih32imiqyeh23pu5yjtjbxcbvmblpjwl6an7vxpisqri4yeuqkwby",
"service/valory/optimus/0.1.0": "bafybeid3sapqas3ow57jc5pdnngyzrmxutih4k5y56elgbez6jjxaqzfiu"
},
"third_party": {
"protocol/open_aea/signing/1.0.0": "bafybeihv62fim3wl2bayavfcg3u5e5cxu3b7brtu4cn5xoxd6lqwachasi",
Expand Down
4 changes: 2 additions & 2 deletions packages/valory/agents/optimus/aea-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ protocols:
skills:
- valory/abstract_abci:0.1.0:bafybeihu2bcgjk2tqjiq2zhk3uogtfszqn4osvdt7ho3fubdpdj4jgdfjm
- valory/abstract_round_abci:0.1.0:bafybeibovsktd3uxur45nrcomq5shcn46cgxd5idmhxbmjhg32c5abyqim
- valory/liquidity_trader_abci:0.1.0:bafybeihml6udc4leqoexdbqrjchxj4nlymqky5ejh6vlnqg7mlh64jp2zi
- valory/optimus_abci:0.1.0:bafybeia3bmcjh2xyfqqlxkapegfkuy4fdezvsjhmu5ans33gdcexlr54ha
- valory/liquidity_trader_abci:0.1.0:bafybeia6pmuwqvpb6bdk75uywqxgr3puarikzcfkxj5xvwbyu7lxqzmkgi
- valory/optimus_abci:0.1.0:bafybeifaid4m5y6nr6zhqhoyonl34gjq4sloajvnwfxp6odybb5tzdepnm
- valory/registration_abci:0.1.0:bafybeicnth5q4httefsusywx3zrrq4al47owvge72dqf2fziruicq6hqta
- valory/reset_pause_abci:0.1.0:bafybeievjciqdvxhqxfjd4whqs27h6qbxqzrae7wwj7fpvxlvmtw3x35im
- valory/termination_abci:0.1.0:bafybeid54buqxipiuduw7b6nnliiwsxajnltseuroad53wukfonpxca2om
Expand Down
2 changes: 1 addition & 1 deletion packages/valory/services/optimus/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ aea_version: '>=1.0.0, <2.0.0'
license: Apache-2.0
fingerprint: {}
fingerprint_ignore_patterns: []
agent: valory/optimus:0.1.0:bafybeihiq4tplmbmlodqnfyojrnvyzkdoz25c667v6gocpv3r5chohnlgm
agent: valory/optimus:0.1.0:bafybeih32imiqyeh23pu5yjtjbxcbvmblpjwl6an7vxpisqri4yeuqkwby
number_of_agents: 1
deployment: {}
---
Expand Down
159 changes: 77 additions & 82 deletions packages/valory/skills/liquidity_trader_abci/behaviours.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,41 +422,6 @@ def async_act(self) -> Generator:
if invest_in_pool:
actions = yield from self.get_order_of_transactions()

current_timestamp = cast(
SharedState, self.context.state
).round_sequence.last_round_transition_timestamp.timestamp()

# Check if rewards can be claimed. Rewards can be claimed if either:
# 1. No rewards have been claimed yet (last_reward_claimed_timestamp is None), or
# 2. The current timestamp exceeds the allowed reward claiming time period since the last claim.
claim_rewards = (
True
if self.synchronized_data.last_reward_claimed_timestamp is None
else current_timestamp
>= self.synchronized_data.last_reward_claimed_timestamp
+ self.params.reward_claiming_time_period
)
if claim_rewards:
# check current reward
allowed_chains = self.params.allowed_chains
if not allowed_chains:
self.context.logger.warning("No chains found")
return None
# we can claim all our token rewards at once
# hence we build only one action per chain
for chain in allowed_chains:
chain_id = self.params.chain_to_chain_id_mapping.get(chain)
safe_address = self.params.safe_contract_addresses.get(chain)
rewards = yield from self.get_rewards(chain_id, safe_address)
if not rewards:
self.context.logger.warning(
f"No rewards to claim for user address {safe_address} on chain {chain}"
)
continue
action = yield from self.build_claim_reward_action(rewards, chain)
if action:
actions.append(action)

self.context.logger.info(f"Actions: {actions}")
serialized_actions = json.dumps(actions)
sender = self.context.agent_address
Expand Down Expand Up @@ -573,7 +538,7 @@ def _get_filtered_pools(self) -> Generator[None, None, Optional[Dict[str, Any]]]
# use this if you want to test with script
# api_url = self.params.pool_data_api_url

self.context.logger.info(f"{api_url}")
self.context.logger.info(f"Fetching campaigns from {api_url}")

response = yield from self.get_http_response(
method="GET",
Expand Down Expand Up @@ -634,24 +599,39 @@ def _filter_campaigns(self, chain, campaigns, filtered_pools):
# type 1 and 2 stand for ERC20 and Concentrated liquidity campaigns respectively
# https://docs.merkl.xyz/integrate-merkl/integrate-merkl-to-your-app#merkl-api
if campaign_type in [1, 2]:
if campaign_apr > self.current_pool.get("apr", 0.0):
campaign_pool_address = campaign.get("mainParameter")
if not campaign_pool_address:
self.context.logger.warning(
"No pool address found for campaign"
)
continue
current_pool_address = self.current_pool.get("address")
# The pool should not be the current pool
if campaign_pool_address != current_pool_address:
filtered_pools[dex_type][chain].append(campaign)
if not campaign_apr > self.current_pool.get("apr", 0.0):
self.context.logger.info(
"APR does not exceed the current pool APR"
)
continue
campaign_pool_address = campaign.get("mainParameter")
if not campaign_pool_address:
continue
current_pool_address = self.current_pool.get("address")
# The pool should not be the current pool
if campaign_pool_address != current_pool_address:
filtered_pools[dex_type][chain].append(campaign)

def get_order_of_transactions(
self,
) -> Generator[None, None, Optional[List[Dict[str, Any]]]]:
"""Get the order of transactions to perform based on the current pool status and token balances."""
actions = []

if self._can_claim_rewards():
# check current reward
allowed_chains = self.params.allowed_chains
# we can claim all our token rewards at once
# hence we build only one action per chain
for chain in allowed_chains:
chain_id = self.params.chain_to_chain_id_mapping.get(chain)
safe_address = self.params.safe_contract_addresses.get(chain)
rewards = yield from self._get_rewards(chain_id, safe_address)
if not rewards:
continue
action = self._build_claim_reward_action(rewards, chain)
actions.append(action)

if not self.current_pool:
tokens = self._get_tokens_over_min_balance()
if not tokens or len(tokens) < 2:
Expand Down Expand Up @@ -684,7 +664,6 @@ def get_order_of_transactions(
return None
actions.append(enter_pool_action)

self.context.logger.info(f"Actions: {actions}")
return actions

def _get_tokens_over_min_balance(self) -> Optional[List[Any]]:
Expand Down Expand Up @@ -969,6 +948,19 @@ def _build_enter_pool_action(self) -> Dict[str, Any]:
"apr": self.highest_apr_pool.get("apr"),
}

def _build_claim_reward_action(
self, rewards: Dict[str, Any], chain: str
) -> Dict[str, Any]:
return {
"action": Action.CLAIM_REWARDS.value,
"chain": chain,
"users": rewards.get("users"),
"tokens": rewards.get("tokens"),
"claims": rewards.get("claims"),
"proofs": rewards.get("proofs"),
"token_symbols": rewards.get("symbols"),
}

def _get_asset_symbol(self, chain: str, address: str) -> Optional[str]:
positions = self.synchronized_data.positions
for position in positions:
Expand All @@ -979,7 +971,7 @@ def _get_asset_symbol(self, chain: str, address: str) -> Optional[str]:

return None

def get_rewards(
def _get_rewards(
self, chain_id: int, user_address: str
) -> Generator[None, None, Optional[Dict[str, Any]]]:
base_url = self.params.merkl_user_rewards_url
Expand All @@ -1002,18 +994,29 @@ def get_rewards(
self.context.logger.info(f"User rewards: {data}")
tokens = [k for k, v in data.items() if v.get("proof")]
if not tokens:
self.context.logger.warning("No tokens to claim")
self.context.logger.info("No tokens to claim!")
return None
claims = [int(data[t].get("unclaimed", 0)) for t in tokens]
symbols = [data[t].get("symbol") for t in tokens]
claims = [int(data[t].get("accumulated", 0)) for t in tokens]

# Check if all claims are zero
if all(claim == 0 for claim in claims):
self.context.logger.warning("All claims are zero, nothing to claim")
self.context.logger.info("All claims are zero, nothing to claim")
return None

unclaimed = [int(data[t].get("unclaimed", 0)) for t in tokens]
# Check if everything has been already claimed are zero
if all(claim == 0 for claim in unclaimed):
self.context.logger.info(
"All accumulated claims already made. Nothing left to claim."
)
return None

proofs = [data[t].get("proof") for t in tokens]
return {
"users": [user_address] * len(tokens),
"tokens": tokens,
"symbols": symbols,
"claims": claims,
"proofs": proofs,
}
Expand All @@ -1024,35 +1027,22 @@ def get_rewards(
)
return None

def build_claim_reward_action(
self, rewards: Dict[str, Any], chain: str
) -> Generator[None, None, Optional[Dict[str, Any]]]:
action = {}
action["action"] = Action.CLAIM_REWARDS.value
action["chain"] = chain
action["users"] = rewards.get("users")
action["tokens"] = rewards.get("tokens")
action["claims"] = rewards.get("claims")
action["proofs"] = rewards.get("proofs")

token_symbols = []
# take each token and add its symbol
for token in rewards.get("tokens"):
token_symbol = yield from self.contract_interact(
performative=ContractApiMessage.Performative.GET_RAW_TRANSACTION,
contract_address=token,
contract_public_id=ERC20.contract_id,
contract_callable="get_token_symbol",
data_key="data",
chain_id=chain,
)
if not token_symbol:
token_symbols.append("unknown")
else:
token_symbols.append(token_symbol)
def _can_claim_rewards(self) -> bool:
# Check if rewards can be claimed. Rewards can be claimed if either:
# 1. No rewards have been claimed yet (last_reward_claimed_timestamp is None), or
# 2. The current timestamp exceeds the allowed reward claiming time period since the last claim.

action["token_symbols"] = token_symbols
return action
current_timestamp = cast(
SharedState, self.context.state
).round_sequence.last_round_transition_timestamp.timestamp()

last_claimed_timestamp = self.synchronized_data.last_reward_claimed_timestamp
if last_claimed_timestamp is None:
return True
return (
current_timestamp
>= last_claimed_timestamp + self.params.reward_claiming_time_period
)


class DecisionMakingBehaviour(LiquidityTraderBaseBehaviour):
Expand Down Expand Up @@ -1187,6 +1177,7 @@ def get_next_event(self) -> Generator[None, None, Tuple[str, Dict, Optional[Dict
# If last action was Claim Rewards and it was successful we update the list of assets and the last_reward_claimed_timestamp
if (
last_executed_action_index is not None
and last_round_id != DecisionMakingRound.auto_round_id()
and Action(actions[last_executed_action_index]["action"])
== Action.CLAIM_REWARDS
):
Expand All @@ -1196,12 +1187,16 @@ def get_next_event(self) -> Generator[None, None, Tuple[str, Dict, Optional[Dict
action.get("tokens"), action.get("token_symbols")
):
self._add_token_to_assets(chain, token, token_symbol)

current_timestamp = cast(
SharedState, self.context.state
).round_sequence.last_round_transition_timestamp.timestamp()

return Event.UPDATE.value, {"last_reward_claimed_timestamp": current_timestamp}, {}
return (
Event.UPDATE.value,
{"last_reward_claimed_timestamp": current_timestamp},
{},
)

# if all actions have been executed we exit DecisionMaking
if current_action_index >= len(self.synchronized_data.actions):
Expand Down
4 changes: 2 additions & 2 deletions packages/valory/skills/liquidity_trader_abci/skill.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license: Apache-2.0
aea_version: '>=1.0.0, <2.0.0'
fingerprint:
__init__.py: bafybeia7bn2ahqqwkf63ptje6rfnftuwrsp33sswgpcbh5osbesxxr6g4m
behaviours.py: bafybeiduwq37ba5bdtus2iwomcb2bhxerdiriuhpr2at5wzjxvqut2xjwm
behaviours.py: bafybeidczsocvdmtdhqh6jm4bdjzveuvcmxstmwwyomdrdvpels7r5qipa
dialogues.py: bafybeiay23otskx2go5xhtgdwfw2kd6rxd62sxxdu3njv7hageorl5zxzm
fsm_specification.yaml: bafybeia7dh7vuifjebf63wdqlw6gtrwcss5mapmdzhbju7i6edsw3zqxki
handlers.py: bafybeidxw2lvgiifmo4siobpwuwbxscuifrdo3gnkjyn6bgexotj5f7zf4
Expand All @@ -16,7 +16,7 @@ fingerprint:
pool_behaviour.py: bafybeiaheuesscgqzwjbpyrezgwpdbdfurlmfwbc462qv6rblwwxlx5dpm
pools/balancer.py: bafybeieo53qtt557632vtp3x3huagdpqevptextbwd7euk6hpoz6ybtuci
pools/uniswap.py: bafybeif2cjbtjh5altlgranmgrif4yaevnn344fn3askbjde5h4y4rh2mq
rounds.py: bafybeiattfoicojezsnc5pidpqkrl2ncglzhbzqufkmy37t7v2b7qta53q
rounds.py: bafybeico4zvu3fpnqbw3k2et3gzvliejjjkosmqrnbh3imblqppiui4alu
strategies/simple_strategy.py: bafybeig2iygxz5gewmiyeawubs5f4pr5e3st22lmdkxthlfq7t5kbluw4a
strategy_behaviour.py: bafybeidk6sorg47kuuubamcccksi65x3txldyo7y2hm5opbye2ghmz2ljy
fingerprint_ignore_patterns: []
Expand Down
2 changes: 1 addition & 1 deletion packages/valory/skills/optimus_abci/skill.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ skills:
- valory/registration_abci:0.1.0:bafybeicnth5q4httefsusywx3zrrq4al47owvge72dqf2fziruicq6hqta
- valory/reset_pause_abci:0.1.0:bafybeievjciqdvxhqxfjd4whqs27h6qbxqzrae7wwj7fpvxlvmtw3x35im
- valory/termination_abci:0.1.0:bafybeid54buqxipiuduw7b6nnliiwsxajnltseuroad53wukfonpxca2om
- valory/liquidity_trader_abci:0.1.0:bafybeihml6udc4leqoexdbqrjchxj4nlymqky5ejh6vlnqg7mlh64jp2zi
- valory/liquidity_trader_abci:0.1.0:bafybeia6pmuwqvpb6bdk75uywqxgr3puarikzcfkxj5xvwbyu7lxqzmkgi
- valory/transaction_settlement_abci:0.1.0:bafybeihq2yenstblmaadzcjousowj5kfn5l7ns5pxweq2gcrsczfyq5wzm
behaviours:
main:
Expand Down
Loading