From 79fa8a83b0f889a442d7a1e9e3f6750b6fbe69f8 Mon Sep 17 00:00:00 2001 From: williamrusdyputra Date: Mon, 15 Sep 2025 13:46:16 +0700 Subject: [PATCH 1/7] feat: fee configs --- internal/migrations/023-fee-configs.sql | 24 ++++++++++++ .../001-actions.sql => 024-erc20-bridge.sql} | 39 ++++++++++--------- 2 files changed, 44 insertions(+), 19 deletions(-) create mode 100644 internal/migrations/023-fee-configs.sql rename internal/migrations/{erc20-bridge/001-actions.sql => 024-erc20-bridge.sql} (58%) diff --git a/internal/migrations/023-fee-configs.sql b/internal/migrations/023-fee-configs.sql new file mode 100644 index 000000000..db8d74fd2 --- /dev/null +++ b/internal/migrations/023-fee-configs.sql @@ -0,0 +1,24 @@ +-- Fee configuration table for ERC20 bridge operations +-- Stores configurable fees and treasury address for deposit and withdraw operations + +CREATE TABLE IF NOT EXISTS fee_configs ( + operation_type TEXT NOT NULL, + fee_percentage NUMERIC(4, 4) NOT NULL, + treasury_address TEXT NOT NULL, + created_at INT8 NOT NULL, + updated_at INT8 NOT NULL, + + PRIMARY KEY (operation_type), + + -- Constraints + CHECK (operation_type IN ('deposit', 'withdraw')), + CHECK (fee_percentage >= 0 AND fee_percentage <= 1), -- 0% to 100% + CHECK (treasury_address LIKE '0x%' AND LENGTH(treasury_address) = 42) +); + +-- Insert default fee configurations +INSERT INTO fee_configs (operation_type, fee_percentage, treasury_address, created_at, updated_at) VALUES +('deposit', 0.0100, '0xDe5B2aBce299eBdC3567895B1B4b02Ca2c33C94A', @height, @height), +('withdraw', 0.0100, '0xDe5B2aBce299eBdC3567895B1B4b02Ca2c33C94A', @height, @height) +ON CONFLICT (operation_type) DO NOTHING; + diff --git a/internal/migrations/erc20-bridge/001-actions.sql b/internal/migrations/024-erc20-bridge.sql similarity index 58% rename from internal/migrations/erc20-bridge/001-actions.sql rename to internal/migrations/024-erc20-bridge.sql index 517a85163..7e440235e 100644 --- a/internal/migrations/erc20-bridge/001-actions.sql +++ b/internal/migrations/024-erc20-bridge.sql @@ -22,16 +22,17 @@ CREATE OR REPLACE ACTION sepolia_wallet_balance($wallet_address TEXT) PUBLIC VIE }; CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { - -- Calculate 1% fee and lock it in our treasury $num_amount := $amount::NUMERIC(78, 0); - $fee := $num_amount * 0.01; - sepolia_bridge.lock($fee); - - $treasury_address := '0xDe5B2aBce299eBdC3567895B1B4b02Ca2c33C94A'; - sepolia_bridge.unlock($treasury_address, $fee); - - -- Bridge the rest to users - sepolia_bridge.bridge($num_amount - $fee); + + -- Get fee configuration for withdraw + FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'deposit' { + $fee := $num_amount * $config.fee_percentage; + sepolia_bridge.lock($fee); + sepolia_bridge.unlock($config.treasury_address, $fee); + + -- Bridge the rest to users + sepolia_bridge.bridge($num_amount - $fee); + } }; -- MAINNET @@ -41,15 +42,15 @@ CREATE OR REPLACE ACTION mainnet_wallet_balance($wallet_address TEXT) PUBLIC VIE }; CREATE OR REPLACE ACTION mainnet_admin_bridge_tokens($amount TEXT) PUBLIC { - -- Calculate 1% fee and lock it in our treasury $numAmount := $amount::NUMERIC(78, 0); - $fee := $numAmount * 0.01; - mainnet_bridge.lock($fee); - - -- TODO: update when we have treasury address on mainnet - -- $treasury_address := '' - -- sepolia_bridge.unlock($treasury_address, $fee); - - -- Bridge the rest to users - mainnet_bridge.bridge($numAmount - $fee); + + -- Get fee configuration for withdraw + FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'deposit' { + $fee := $numAmount * $config.fee_percentage; + mainnet_bridge.lock($fee); + mainnet_bridge.unlock($config.treasury_address, $fee); + + -- Bridge the rest to users + mainnet_bridge.bridge($numAmount - $fee); + } }; \ No newline at end of file From f11636df38a08bdfc3e0e0d36482556e1ac6ba58 Mon Sep 17 00:00:00 2001 From: williamrusdyputra Date: Mon, 15 Sep 2025 13:53:45 +0700 Subject: [PATCH 2/7] chore: create a function to call the fee config --- internal/migrations/023-fee-configs.sql | 10 +++++++ internal/migrations/024-erc20-bridge.sql | 34 +++++++++++------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/internal/migrations/023-fee-configs.sql b/internal/migrations/023-fee-configs.sql index db8d74fd2..851904894 100644 --- a/internal/migrations/023-fee-configs.sql +++ b/internal/migrations/023-fee-configs.sql @@ -22,3 +22,13 @@ INSERT INTO fee_configs (operation_type, fee_percentage, treasury_address, creat ('withdraw', 0.0100, '0xDe5B2aBce299eBdC3567895B1B4b02Ca2c33C94A', @height, @height) ON CONFLICT (operation_type) DO NOTHING; +-- Action to get fee configuration by operation type +CREATE OR REPLACE ACTION get_fee_config_by_type($operation_type TEXT) +PUBLIC VIEW RETURNS ( + fee_percentage NUMERIC(4, 4), + treasury_address TEXT +) { + FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = $operation_type { + RETURN $config.fee_percentage, $config.treasury_address; + } +}; diff --git a/internal/migrations/024-erc20-bridge.sql b/internal/migrations/024-erc20-bridge.sql index 7e440235e..5a6fae628 100644 --- a/internal/migrations/024-erc20-bridge.sql +++ b/internal/migrations/024-erc20-bridge.sql @@ -24,15 +24,14 @@ CREATE OR REPLACE ACTION sepolia_wallet_balance($wallet_address TEXT) PUBLIC VIE CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { $num_amount := $amount::NUMERIC(78, 0); - -- Get fee configuration for withdraw - FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'deposit' { - $fee := $num_amount * $config.fee_percentage; - sepolia_bridge.lock($fee); - sepolia_bridge.unlock($config.treasury_address, $fee); - - -- Bridge the rest to users - sepolia_bridge.bridge($num_amount - $fee); - } + -- Get fee configuration for deposit + $fee_percentage, $treasury_address := get_fee_config_by_type('withdraw'); + $fee := $num_amount * $fee_percentage; + sepolia_bridge.lock($fee); + sepolia_bridge.unlock($treasury_address, $fee); + + -- Bridge the rest to users + sepolia_bridge.bridge($num_amount - $fee); }; -- MAINNET @@ -44,13 +43,12 @@ CREATE OR REPLACE ACTION mainnet_wallet_balance($wallet_address TEXT) PUBLIC VIE CREATE OR REPLACE ACTION mainnet_admin_bridge_tokens($amount TEXT) PUBLIC { $numAmount := $amount::NUMERIC(78, 0); - -- Get fee configuration for withdraw - FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'deposit' { - $fee := $numAmount * $config.fee_percentage; - mainnet_bridge.lock($fee); - mainnet_bridge.unlock($config.treasury_address, $fee); - - -- Bridge the rest to users - mainnet_bridge.bridge($numAmount - $fee); - } + -- Get fee configuration for deposit + $fee_percentage, $treasury_address := get_fee_config_by_type('withdraw'); + $fee := $numAmount * $fee_percentage; + mainnet_bridge.lock($fee); + mainnet_bridge.unlock($treasury_address, $fee); + + -- Bridge the rest to users + mainnet_bridge.bridge($numAmount - $fee); }; \ No newline at end of file From 693fa04db5fd32b24b502ca18624897bd7563df1 Mon Sep 17 00:00:00 2001 From: williamrusdyputra Date: Mon, 15 Sep 2025 14:13:02 +0700 Subject: [PATCH 3/7] fix: apply coderabbit suggestions --- internal/migrations/024-erc20-bridge.sql | 42 ++++++++++++++---------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/internal/migrations/024-erc20-bridge.sql b/internal/migrations/024-erc20-bridge.sql index 5a6fae628..3d506d6c0 100644 --- a/internal/migrations/024-erc20-bridge.sql +++ b/internal/migrations/024-erc20-bridge.sql @@ -24,14 +24,18 @@ CREATE OR REPLACE ACTION sepolia_wallet_balance($wallet_address TEXT) PUBLIC VIE CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { $num_amount := $amount::NUMERIC(78, 0); - -- Get fee configuration for deposit - $fee_percentage, $treasury_address := get_fee_config_by_type('withdraw'); - $fee := $num_amount * $fee_percentage; - sepolia_bridge.lock($fee); - sepolia_bridge.unlock($treasury_address, $fee); - - -- Bridge the rest to users - sepolia_bridge.bridge($num_amount - $fee); + -- Get fee configuration for withdraw + FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at LIMIT 1 { + $fee := $num_amount * $config.fee_percentage; + + IF $fee > 0 { + sepolia_bridge.lock($fee); + sepolia_bridge.unlock($config.treasury_address, $fee); + } + + -- Bridge the rest to users + sepolia_bridge.bridge($num_amount - $fee); + } }; -- MAINNET @@ -41,14 +45,18 @@ CREATE OR REPLACE ACTION mainnet_wallet_balance($wallet_address TEXT) PUBLIC VIE }; CREATE OR REPLACE ACTION mainnet_admin_bridge_tokens($amount TEXT) PUBLIC { - $numAmount := $amount::NUMERIC(78, 0); - - -- Get fee configuration for deposit - $fee_percentage, $treasury_address := get_fee_config_by_type('withdraw'); - $fee := $numAmount * $fee_percentage; - mainnet_bridge.lock($fee); - mainnet_bridge.unlock($treasury_address, $fee); + $num_amount := $amount::NUMERIC(78, 0); - -- Bridge the rest to users - mainnet_bridge.bridge($numAmount - $fee); + -- Get fee configuration for withdraw + FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at LIMIT 1 { + $fee := $num_amount * $config.fee_percentage; + + IF $fee > 0 { + mainnet_bridge.lock($fee); + mainnet_bridge.unlock($config.treasury_address, $fee); + } + + -- Bridge the rest to users + mainnet_bridge.bridge($num_amount - $fee); + } }; \ No newline at end of file From 8d5e6095d92c832804754357d0e741c51b509a54 Mon Sep 17 00:00:00 2001 From: williamrusdyputra Date: Mon, 15 Sep 2025 14:33:35 +0700 Subject: [PATCH 4/7] fix: type --- internal/migrations/024-erc20-bridge.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/migrations/024-erc20-bridge.sql b/internal/migrations/024-erc20-bridge.sql index 3d506d6c0..c2ab9f72d 100644 --- a/internal/migrations/024-erc20-bridge.sql +++ b/internal/migrations/024-erc20-bridge.sql @@ -28,7 +28,7 @@ CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at LIMIT 1 { $fee := $num_amount * $config.fee_percentage; - IF $fee > 0 { + IF $fee > 0::NUMERIC(78, 0) { sepolia_bridge.lock($fee); sepolia_bridge.unlock($config.treasury_address, $fee); } @@ -51,7 +51,7 @@ CREATE OR REPLACE ACTION mainnet_admin_bridge_tokens($amount TEXT) PUBLIC { FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at LIMIT 1 { $fee := $num_amount * $config.fee_percentage; - IF $fee > 0 { + IF $fee > 0::NUMERIC(78, 0) { mainnet_bridge.lock($fee); mainnet_bridge.unlock($config.treasury_address, $fee); } From 11438aad2896a733c07d65122d3d419d42910f62 Mon Sep 17 00:00:00 2001 From: williamrusdyputra Date: Mon, 15 Sep 2025 15:03:46 +0700 Subject: [PATCH 5/7] fix: if not found config --- internal/migrations/024-erc20-bridge.sql | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/internal/migrations/024-erc20-bridge.sql b/internal/migrations/024-erc20-bridge.sql index c2ab9f72d..30e0bcd80 100644 --- a/internal/migrations/024-erc20-bridge.sql +++ b/internal/migrations/024-erc20-bridge.sql @@ -25,7 +25,8 @@ CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { $num_amount := $amount::NUMERIC(78, 0); -- Get fee configuration for withdraw - FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at LIMIT 1 { + $found := 0 + FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at DESC LIMIT 1 { $fee := $num_amount * $config.fee_percentage; IF $fee > 0::NUMERIC(78, 0) { @@ -35,7 +36,10 @@ CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { -- Bridge the rest to users sepolia_bridge.bridge($num_amount - $fee); + $found := 1; } + + IF $found = 0 { ERROR('No fee_configs rows for operation_type=withdraw'); } }; -- MAINNET @@ -44,11 +48,12 @@ CREATE OR REPLACE ACTION mainnet_wallet_balance($wallet_address TEXT) PUBLIC VIE RETURN $balance; }; -CREATE OR REPLACE ACTION mainnet_admin_bridge_tokens($amount TEXT) PUBLIC { +CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { $num_amount := $amount::NUMERIC(78, 0); -- Get fee configuration for withdraw - FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at LIMIT 1 { + $found := 0 + FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at DESC LIMIT 1 { $fee := $num_amount * $config.fee_percentage; IF $fee > 0::NUMERIC(78, 0) { @@ -58,5 +63,8 @@ CREATE OR REPLACE ACTION mainnet_admin_bridge_tokens($amount TEXT) PUBLIC { -- Bridge the rest to users mainnet_bridge.bridge($num_amount - $fee); + $found := 1; } + + IF $found = 0 { ERROR('No fee_configs rows for operation_type=withdraw'); } }; \ No newline at end of file From 8a8128cb14ece814acb6b8128cfa93f43022caeb Mon Sep 17 00:00:00 2001 From: williamrusdyputra Date: Mon, 15 Sep 2025 15:14:12 +0700 Subject: [PATCH 6/7] fix: naming --- internal/migrations/024-erc20-bridge.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/migrations/024-erc20-bridge.sql b/internal/migrations/024-erc20-bridge.sql index 30e0bcd80..8772354da 100644 --- a/internal/migrations/024-erc20-bridge.sql +++ b/internal/migrations/024-erc20-bridge.sql @@ -25,7 +25,7 @@ CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { $num_amount := $amount::NUMERIC(78, 0); -- Get fee configuration for withdraw - $found := 0 + $found := 0; FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at DESC LIMIT 1 { $fee := $num_amount * $config.fee_percentage; @@ -48,11 +48,11 @@ CREATE OR REPLACE ACTION mainnet_wallet_balance($wallet_address TEXT) PUBLIC VIE RETURN $balance; }; -CREATE OR REPLACE ACTION sepolia_admin_bridge_tokens($amount TEXT) PUBLIC { +CREATE OR REPLACE ACTION mainnet_admin_bridge_tokens($amount TEXT) PUBLIC { $num_amount := $amount::NUMERIC(78, 0); -- Get fee configuration for withdraw - $found := 0 + $found := 0; FOR $config IN SELECT fee_percentage, treasury_address FROM fee_configs WHERE operation_type = 'withdraw' ORDER BY created_at DESC LIMIT 1 { $fee := $num_amount * $config.fee_percentage; From 97d0cafae0554527b55f7e3d6826c22d993ac6e0 Mon Sep 17 00:00:00 2001 From: williamrusdyputra Date: Mon, 15 Sep 2025 18:21:59 +0700 Subject: [PATCH 7/7] chore: remove default insert --- internal/migrations/023-fee-configs.sql | 6 ------ 1 file changed, 6 deletions(-) diff --git a/internal/migrations/023-fee-configs.sql b/internal/migrations/023-fee-configs.sql index 851904894..03796aaf1 100644 --- a/internal/migrations/023-fee-configs.sql +++ b/internal/migrations/023-fee-configs.sql @@ -16,12 +16,6 @@ CREATE TABLE IF NOT EXISTS fee_configs ( CHECK (treasury_address LIKE '0x%' AND LENGTH(treasury_address) = 42) ); --- Insert default fee configurations -INSERT INTO fee_configs (operation_type, fee_percentage, treasury_address, created_at, updated_at) VALUES -('deposit', 0.0100, '0xDe5B2aBce299eBdC3567895B1B4b02Ca2c33C94A', @height, @height), -('withdraw', 0.0100, '0xDe5B2aBce299eBdC3567895B1B4b02Ca2c33C94A', @height, @height) -ON CONFLICT (operation_type) DO NOTHING; - -- Action to get fee configuration by operation type CREATE OR REPLACE ACTION get_fee_config_by_type($operation_type TEXT) PUBLIC VIEW RETURNS (