mirror of
https://github.com/FlipsideCrypto/fsc-utils.git
synced 2026-02-06 02:46:59 +00:00
Merge pull request #70 from FlipsideCrypto/fix/udf-compile-error
Fix/udf compile error
This commit is contained in:
commit
a363429861
116
README.md
116
README.md
@ -159,6 +159,122 @@ The `fsc_utils` dbt package is a centralized repository consisting of various db
|
||||
|
||||
```
|
||||
|
||||
- `utils.udf_encode_contract_call`: Encodes EVM contract function calls into ABI-encoded calldata format for eth_call RPC requests. Handles all Solidity types including tuples and arrays.
|
||||
|
||||
```
|
||||
-- Simple function with no inputs
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON('{"name": "totalSupply", "inputs": []}'),
|
||||
ARRAY_CONSTRUCT()
|
||||
);
|
||||
-- Returns: 0x18160ddd
|
||||
|
||||
-- Function with single address parameter
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON('{
|
||||
"name": "balanceOf",
|
||||
"inputs": [{"name": "account", "type": "address"}]
|
||||
}'),
|
||||
ARRAY_CONSTRUCT('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48')
|
||||
);
|
||||
-- Returns: 0x70a08231000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
|
||||
|
||||
-- Function with multiple parameters
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON('{
|
||||
"name": "transfer",
|
||||
"inputs": [
|
||||
{"name": "to", "type": "address"},
|
||||
{"name": "amount", "type": "uint256"}
|
||||
]
|
||||
}'),
|
||||
ARRAY_CONSTRUCT('0x1234567890123456789012345678901234567890', 1000000)
|
||||
);
|
||||
|
||||
-- Complex function with nested tuples
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON('{
|
||||
"name": "swap",
|
||||
"inputs": [{
|
||||
"name": "params",
|
||||
"type": "tuple",
|
||||
"components": [
|
||||
{"name": "tokenIn", "type": "address"},
|
||||
{"name": "tokenOut", "type": "address"},
|
||||
{"name": "amountIn", "type": "uint256"}
|
||||
]
|
||||
}]
|
||||
}'),
|
||||
ARRAY_CONSTRUCT(
|
||||
ARRAY_CONSTRUCT(
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
||||
1000000
|
||||
)
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
- `utils.udf_create_eth_call`: Creates an eth_call JSON-RPC request object from contract address and encoded calldata. Supports block parameter as string or number (auto-converts numbers to hex).
|
||||
|
||||
```
|
||||
-- Using default 'latest' block
|
||||
SELECT utils.udf_create_eth_call(
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0x70a08231000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
||||
);
|
||||
|
||||
-- Using specific block number (auto-converted to hex)
|
||||
SELECT utils.udf_create_eth_call(
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
'0x70a08231000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
18500000
|
||||
);
|
||||
```
|
||||
|
||||
- `utils.udf_create_eth_call_from_abi`: Convenience function that combines contract call encoding and JSON-RPC request creation in a single call. Recommended for most use cases.
|
||||
|
||||
```
|
||||
-- Simple balanceOf call with default 'latest' block
|
||||
SELECT utils.udf_create_eth_call_from_abi(
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
PARSE_JSON('{
|
||||
"name": "balanceOf",
|
||||
"inputs": [{"name": "account", "type": "address"}]
|
||||
}'),
|
||||
ARRAY_CONSTRUCT('0xbcca60bb61934080951369a648fb03df4f96263c')
|
||||
);
|
||||
|
||||
-- Same call but at a specific block number
|
||||
SELECT utils.udf_create_eth_call_from_abi(
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
PARSE_JSON('{
|
||||
"name": "balanceOf",
|
||||
"inputs": [{"name": "account", "type": "address"}]
|
||||
}'),
|
||||
ARRAY_CONSTRUCT('0xbcca60bb61934080951369a648fb03df4f96263c'),
|
||||
18500000
|
||||
);
|
||||
|
||||
-- Using ABI from a table
|
||||
WITH abi_data AS (
|
||||
SELECT
|
||||
abi,
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' as contract_address,
|
||||
'0xbcca60bb61934080951369a648fb03df4f96263c' as user_address
|
||||
FROM ethereum.silver.flat_function_abis
|
||||
WHERE contract_address = LOWER('0x43506849d7c04f9138d1a2050bbf3a0c054402dd')
|
||||
AND function_name = 'balanceOf'
|
||||
)
|
||||
SELECT
|
||||
utils.udf_create_eth_call_from_abi(
|
||||
contract_address,
|
||||
abi,
|
||||
ARRAY_CONSTRUCT(user_address)
|
||||
) as rpc_call
|
||||
FROM abi_data;
|
||||
```
|
||||
|
||||
## **Streamline V 2.0 Functions**
|
||||
|
||||
The `Streamline V 2.0` functions are a set of macros and UDFs that are designed to be used with `Streamline V 2.0` deployments.
|
||||
|
||||
@ -30,6 +30,18 @@
|
||||
sql: |
|
||||
{{ fsc_utils.python_udf_hex_to_int_with_encoding() | indent(4) }}
|
||||
|
||||
|
||||
- name: {{ schema }}.udf_int_to_hex
|
||||
signature:
|
||||
- [int, NUMBER]
|
||||
return_type: VARCHAR(16777216)
|
||||
options: |
|
||||
NULL
|
||||
LANGUAGE SQL
|
||||
STRICT IMMUTABLE
|
||||
sql: |
|
||||
SELECT CONCAT('0x', TRIM(TO_CHAR(int, 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')))
|
||||
|
||||
- name: {{ schema }}.udf_hex_to_string
|
||||
signature:
|
||||
- [hex, STRING]
|
||||
@ -303,7 +315,7 @@
|
||||
RUNTIME_VERSION = '3.10'
|
||||
PACKAGES = ('eth-abi')
|
||||
HANDLER = 'encode_call'
|
||||
COMMENT = '{{ fsc_utils.udf_encode_contract_call_comment() }}'
|
||||
COMMENT = 'Encodes EVM contract function calls into ABI-encoded calldata format for eth_call RPC requests. Handles all Solidity types including tuples and arrays.'
|
||||
sql: |
|
||||
{{ fsc_utils.create_udf_encode_contract_call() | indent(4) }}
|
||||
|
||||
@ -367,7 +379,7 @@
|
||||
NULL
|
||||
LANGUAGE SQL
|
||||
STRICT IMMUTABLE
|
||||
COMMENT = '{{ fsc_utils.udf_create_eth_call_from_abi_comment() }}'
|
||||
COMMENT = 'Convenience function that combines contract call encoding and JSON-RPC request creation for eth_call. Encodes function call from ABI and creates RPC request with default block parameter "latest".'
|
||||
sql: |
|
||||
{{ schema }}.udf_create_eth_call(
|
||||
contract_address,
|
||||
@ -385,7 +397,7 @@
|
||||
NULL
|
||||
LANGUAGE SQL
|
||||
STRICT IMMUTABLE
|
||||
COMMENT = '{{ fsc_utils.udf_create_eth_call_from_abi_comment() }}'
|
||||
COMMENT = 'Convenience function that combines contract call encoding and JSON-RPC request creation for eth_call. Encodes function call from ABI and creates RPC request with specified block parameter.'
|
||||
sql: |
|
||||
{{ schema }}.udf_create_eth_call(
|
||||
contract_address,
|
||||
|
||||
@ -1010,233 +1010,3 @@ def encode_call(function_abi, input_values):
|
||||
})
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
{% macro udf_encode_contract_call_comment() %}
|
||||
Encodes EVM contract function calls into hex calldata format for eth_call RPC requests.
|
||||
|
||||
PURPOSE:
|
||||
Converts human-readable function parameters into ABI-encoded calldata that can be sent
|
||||
to Ethereum nodes via JSON-RPC. Handles all Solidity types including complex nested
|
||||
structures like tuples and arrays.
|
||||
|
||||
PARAMETERS:
|
||||
function_abi (VARIANT):
|
||||
- JSON object containing the function ABI definition
|
||||
- Must include: "name" (string) and "inputs" (array of input definitions)
|
||||
- Each input needs: "name", "type", and optionally "components" for tuples
|
||||
|
||||
input_values (ARRAY):
|
||||
- Array of values matching the function inputs in order
|
||||
- Values should be provided as native Snowflake types:
|
||||
* addresses: strings (with or without 0x prefix)
|
||||
* uint/int: numbers
|
||||
* bool: booleans
|
||||
* bytes/bytes32: hex strings (with or without 0x prefix)
|
||||
* arrays: Snowflake arrays
|
||||
* tuples: Snowflake arrays in component order
|
||||
|
||||
RETURNS:
|
||||
STRING: Complete calldata as hex string with 0x prefix
|
||||
- Format: 0x{4-byte selector}{encoded parameters}
|
||||
- Can be used directly in eth_call RPC requests
|
||||
- Returns JSON error object if encoding fails
|
||||
|
||||
EXAMPLES:
|
||||
|
||||
-- Simple function with no inputs
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON(''{"name": "totalSupply", "inputs": []}''),
|
||||
ARRAY_CONSTRUCT()
|
||||
);
|
||||
-- Returns: 0x18160ddd
|
||||
|
||||
-- Function with single address parameter
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON(''{
|
||||
"name": "balanceOf",
|
||||
"inputs": [{"name": "account", "type": "address"}]
|
||||
}''),
|
||||
ARRAY_CONSTRUCT(''0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'')
|
||||
);
|
||||
-- Returns: 0x70a08231000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
|
||||
|
||||
-- Function with multiple parameters
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON(''{
|
||||
"name": "transfer",
|
||||
"inputs": [
|
||||
{"name": "to", "type": "address"},
|
||||
{"name": "amount", "type": "uint256"}
|
||||
]
|
||||
}''),
|
||||
ARRAY_CONSTRUCT(''0x1234567890123456789012345678901234567890'', 1000000)
|
||||
);
|
||||
|
||||
-- Complex function with nested tuples
|
||||
SELECT utils.udf_encode_contract_call(
|
||||
PARSE_JSON(''{
|
||||
"name": "swap",
|
||||
"inputs": [{
|
||||
"name": "params",
|
||||
"type": "tuple",
|
||||
"components": [
|
||||
{"name": "tokenIn", "type": "address"},
|
||||
{"name": "tokenOut", "type": "address"},
|
||||
{"name": "amountIn", "type": "uint256"}
|
||||
]
|
||||
}]
|
||||
}''),
|
||||
ARRAY_CONSTRUCT(
|
||||
ARRAY_CONSTRUCT(
|
||||
''0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'',
|
||||
''0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'',
|
||||
1000000
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
TYPICAL WORKFLOW:
|
||||
1. Get function ABI from crosschain.evm.dim_contract_abis
|
||||
2. Prepare input values as Snowflake arrays
|
||||
3. Encode using this function
|
||||
4. Execute via eth_call RPC (live.udf_api)
|
||||
5. Decode response using utils.udf_evm_decode_trace
|
||||
|
||||
SUPPORTED TYPES:
|
||||
- address: Ethereum addresses
|
||||
- uint8, uint16, ..., uint256: Unsigned integers
|
||||
- int8, int16, ..., int256: Signed integers
|
||||
- bool: Boolean values
|
||||
- bytes, bytes1, ..., bytes32: Fixed and dynamic byte arrays
|
||||
- string: Dynamic strings
|
||||
- Arrays: Any type followed by []
|
||||
- Tuples: Nested structures with components
|
||||
- Nested combinations: tuple[], tuple[][], etc.
|
||||
|
||||
NOTES:
|
||||
- Function selector is automatically calculated using Keccak256
|
||||
- Compatible with existing utils.udf_evm_text_signature and utils.udf_keccak256
|
||||
- Handles gas-optimized function names (e.g., selector 0x00000000)
|
||||
- Tuples must be provided as arrays in component order
|
||||
- Empty arrays are valid for array-type parameters
|
||||
|
||||
ERROR HANDLING:
|
||||
- Returns JSON error object on failure
|
||||
- Check if result starts with "{" to detect errors
|
||||
- Error object includes: error message, traceback, function name, types
|
||||
|
||||
RELATED FUNCTIONS:
|
||||
- utils.udf_evm_text_signature: Generate function signature
|
||||
- utils.udf_keccak256: Calculate function selector
|
||||
- utils.udf_evm_decode_trace: Decode call results
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
{% macro udf_create_eth_call_from_abi_comment() %}
|
||||
Convenience function that combines contract call encoding and JSON-RPC request creation for eth_call.
|
||||
|
||||
PURPOSE:
|
||||
Simplifies the workflow of creating eth_call JSON-RPC requests by combining ABI encoding
|
||||
and RPC call construction into a single function call. This is the recommended approach for
|
||||
most use cases where you want to query contract state via eth_call.
|
||||
|
||||
PARAMETERS:
|
||||
contract_address (STRING):
|
||||
- Ethereum contract address (with or without 0x prefix)
|
||||
- Example: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
|
||||
|
||||
function_abi (VARIANT):
|
||||
- JSON object containing the function ABI definition
|
||||
- Must include: "name" (string) and "inputs" (array of input definitions)
|
||||
- Each input needs: "name", "type", and optionally "components" for tuples
|
||||
- Can be retrieved from tables like crosschain.evm.dim_contract_abis or ethereum.silver.flat_function_abis
|
||||
|
||||
input_values (ARRAY):
|
||||
- Array of values matching the function inputs in order
|
||||
- Values should be provided as native Snowflake types:
|
||||
* addresses: strings (with or without 0x prefix)
|
||||
* uint/int: numbers
|
||||
* bool: booleans
|
||||
* bytes/bytes32: hex strings (with or without 0x prefix)
|
||||
* arrays: Snowflake arrays
|
||||
* tuples: Snowflake arrays in component order
|
||||
|
||||
block_parameter (VARIANT, optional):
|
||||
- Block identifier for the eth_call request
|
||||
- If NULL or omitted: defaults to 'latest'
|
||||
- If NUMBER: automatically converted to hex format (e.g., 18500000 -> '0x11a7f80')
|
||||
- If STRING: used directly (e.g., 'latest', '0x11a7f80', 'pending')
|
||||
|
||||
RETURNS:
|
||||
OBJECT: Complete JSON-RPC request object ready for eth_call
|
||||
- Format: {"jsonrpc": "2.0", "method": "eth_call", "params": [...], "id": "..."}
|
||||
- Can be used directly with RPC execution functions like live.udf_api
|
||||
|
||||
EXAMPLES:
|
||||
|
||||
-- Simple balanceOf call with default 'latest' block
|
||||
SELECT utils.udf_create_eth_call_from_abi(
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
PARSE_JSON('{
|
||||
"name": "balanceOf",
|
||||
"inputs": [{"name": "account", "type": "address"}]
|
||||
}'),
|
||||
ARRAY_CONSTRUCT('0xbcca60bb61934080951369a648fb03df4f96263c')
|
||||
);
|
||||
|
||||
-- Same call but at a specific block number
|
||||
SELECT utils.udf_create_eth_call_from_abi(
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
PARSE_JSON('{
|
||||
"name": "balanceOf",
|
||||
"inputs": [{"name": "account", "type": "address"}]
|
||||
}'),
|
||||
ARRAY_CONSTRUCT('0xbcca60bb61934080951369a648fb03df4f96263c'),
|
||||
18500000
|
||||
);
|
||||
|
||||
-- Using ABI from a table
|
||||
WITH abi_data AS (
|
||||
SELECT
|
||||
abi,
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' as contract_address,
|
||||
'0xbcca60bb61934080951369a648fb03df4f96263c' as user_address
|
||||
FROM ethereum.silver.flat_function_abis
|
||||
WHERE contract_address = LOWER('0x43506849d7c04f9138d1a2050bbf3a0c054402dd')
|
||||
AND function_name = 'balanceOf'
|
||||
)
|
||||
SELECT
|
||||
utils.udf_create_eth_call_from_abi(
|
||||
contract_address,
|
||||
abi,
|
||||
ARRAY_CONSTRUCT(user_address)
|
||||
) as rpc_call
|
||||
FROM abi_data;
|
||||
|
||||
TYPICAL WORKFLOW:
|
||||
1. Get function ABI from contract ABI tables (crosschain.evm.dim_contract_abis, etc.)
|
||||
2. Prepare input values as Snowflake arrays matching the function signature
|
||||
3. Call this function with contract address, ABI, and inputs
|
||||
4. Execute the returned RPC call object via live.udf_api or similar
|
||||
5. Decode the response using utils.udf_evm_decode_trace or similar decoder
|
||||
|
||||
ADVANTAGES OVER MODULAR APPROACH:
|
||||
- Single function call instead of two (encode + create)
|
||||
- Cleaner, more readable SQL
|
||||
- Better for AI systems (fewer steps to explain)
|
||||
- Less error-prone (no intermediate variables)
|
||||
- More intuitive function name
|
||||
|
||||
WHEN TO USE MODULAR FUNCTIONS INSTEAD:
|
||||
- When you need to reuse encoded calldata for multiple RPC calls
|
||||
- When you need encoded calldata for transaction construction
|
||||
- When building complex workflows with intermediate steps
|
||||
|
||||
RELATED FUNCTIONS:
|
||||
- utils.udf_encode_contract_call: Encode function calls to calldata (used internally)
|
||||
- utils.udf_create_eth_call: Create RPC call from encoded calldata (used internally)
|
||||
- utils.udf_evm_text_signature: Generate function signature from ABI
|
||||
- utils.udf_keccak256: Calculate function selector hash
|
||||
- utils.udf_evm_decode_trace: Decode eth_call response results
|
||||
|
||||
{% endmacro %}
|
||||
Loading…
Reference in New Issue
Block a user