@keygate/onesec
v0.10.4
Published
A library for interacting with the onesec.to bridge
Maintainers
Readme
OneSec Bridge SDK
A TypeScript SDK for bridging tokens between EVM chains (Ethereum, Arbitrum, Base) and the Internet Computer (ICP) using the OneSec bridge protocol.
Features
- Bi-directional bridging: Transfer tokens from EVM chains to ICP and vice versa
- Multiple bridging modes: Direct wallet-based bridging and forwarding address bridging
- Step-by-step execution: Track progress and handle errors at each step
Installation
# with npm
npm install onesec-bridge
# with pnpm
pnpm add onesec-bridge
# with yarn
yarn add onesec-bridgeQuick Start
EVM to ICP Bridging (Direct)
Use this approach when users can connect their wallet and sign transactions directly.
import { EvmToIcpBridgeBuilder } from "onesec-bridge";
import { JsonRpcProvider, Wallet } from "ethers";
import { Principal } from "@dfinity/principal";
// Setup wallet or use the browser wallet API.
const provider = new JsonRpcProvider("https://mainnet.base.org");
const wallet = new Wallet("your-private-key", provider);
// Create bridging plan
const plan = await new EvmToIcpBridgeBuilder("Base", "USDC")
.receiver(Principal.fromText("your-icp-principal"))
.amountInTokens(1_500_000n) // 1.5 USDC
// alternative: use `.amountInTokens(1.5)`
.build(wallet);
// Print plan overview
console.log("Plan steps:");
plan.steps().forEach((step, index) => {
console.log(` ${index + 1}. ${step.about().verbose}`);
});
// Execute step by step with progress tracking
let nextStep;
while (nextStep = plan.nextStepToRun()) {
const status = nextStep.status();
if (status.state === "planned") {
console.log(nextStep.about().verbose);
}
try {
const result = await nextStep.run();
console.log(` - ${result.verbose}`);
} catch (error) {
console.error("Step execution failed:", error);
break;
}
}
// Get final results after completion
const finalStep = plan.latestStep();
if (finalStep) {
const status = finalStep.status();
if (status.state === "succeeded") {
console.log("Bridging completed successfully!");
if (status.amount) {
console.log(`Received: ${status.amount.inTokens} USDC`);
}
if (status.transaction) {
console.log(`Transaction: ${JSON.stringify(status.transaction)}`);
}
}
}EVM to ICP Bridging (Forwarding Address)
Use this approach when users cannot connect a wallet or prefer to send tokens manually.
import { EvmToIcpBridgeBuilder } from "onesec-bridge";
import { Principal } from "@dfinity/principal";
// Create forwarding-based bridging plan
const plan = await new EvmToIcpBridgeBuilder("Base", "USDC")
.receiver(Principal.fromText("your-icp-principal"))
.forward();
// Execute with progress tracking
let nextStep;
while (nextStep = plan.nextStepToRun()) {
const status = nextStep.status();
if (status.state === "planned") {
console.log(nextStep.about().verbose);
}
try {
const result = await nextStep.run();
console.log(` - ${result.verbose}`);
// Show forwarding address to user
if (result.forwardingAddress) {
console.log(`Please send USDC to: ${result.forwardingAddress}`);
// Wait for user to send tokens before continuing
}
} catch (error) {
console.error("Step execution failed:", error);
break;
}
}
// Get final results after completion
const finalStep = plan.latestStep();
if (finalStep) {
const status = finalStep.status();
if (status.state === "succeeded") {
console.log("Bridging completed successfully!");
if (status.amount) {
console.log(`Received: ${status.amount.inTokens} USDC`);
}
if (status.transaction) {
console.log(`ICP Transaction: ${JSON.stringify(status.transaction)}`);
}
}
}ICP to EVM Bridging
Transfer tokens from ICP to EVM chains. Requires an authenticated ICP agent.
import { IcpToEvmBridgeBuilder } from "onesec-bridge";
import { HttpAgent } from "@dfinity/agent";
import { Secp256k1KeyIdentity } from "@dfinity/identity-secp256k1";
// Setup ICP identity and agent
const identity = Secp256k1KeyIdentity.fromSecretKey(/* your private key */);
const agent = HttpAgent.createSync({
identity,
host: "https://ic0.app",
});
// Create bridging plan
const plan = await new IcpToEvmBridgeBuilder(agent, "Base", "USDC")
.sender(identity.getPrincipal())
.receiver("0x742d35Cc6575C4B9bE904C1e13D21c4C624A9960")
.amountInUnits(1_500_000n) // 1.5 USDC
// alternative: use `.amountInTokens(1.5)`
.build();
// Execute with progress tracking
let nextStep;
while (nextStep = plan.nextStepToRun()) {
const status = nextStep.status();
if (status.state === "planned") {
console.log(nextStep.about().verbose);
}
try {
const result = await nextStep.run();
console.log(` - ${result.verbose}`);
} catch (error) {
console.error("Step execution failed:", error);
break;
}
}
// Get final results after completion
const finalStep = plan.latestStep();
if (finalStep) {
const status = finalStep.status();
if (status.state === "succeeded") {
console.log("Bridging completed successfully!");
if (status.amount) {
console.log(`Received: ${status.amount.inTokens} USDC`);
}
if (status.transaction) {
console.log(`EVM Transaction: ${JSON.stringify(status.transaction)}`);
}
}
}Supported Networks and Tokens
EVM Chains
- Ethereum
- Arbitrum
- Base
Tokens
- USDC
- USDT
- ICP
- ckBTC
- cbBTC
- BOB
- GLDT
Migration from v0.7.x
If you're using the deprecated oneSecForwarding() function:
// Old approach (deprecated)
const forwarding = oneSecForwarding();
const address = await forwarding.addressFor(receiver);
// New approach
const plan = await new EvmToIcpBridgeBuilder("Base", "USDC")
.receiver(principal)
.amountInUnits(amount)
.forward();Documentation
-
:factory: IcpToEvmBridgeBuilder
Builder for creating ICP to EVM token bridging plans.
Transfers tokens from ICP ledgers to EVM networks. Requires an authenticated agent to interact with ICP canisters on behalf of the user.
Methods
:gear: deployment
Set target deployment network.
| Method | Type |
| ---------- | ---------- |
| deployment | (deployment: Deployment) => IcpToEvmBridgeBuilder |
Parameters:
deployment: Target network ("Mainnet", "Testnet", or "Local")
:gear: sender
Set sender ICP account.
| Method | Type |
| ---------- | ---------- |
| sender | (principal: Principal, subaccount?: Uint8Array<ArrayBufferLike> or undefined) => IcpToEvmBridgeBuilder |
Parameters:
principal: ICP principal sending the tokenssubaccount: Optional 32-byte subaccount
:gear: receiver
Set EVM recipient address.
| Method | Type |
| ---------- | ---------- |
| receiver | (address: string) => IcpToEvmBridgeBuilder |
Parameters:
address: EVM address receiving the tokens
:gear: amountInUnits
Set amount to bridge in token's smallest units.
| Method | Type |
| ---------- | ---------- |
| amountInUnits | (amount: bigint) => IcpToEvmBridgeBuilder |
Parameters:
amount: Amount in base units (e.g., 1_500_000n for 1.5 USDC)
:gear: amountInTokens
Set amount to bridge in human-readable token units.
| Method | Type |
| ---------- | ---------- |
| amountInTokens | (amount: number) => IcpToEvmBridgeBuilder |
Parameters:
amount: Amount in token units (e.g., 1.5 for 1.5 USDC)
:gear: payApproveFeeFromAmount
Deduct the ledger approval fee from the bridging amount.
When enabled, the approval fee is subtracted from the specified amount, so the user only needs to have exactly the bridging amount in their account rather than bridging amount + approval fee.
| Method | Type |
| ---------- | ---------- |
| payApproveFeeFromAmount | () => IcpToEvmBridgeBuilder |
Examples:
// Without payApproveFeeFromAmount(): User needs 1.5 USDC + approval fee
const plan1 = await builder.amountInUnits(1_500_000n).build();
// With payApproveFeeFromAmount(): User needs exactly 1.5 USDC, approval fee deducted from amount
const plan2 = await builder.amountInUnits(1_500_000n).payApproveFeeFromAmount().build();:gear: withConfig
Use custom configuration instead of defaults.
| Method | Type |
| ---------- | ---------- |
| withConfig | (config: Config) => IcpToEvmBridgeBuilder |
Parameters:
config: Custom bridge configuration
:factory: EvmToIcpBridgeBuilder
Builder for creating EVM to ICP token bridging plans.
Supports two bridging modes:
- Direct bridging via
build()- requires user to connect wallet and sign transactions - Forwarding via
forward()- user sends tokens to a generated forwarding address
Methods
:gear: deployment
Set target deployment network.
| Method | Type |
| ---------- | ---------- |
| deployment | (deployment: Deployment) => EvmToIcpBridgeBuilder |
Parameters:
deployment: Target network ("Mainnet", "Testnet", or "Local")
:gear: sender
Set sender EVM address. Optional for direct bridging (inferred from signer).
| Method | Type |
| ---------- | ---------- |
| sender | (evmAddress: string) => EvmToIcpBridgeBuilder |
Parameters:
evmAddress: EVM address sending the tokens
:gear: amountInUnits
Set amount to bridge in token's smallest units.
| Method | Type |
| ---------- | ---------- |
| amountInUnits | (amount: bigint) => EvmToIcpBridgeBuilder |
Parameters:
amount: Amount in base units (e.g., 1_500_000n for 1.5 USDC)
:gear: amountInTokens
Set amount to bridge in human-readable token units.
| Method | Type |
| ---------- | ---------- |
| amountInTokens | (amount: number) => EvmToIcpBridgeBuilder |
Parameters:
amount: Amount in token units (e.g., 1.5 for 1.5 USDC)
:gear: receiver
Set ICP recipient account.
| Method | Type |
| ---------- | ---------- |
| receiver | (principal: Principal, subaccount?: Uint8Array<ArrayBufferLike> or undefined) => EvmToIcpBridgeBuilder |
Parameters:
principal: ICP principal receiving the tokenssubaccount: Optional 32-byte subaccount
:gear: withConfig
Use custom configuration instead of defaults.
| Method | Type |
| ---------- | ---------- |
| withConfig | (config: Config) => EvmToIcpBridgeBuilder |
Parameters:
config: Custom bridge configuration
License
MIT
Support
For issues and questions:
