Skip to content

Commit

Permalink
feat: fixing followups and adding integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
geekbrother committed Oct 24, 2024
1 parent a43e611 commit 68a1395
Show file tree
Hide file tree
Showing 19 changed files with 797 additions and 61 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export RPC_PROXY_PROVIDER_GETBLOCK_ACCESS_TOKENS='{}'
export RPC_PROXY_PROVIDER_PIMLICO_API_KEY=""
export RPC_PROXY_PROVIDER_SOLSCAN_API_V1_TOKEN=""
export RPC_PROXY_PROVIDER_SOLSCAN_API_V2_TOKEN=""
export RPC_PROXY_PROVIDER_BUNGEE_API_KEY=""

# PostgreSQL URI connection string
export RPC_PROXY_POSTGRES_URI="postgres://postgres@localhost/postgres"
Expand Down
1 change: 1 addition & 0 deletions .env.terraform.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export TF_VAR_getblock_access_tokens='{}'
export TF_VAR_pimlico_api_key=""
export TF_VAR_solscan_api_v1_token=""
export TF_VAR_solscan_api_v2_token=""
export TF_VAR_bungee_api_key=""
export TF_VAR_grafana_endpoint=$(aws grafana list-workspaces | jq -r '.workspaces[] | select( .tags.Env == "prod") | select( .tags.Name == "grafana-9") | .endpoint')
export TF_VAR_registry_api_auth_token=""
export TF_VAR_debug_secret=""
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/event_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ jobs:
RPC_PROXY_PROVIDER_PIMLICO_API_KEY: ""
RPC_PROXY_PROVIDER_SOLSCAN_API_V1_TOKEN: ""
RPC_PROXY_PROVIDER_SOLSCAN_API_V2_TOKEN: ""
RPC_PROXY_PROVIDER_BUNGEE_API_KEY: ""
- run: docker logs mock-bundler-anvil-1
if: failure()
- run: docker logs mock-bundler-alto-1
Expand Down
1 change: 1 addition & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ allow = [
"0BSD",
"ISC",
"MPL-2.0",
"Zlib",
]

exceptions = [{ name = "unicode-ident", allow = ["Unicode-DFS-2016"] }]
Expand Down
183 changes: 183 additions & 0 deletions integration/chain_orchestrator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { getTestSetup } from './init';
import { ethers, Interface } from "ethers"

