Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/adapters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ import teleswap from "./teleswap";
import agglayer from "./agglayer";
import fxrp from "./flare/fxrp";
import snowbridge from "./snowbridge";
import kaspabridge from "./kaspabridge";
import hyperbridge from "./hyperbridge";
import starkgate from "./starkgate";
import onesec from "./1sec";
Expand Down Expand Up @@ -200,6 +201,7 @@ export default {
agglayer,
fxrp,
snowbridge,
kaspabridge,
hyperbridge,
starkgate,
"1sec": onesec,
Expand Down
107 changes: 107 additions & 0 deletions src/adapters/kaspabridge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as sdk from "@defillama/sdk";
import { BridgeAdapter } from "../../helpers/bridgeAdapter.type";
import { BigNumber, utils } from "ethers";

const MAILBOX_BSC = "0x5f297B3A1e8154c4D58702F7a880b7631bBf5340";

const ABI = [
"event Dispatch(bytes32 indexed id, uint32 indexed destinationDomain, bytes32 recipientAddress, bytes messageBody)",
"event Process(bytes32 indexed id, bool success)"
];

const iface = new utils.Interface(ABI);

function decodeMessageBody(body: string) {
try {
const coder = new utils.AbiCoder();
const [from, to, token, amount] = coder.decode(
["address", "address", "address", "uint256"],
body
);
return { from, to, token, amount: BigNumber.from(amount) };
} catch {
return null; // Important: return null to indicate failure
}
}

async function getKaspaBridgeEvents(fromBlock: number, toBlock: number) {
const events: any[] = [];

const dispatchMap = new Map<
string,
{ from: string; to: string; token: string; amount: BigNumber }
>();

// ---------------------- FETCH DISPATCH EVENTS ----------------------
const dispatch = await sdk.api.util.getLogs({
target: MAILBOX_BSC,
topic: "Dispatch(bytes32,uint32,bytes32,bytes)",
keys: [],
fromBlock,
toBlock,
chain: "bsc",
});

for (const log of dispatch.output) {
const parsed = iface.parseLog({
data: log.data,
// @ts-ignore
topics: log.topics,
});

const decoded = decodeMessageBody(parsed.args.messageBody);
if (!decoded) continue; // Skip invalid message bodies

dispatchMap.set(log.transactionHash, decoded);

events.push({
txHash: log.transactionHash,
blockNumber: log.blockNumber,
from: decoded.from,
to: decoded.to,
token: decoded.token,
isDeposit: true,
amount: decoded.amount,
});
}

// ---------------------- FETCH PROCESS EVENTS ----------------------
const process = await sdk.api.util.getLogs({
target: MAILBOX_BSC,
topic: "Process(bytes32,bool)",
keys: [],
fromBlock,
toBlock,
chain: "bsc",
});

for (const log of process.output) {
const dispatchData = dispatchMap.get(log.transactionHash);

// >>> Maintainer request: SKIP events without dispatch data
if (!dispatchData) continue;

events.push({
txHash: log.transactionHash,
blockNumber: log.blockNumber,
from: dispatchData.from,
to: dispatchData.to,
token: dispatchData.token,
isDeposit: false,
amount: dispatchData.amount,
});
}

return events;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets filter events without from,to,token (without dispatch data)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done , please review now and merge it .

}

export async function build(): Promise<BridgeAdapter> {
return {
bsc: getKaspaBridgeEvents,
};
}

export default {
isAsync: true,
build,
};
16 changes: 16 additions & 0 deletions src/data/bridgeNetworkData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2717,4 +2717,20 @@ export default [
chains: ["Ethereum", "Arbitrum", "Base", "ICP"],
destinationChain: "ICP"
},
{
id: 105,
displayName: "Kaspa Bridge",
bridgeDbName: "kaspabridge",
slug: "kaspabridge",
iconLink: "icons:kaspabridge",
largeTxThreshold: 10000,
url: "https://www.kaspabridge.com/",
chains: [
"kasplex",
"bsc",
],
chainMapping: {
avalanche: "avax",
}
},
] as BridgeNetwork[];