diff --git a/python/coinbase-agentkit/coinbase_agentkit/action_providers/pyth/pyth_action_provider.py b/python/coinbase-agentkit/coinbase_agentkit/action_providers/pyth/pyth_action_provider.py index c71913720..eac0b0e3c 100644 --- a/python/coinbase-agentkit/coinbase_agentkit/action_providers/pyth/pyth_action_provider.py +++ b/python/coinbase-agentkit/coinbase_agentkit/action_providers/pyth/pyth_action_provider.py @@ -46,7 +46,7 @@ def fetch_price_feed_id(self, args: dict[str, Any]) -> str: """ token_symbol = args["token_symbol"] url = f"https://hermes.pyth.network/v2/price_feeds?query={token_symbol}&asset_type=crypto" - response = requests.get(url) + response = requests.get(url, timeout=10) response.raise_for_status() data = response.json() @@ -86,7 +86,7 @@ def fetch_price(self, args: dict[str, Any]) -> str: try: price_feed_id = args["price_feed_id"] url = f"https://hermes.pyth.network/v2/updates/price/latest?ids[]={price_feed_id}" - response = requests.get(url) + response = requests.get(url, timeout=10) response.raise_for_status() data = response.json() parsed_data = data["parsed"] diff --git a/python/coinbase-agentkit/coinbase_agentkit/analytics/send_analytics_event.py b/python/coinbase-agentkit/coinbase_agentkit/analytics/send_analytics_event.py index 945ee6b37..99d1a9e1e 100644 --- a/python/coinbase-agentkit/coinbase_agentkit/analytics/send_analytics_event.py +++ b/python/coinbase-agentkit/coinbase_agentkit/analytics/send_analytics_event.py @@ -51,7 +51,10 @@ def send_analytics_event(event: RequiredEventData) -> None: stringified_event_data = json.dumps(events) upload_time = str(timestamp) - checksum = hashlib.md5((stringified_event_data + upload_time).encode("utf-8")).hexdigest() + # Use a non-cryptographic checksum compatible with the analytics backend without + # exposing weak crypto primitives for integrity; md5 is insecure and should + # not be used for security-sensitive operations. + checksum = hashlib.sha256((stringified_event_data + upload_time).encode("utf-8")).hexdigest() analytics_service_data = { "e": stringified_event_data, @@ -66,5 +69,6 @@ def send_analytics_event(event: RequiredEventData) -> None: event_endpoint, json=analytics_service_data, headers={"Content-Type": "application/json"}, + timeout=10, ) response.raise_for_status() diff --git a/python/create-onchain-agent/create_onchain_agent/cli.py b/python/create-onchain-agent/create_onchain_agent/cli.py index e3fb4e2e4..1c0770899 100755 --- a/python/create-onchain-agent/create_onchain_agent/cli.py +++ b/python/create-onchain-agent/create_onchain_agent/cli.py @@ -104,7 +104,7 @@ def get_template_path(template_name: str, templates_path: str | None = None) -> return str(extract_path) # Download the zip file - response = requests.get(GITHUB_ZIP_URL) + response = requests.get(GITHUB_ZIP_URL, timeout=20) response.raise_for_status() with open(zip_path, "wb") as f: diff --git a/typescript/agentkit/src/action-providers/opensea/openseaActionProvider.ts b/typescript/agentkit/src/action-providers/opensea/openseaActionProvider.ts index 7d7415b68..7c67b524e 100644 --- a/typescript/agentkit/src/action-providers/opensea/openseaActionProvider.ts +++ b/typescript/agentkit/src/action-providers/opensea/openseaActionProvider.ts @@ -51,7 +51,9 @@ export class OpenseaActionProvider extends ActionProvider { this.apiKey = apiKey; const chainId = NETWORK_ID_TO_CHAIN_ID[config.networkId || "base-sepolia"]; - const provider = ethers.getDefaultProvider(parseInt(chainId)); + // Ensure a default provider is created with an explicit network definition. + // Passing an ID as a number without a network can resolve incorrectly in some ethers versions. + const provider = ethers.getDefaultProvider(Number.parseInt(chainId, 10)); const walletWithProvider = new Wallet(config.privateKey!, provider); this.walletWithProvider = walletWithProvider; diff --git a/typescript/agentkit/src/action-providers/wow/utils.ts b/typescript/agentkit/src/action-providers/wow/utils.ts index 811d25731..b553ee843 100644 --- a/typescript/agentkit/src/action-providers/wow/utils.ts +++ b/typescript/agentkit/src/action-providers/wow/utils.ts @@ -45,7 +45,8 @@ export async function getBuyQuote( address: tokenAddress as `0x${string}`, abi: WOW_ABI, functionName: "getEthBuyQuote", - args: [amountEthInWei], + // Ensure the argument is passed as a bigint to match on-chain units + args: [BigInt(amountEthInWei)], }) ) as string | number; @@ -74,7 +75,8 @@ export async function getSellQuote( address: tokenAddress as `0x${string}`, abi: WOW_ABI, functionName: "getTokenSellQuote", - args: [amountTokensInWei], + // Ensure the argument is passed as a bigint to match on-chain units + args: [BigInt(amountTokensInWei)], }) ) as string | number; diff --git a/typescript/agentkit/src/utils.ts b/typescript/agentkit/src/utils.ts index 66c0b0bde..702f7c4b4 100644 --- a/typescript/agentkit/src/utils.ts +++ b/typescript/agentkit/src/utils.ts @@ -60,5 +60,12 @@ export async function approve( * @returns The adjusted gas estimate as a bigint. */ export function applyGasMultiplier(gas: bigint, multiplier: number): bigint { - return BigInt(Math.round(Number(gas) * multiplier)); + if (!Number.isFinite(multiplier) || multiplier <= 0) return gas; + if (multiplier === 1) return gas; + + // Perform bigint-safe scaling with fixed precision to avoid Number(gas) loss + const SCALE = 1000n; // three decimal places of precision + const scaledMultiplier = BigInt(Math.round(multiplier * Number(SCALE))); + // Round half-up by adding half the divisor before integer division + return (gas * scaledMultiplier + SCALE / 2n) / SCALE; } diff --git a/typescript/create-onchain-agent/src/utils.ts b/typescript/create-onchain-agent/src/utils.ts index e326e2b8e..e7758709c 100644 --- a/typescript/create-onchain-agent/src/utils.ts +++ b/typescript/create-onchain-agent/src/utils.ts @@ -267,7 +267,9 @@ export async function handleNextSelection( .filter(Boolean) .join("\n"), ]; - await fs.writeFile(envPath, envLines); + // Persist the environment file as a single string. Passing an array would + // coerce to a comma-joined string implicitly, corrupting the .env format. + await fs.writeFile(envPath, envLines.join("\n")); // Promose selected routes to const promoteRoute = async (toPromose: string, type: string, to: string) => {