describe('Chain abstraction orchestrator', () => {
const { baseUrl, projectId, httpClient } = getTestSetup();
const erc20Interface = new Interface([
'function transfer(address to, uint256 amount)',
]);

// Address with 3 USDC on Base chain
const from_address_with_funds = "0x2Aae531A81461F029cD55Cb46703211c9227ba05";
const usdc_funds_on_address = 3_000_000;

const receiver_address = "0x739ff389c8eBd9339E69611d46Eec6212179BB67";
const chain_id_optimism = "eip155:10";
const chain_id_base = "eip155:8453";
const usdc_contract_optimism = "0x0b2c639c533813f4aa9d7837caf62653d097ff85";

it('bridging available', async () => {
// Sending USDC to Optimism, but having the USDC balance on Base chain
const amount_to_send_in_decimals = usdc_funds_on_address - 1_000_000
const data_encoded = erc20Interface.encodeFunctionData('transfer', [
receiver_address,
amount_to_send_in_decimals,
]);

let transactionObj = {
transaction: {
from: from_address_with_funds,
to: usdc_contract_optimism,
value: "0x00", // Zero native tokens
gas: "0x00",
gasPrice: "0x00",
data: data_encoded,
nonce: "0x00",
maxFeePerGas: "0x00",
maxPriorityFeePerGas: "0x00",
chainId: chain_id_optimism,
}
}

let resp: any = await httpClient.post(
`${baseUrl}/v1/ca/orchestrator/check?projectId=${projectId}`,
transactionObj
)
expect(resp.status).toBe(200)
expect(typeof resp.data.requiresMultiChain).toBe('boolean')
expect(resp.data.requiresMultiChain).toBe(true)
})

it('bridging unavailable (insufficient funds)', async () => {
// Having the USDC balance on Base chain less then the amount to send
const amount_to_send_in_decimals = usdc_funds_on_address + 1_000_000
const data_encoded = erc20Interface.encodeFunctionData('transfer', [
receiver_address,
amount_to_send_in_decimals,
]);

let transactionObj = {
transaction: {
from: from_address_with_funds,
to: usdc_contract_optimism,
value: "0x00", // Zero native tokens
gas: "0x00",
gasPrice: "0x00",
data: data_encoded,
nonce: "0x00",
maxFeePerGas: "0x00",
maxPriorityFeePerGas: "0x00",
chainId: chain_id_optimism,
}
}

let resp: any = await httpClient.post(
`${baseUrl}/v1/ca/orchestrator/check?projectId=${projectId}`,
transactionObj
)
expect(resp.status).toBe(200)
expect(typeof resp.data.requiresMultiChain).toBe('boolean')
expect(resp.data.requiresMultiChain).toBe(false)
})

it('bridging unavailable (empty wallet)', async () => {
// Checking an empty wallet
const amount_to_send_in_decimals = usdc_funds_on_address
const empty_wallet_address = ethers.Wallet.createRandom().address
const data_encoded = erc20Interface.encodeFunctionData('transfer', [
receiver_address,
amount_to_send_in_decimals,
]);

let transactionObj = {
transaction: {
from: empty_wallet_address,
to: usdc_contract_optimism,
value: "0x00", // Zero native tokens
gas: "0x00",
gasPrice: "0x00",
data: data_encoded,
nonce: "0x00",
maxFeePerGas: "0x00",
maxPriorityFeePerGas: "0x00",
chainId: chain_id_optimism,
}
}

let resp: any = await httpClient.post(
`${baseUrl}/v1/ca/orchestrator/check?projectId=${projectId}`,
transactionObj
)
expect(resp.status).toBe(200)
expect(typeof resp.data.requiresMultiChain).toBe('boolean')
expect(resp.data.requiresMultiChain).toBe(false)
})

it('bridging routes (no routes)', async () => {
// Sending USDC to Optimism, having the USDC balance on Base chain
// with MIN_AMOUNT_NOT_MET error expected
const amount_to_send_in_decimals = 20_000 // Less then minimum amount required
const data_encoded = erc20Interface.encodeFunctionData('transfer', [
receiver_address,
amount_to_send_in_decimals,
]);

let transactionObj = {
transaction: {
from: from_address_with_funds,
to: usdc_contract_optimism,
value: "0x00", // Zero native tokens
gas: "0x00",
gasPrice: "0x00",
data: data_encoded,
nonce: "0x00",
maxFeePerGas: "0x00",
maxPriorityFeePerGas: "0x00",
chainId: chain_id_optimism,
}
}

let resp: any = await httpClient.post(
`${baseUrl}/v1/ca/orchestrator/route?projectId=${projectId}`,
transactionObj
)
expect(resp.status).toBe(400)
})

it('bridging routes (routes available)', async () => {
// Sending USDC to Optimism, but having the USDC balance on Base chain
const amount_to_send_in_decimals = usdc_funds_on_address - 1_000_000
const data_encoded = erc20Interface.encodeFunctionData('transfer', [
receiver_address,
amount_to_send_in_decimals,
]);

let transactionObj = {
transaction: {
from: from_address_with_funds,
to: usdc_contract_optimism,
value: "0x00", // Zero native tokens
gas: "0x00",
gasPrice: "0x00",
data: data_encoded,
nonce: "0x00",
maxFeePerGas: "0x00",
maxPriorityFeePerGas: "0x00",
chainId: chain_id_optimism,
}
}

let resp: any = await httpClient.post(
`${baseUrl}/v1/ca/orchestrator/route?projectId=${projectId}`,
transactionObj
)
expect(resp.status).toBe(200)

const data = resp.data
expect(typeof data.orchestrationId).toBe('string')
// First transaction expected to be the bridging to the Base
expect(data.transactions[0].chainId).toBe(chain_id_base)
// The second transaction expected to be the initial one
expect(data.transactions[1].chainId).toBe(chain_id_optimism)
})
})
3 changes: 3 additions & 0 deletions src/analytics/message_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ mod tests {

let source = MessageSource::SessionCoSignSigValidate;
assert_eq!(source.to_string(), "session_co_sign_sig_validate");

let source = MessageSource::ChainAgnosticCheck;
assert_eq!(source.to_string(), "chain_agnostic_check");
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions src/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ mod test {
"RPC_PROXY_PROVIDER_SOLSCAN_API_V2_TOKEN",
"SOLSCAN_API_V2_TOKEN",
),
("RPC_PROXY_PROVIDER_BUNGEE_API_KEY", "BUNGEE_API_KEY"),
(
"RPC_PROXY_PROVIDER_PROMETHEUS_QUERY_URL",
"PROMETHEUS_QUERY_URL",
Expand Down Expand Up @@ -275,6 +276,7 @@ mod test {
pimlico_api_key: "PIMLICO_API_KEY".to_string(),
solscan_api_v1_token: "SOLSCAN_API_V1_TOKEN".to_string(),
solscan_api_v2_token: "SOLSCAN_API_V2_TOKEN".to_string(),
bungee_api_key: "BUNGEE_API_KEY".to_string(),
override_bundler_urls: None,
},
rate_limiting: RateLimitingConfig {
Expand Down
33 changes: 33 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@ pub enum RpcError {

#[error("ABI decoding error: {0}")]
AbiDecodingError(String),

#[error("No bridging needed")]
NoBridgingNeeded,

#[error("No bridging available")]
NoBridgingAvailable,

#[error("No routes available for the bridging")]
NoBridgingRoutesAvailable,
}

impl IntoResponse for RpcError {
Expand Down Expand Up @@ -622,6 +631,30 @@ impl IntoResponse for RpcError {
)),
)
.into_response(),
Self::NoBridgingNeeded => (
StatusCode::BAD_REQUEST,
Json(new_error_response(
"".to_string(),
"No bridging needed".to_string(),
)),
)
.into_response(),
Self::NoBridgingAvailable => (
StatusCode::BAD_REQUEST,
Json(new_error_response(
"".to_string(),
"No bridging available".to_string(),
)),
)
.into_response(),
Self::NoBridgingRoutesAvailable => (
StatusCode::BAD_REQUEST,
Json(new_error_response(
"".to_string(),
"No bridging routes available".to_string(),
)),
)
.into_response(),
// Any other errors considering as 500
_ => (
StatusCode::INTERNAL_SERVER_ERROR,
Expand Down
Loading

0 comments on commit 68a1395

Please sign in to comment.