# ActionDecoder

In order to reproduce user behaviour in existing pools, data is pulled from several sources and combined into a temporal sequence of actions, in a json file (see [Adding On-chain Transaction Data](/balancer-simulations/additional-code-and-instructions/onchaintransactions.md))

ActionDecoder reads the actions from the json every simulation step and converts the actions into pool "opcodes", each represented by a class in `pool_method_entities.py` . These are passed to the pool state update function `s_update_pool.py`

First action (`pool_creation)`is skipped, since the results are already in the initial state variables

There are two main types of actions:

**a) Pool actions**\
**b) Price updates**

1. **Pool actions** call pool related policies, like this `swap`:

```
{
		"timestamp": "2021-01-13T18:46:38+00:00",
		"tx_hash": "0x8819714eaa6ce5310586e33b4c7e1dfbc947318330984d1d110a369c9de6da2c",
		"block_number": "11648399",
		"swap_fee": "0.0025",
		"denorms": [
			{
				"token_address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
				"token_symbol": "DAI",
				"denorm": "10.000000000"
			},
			{
				"token_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
				"token_symbol": "WETH",
				"denorm": "40.000000000"
			}
		],
		"contract_call": [
			{
				"type": "swapExactAmountIn",
				"inputs": {
					"tokenIn_symbol": "DAI",
					"tokenIn": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
					"tokenAmountIn": "236.906023596408551105",
					"tokenOut_symbol": "WETH",
					"tokenOut": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
					"minAmountOut": "0",
					"maxPrice": "115792089237316195423570985008687907853269984665640564039457.584007913129639935"
				}
			}
		],
		"action": {
			"type": "swap",
			"token_in": {
				"amount": "236.906023596408551105",
				"symbol": "DAI"
			},
			"token_out": {
				"amount": "0.21445704314241238",
				"symbol": "WETH"
			}
		}
	},
```

The structure in general is:

* timestamp: When the action happened
* tx\_hash: Transaction hash that resulted in the action. May not be unique, for example a transaction generated by an aggregator like 1inch can result in several swaps against the same pool
* block\_number: Ethereum block number where the transaction happened
* swap\_fee: Pool swap fee setting at this stage.
* denorms: Pool tokens' [denormalized weight](https://docs.balancer.finance/core-concepts/protocol/glossary) at this stage
* contract\_call: Result of parsing LOG\_CALL anonymous event, that has the exact method name and parameters of the smart contract method
* action: Outcome of the action in this pool, combining LOG\_CALL, LO&#x47;*\_*&#x4A;OIN and LOG\_EXIT events getting data from BigQuery ETL project

**2. External price updates** trigger state updates to the USD price of tokens

```
{
		"timestamp": "2021-01-13T19:00:00+00:00",
		"fiat_currency": "USD",
		"action": {
			"type": "external_price_update",
			"tokens": {
				"DAI": 1.0010362320777462,
				"WETH": 1068.3949468116527
			}
		}
	},
```

The decoder has a selector to execute the relevant pool method or price update. In this version, only some pool events are used according to action type.

In every timestep we update the date time and action type.

```
    @staticmethod
    def p_action_decoder(params, step, history, current_state):
        if ActionDecoder.action_df is None:
            raise Exception('call ActionDecoder.load_actions(path_to_action.json) first')
        '''
        In this simplified model of Balancer, we have not modeled user behavior. Instead, we map events to actions.
        '''
        decoding_type = get_param(params, 'decoding_type')

        ActionDecoder.decoding_type = ActionDecodingType(decoding_type)
        idx = current_state['timestep'] + 1
        if ActionDecoder.decoding_type == ActionDecodingType.simplified:
            return ActionDecoder.p_simplified_action_decoder(idx, params, step, history, current_state)
        elif ActionDecoder.decoding_type == ActionDecodingType.contract_call:
            return ActionDecoder.p_contract_call_action_decoder(idx, params, step, history, current_state)
        elif ActionDecoder.decoding_type == ActionDecodingType.replay_output:
            return ActionDecoder.p_plot_output_action_decoder(idx, params, step, history, current_state)
        else:
            raise Exception(f'unknown decoding type {decoding_type}')

    ...
    
    @staticmethod
    def p_simplified_action_decoder(idx, params, step, history, current_state):
        action = ActionDecoder.action_df['action'][idx]
        timestamp = ActionDecoder.action_df['timestamp'][idx]
        tx_hash = ActionDecoder.action_df['tx_hash'][idx]
        if action['type'] == 'swap':
            pool_method_params = PoolMethodParamsDecoder.swap_exact_amount_in_simplified(action)
        elif action['type'] == 'join':
            pool_method_params = PoolMethodParamsDecoder.join_pool_simplified(action)
        elif action['type'] == 'join_swap':
            pool_method_params = PoolMethodParamsDecoder.join_swap_extern_amount_in_simplified(action)
        elif action['type'] == 'exit_swap':
            pool_method_params = PoolMethodParamsDecoder.exit_swap_pool_amount_in_simplified(action)
        elif action['type'] == 'exit':
            pool_method_params = PoolMethodParamsDecoder.exit_pool_simplified(action)
        elif action['type'] == 'external_price_update':
            return {'external_price_update': action['tokens'], 'change_datetime_update': timestamp, 'action_type': action['type'],
                    'pool_update': None}
        else:
            raise Exception("Action type {} unimplemented".format(action['type']))
        return {'pool_update': pool_method_params, 'change_datetime_update': timestamp, 'action_type': action['type']}
            
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://token-engineering-balancer.gitbook.io/balancer-simulations/additional-code-and-instructions/balancer-the-python-edition/actiondecoder.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
