Skip to content

feat: add fiber-sdk#194

Open
ashuralyk wants to merge 37 commits intockb-devrel:masterfrom
ashuralyk:feat/fiber-sdk
Open

feat: add fiber-sdk#194
ashuralyk wants to merge 37 commits intockb-devrel:masterfrom
ashuralyk:feat/fiber-sdk

Conversation

@ashuralyk
Copy link
Contributor

@ashuralyk ashuralyk commented Apr 16, 2025

Background

Taking advantage of fiber-js to implement a basic usable fiber-sdk in ccc, which contains only features of channel, invoice and payment.

Inside test cases, there're two native fiber nodes started by fiber-js with interconnection, all the cases would interact with them to validate channel, invoice and payment functionalities, without needs of any outside fiber nodes.

@changeset-bot
Copy link

changeset-bot bot commented Apr 16, 2025

🦋 Changeset detected

Latest commit: e0f89ac

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@ashuralyk ashuralyk marked this pull request as ready for review April 19, 2025 00:52
@Hanssen0 Hanssen0 force-pushed the master branch 2 times, most recently from 4f1083c to 1d5d04d Compare June 7, 2025 20:12
ashuralyk and others added 23 commits February 4, 2026 10:03
- 修改 Script 接口中 args 的类型从 string[] 改为 string
- 修改 shutdownChannel 函数中的 close_script.args 参数格式
- 确保所有参数都符合 API 期望的十六进制字符串格式
- 修改 Script 接口中 args 的类型从 string[] 改为 string
- 修改 shutdownChannel 函数中的 close_script.args 参数格式
- 确保所有参数都符合 API 期望的十六进制字符串格式
- 更新相关依赖和工具函数

这个修改解决了通道关闭时出现的 'invalid type: sequence, expected a 0x-prefixed hex string' 错误。
@netlify
Copy link

netlify bot commented Feb 23, 2026

Deploy Preview for appccc ready!

Name Link
🔨 Latest commit e0f89ac
🔍 Latest deploy log https://app.netlify.com/projects/appccc/deploys/69c25451063f360008469b87
😎 Deploy Preview https://deploy-preview-194--appccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 73 (🔴 down 13 from production)
Accessibility: 89 (🟢 up 1 from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Feb 23, 2026

Deploy Preview for apiccc ready!

Name Link
🔨 Latest commit e0f89ac
🔍 Latest deploy log https://app.netlify.com/projects/apiccc/deploys/69c25451b49de60008dd7985
😎 Deploy Preview https://deploy-preview-194--apiccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 86 (🟢 up 4 from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 94 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Feb 23, 2026

Deploy Preview for liveccc ready!

Name Link
🔨 Latest commit e0f89ac
🔍 Latest deploy log https://app.netlify.com/projects/liveccc/deploys/69c254510257010008ed6edc
😎 Deploy Preview https://deploy-preview-194--liveccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 39 (🟢 up 2 from production)
Accessibility: 88 (no change from production)
Best Practices: 92 (🔴 down 8 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Feb 23, 2026

Deploy Preview for docsccc ready!

Name Link
🔨 Latest commit e0f89ac
🔍 Latest deploy log https://app.netlify.com/projects/docsccc/deploys/69c25451c4cfa800085b807f
😎 Deploy Preview https://deploy-preview-194--docsccc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 73 (🟢 up 6 from production)
Accessibility: 88 (no change from production)
Best Practices: 92 (no change from production)
SEO: 92 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@ashuralyk
Copy link
Contributor Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new fiber-sdk package, which is a significant and well-structured feature. The inclusion of comprehensive integration tests and a detailed README is excellent. However, there are several issues to address, including a critical security vulnerability related to a hardcoded private key, bugs in the example HTML files due to incorrect API usage, and some areas for code improvement for better maintainability and security.

.env Outdated
Comment on lines +1 to +2
process.env.PRIVATE_KEY =
"0x0000000000000000000000000000000000000000000000000000000000000000";
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

Committing an environment file containing a private key, even a zero-value one, poses a significant security risk. This file should be removed from the repository to prevent accidental exposure of real credentials in the future. It's recommended to use a template file (e.g., .env.example) to guide developers on the required environment variables, and keep the actual .env file in .gitignore.

.prettierrc
tsconfig.json
eslint.config.mjs
.prettierrc
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

There is a duplicate entry for .prettierrc in this file. Removing the duplicate will improve the maintainability of the configuration.

Comment on lines +198 to +202
const result = await sdk.channel.openChannel({
peer_id: peerId,
funding_amount: BigInt(fundingAmount) * BigInt(100000000), // Convert to shannon
public: isPublic,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The openChannel method expects parameters with camelCase keys (e.g., peerId, fundingAmount), as defined in the SDK. The current implementation uses snake_case keys (peer_id, funding_amount), which will cause runtime errors. Please update the keys to use camelCase.

Suggested change
const result = await sdk.channel.openChannel({
peer_id: peerId,
funding_amount: BigInt(fundingAmount) * BigInt(100000000), // Convert to shannon
public: isPublic,
});
const result = await sdk.channel.openChannel({
peerId: peerId,
fundingAmount: BigInt(fundingAmount) * BigInt(100000000), // Convert to shannon
public: isPublic,
});

Comment on lines +237 to +242
if (channelToClose.state.state_name === "NEGOTIATING_FUNDING") {
showStatus("通道正在协商资金阶段,无法关闭", "error");
return;
}

await sdk.channel.abandonChannel(channelToClose.channel_id);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The properties of the channel object returned by listChannels are in camelCase. The code is trying to access state.state_name and channel_id, but it should be state.stateName and channelId. Additionally, the abandonChannel method expects an object with the channelId property, not just the ID string.

Suggested change
if (channelToClose.state.state_name === "NEGOTIATING_FUNDING") {
showStatus("通道正在协商资金阶段,无法关闭", "error");
return;
}
await sdk.channel.abandonChannel(channelToClose.channel_id);
if (channelToClose.state.stateName === "NEGOTIATING_FUNDING") {
showStatus("通道正在协商资金阶段,无法关闭", "error");
return;
}
await sdk.channel.abandonChannel({ channelId: channelToClose.channelId });

}

try {
await sdk.peer.connectPeer(peerAddress);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The connectPeer method expects an object with an address property, not the address string directly. Please wrap the peerAddress in an object.

Suggested change
await sdk.peer.connectPeer(peerAddress);
await sdk.peer.connectPeer({ address: peerAddress });

Comment on lines +144 to +150
if (channelToClose.state.state_name === "NEGOTIATING_FUNDING") {
document.getElementById("channelInfo").textContent =
"通道正在协商资金阶段,无法关闭";
return;
}

await sdk.channel.abandonChannel(channelToClose.channel_id);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The properties of the channel object are in camelCase, so state.state_name should be state.stateName and channel_id should be channelId. Also, abandonChannel expects an object with a channelId property, like { channelId: ... }.

Suggested change
if (channelToClose.state.state_name === "NEGOTIATING_FUNDING") {
document.getElementById("channelInfo").textContent =
"通道正在协商资金阶段,无法关闭";
return;
}
await sdk.channel.abandonChannel(channelToClose.channel_id);
if (channelToClose.state.stateName === "NEGOTIATING_FUNDING") {
document.getElementById("channelInfo").textContent =
"通道正在协商资金阶段,无法关闭";
return;
}
await sdk.channel.abandonChannel({ channelId: channelToClose.channelId });

}
});

eval(workerData.script);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Using eval() can introduce security vulnerabilities by executing arbitrary code. Although this is within a test environment, it's a best practice to avoid eval(). Consider using a safer alternative like new Function(workerData.script)() to execute the script in a more controlled scope.

Suggested change
eval(workerData.script);
new Function(workerData.script)();

Comment on lines +27 to +50
export class OpenChannelParams {
constructor(
public readonly peerId: string,
public readonly fundingAmount: ccc.Hex,
isPublic?: boolean,
public readonly fundingUdtTypeScript?: ccc.Script,
public readonly shutdownScript?: ccc.Script,
public readonly commitmentDelayEpoch?: ccc.Hex,
public readonly commitmentFeeRate?: ccc.Hex,
public readonly fundingFeeRate?: ccc.Hex,
public readonly tlcExpiryDelta?: ccc.Hex,
public readonly tlcMinValue?: ccc.Hex,
public readonly tlcFeeProportionalMillionths?: ccc.Hex,
public readonly maxTlcValueInFlight?: ccc.Hex,
public readonly maxTlcNumberInFlight?: ccc.Hex,
) {
this._isPublic = isPublic;
}

private readonly _isPublic?: boolean;
get public(): boolean | undefined {
return this._isPublic;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The implementation of the public property in OpenChannelParams using a private _isPublic field and a public getter is a bit confusing and could be simplified. A standard public property would be more straightforward and easier to maintain, especially since public is not a reserved keyword for property names in this context.

export class OpenChannelParams {
  constructor(
    public readonly peerId: string,
    public readonly fundingAmount: ccc.Hex,
    public readonly public?: boolean,
    public readonly fundingUdtTypeScript?: ccc.Script,
    public readonly shutdownScript?: ccc.Script,
    public readonly commitmentDelayEpoch?: ccc.Hex,
    public readonly commitmentFeeRate?: ccc.Hex,
    public readonly fundingFeeRate?: ccc.Hex,
    public readonly tlcExpiryDelta?: ccc.Hex,
    public readonly tlcMinValue?: ccc.Hex,
    public readonly tlcFeeProportionalMillionths?: ccc.Hex,
    public readonly maxTlcValueInFlight?: ccc.Hex,
    public readonly maxTlcNumberInFlight?: ccc.Hex,
  ) {}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

public is reserved words so it cannot be used as a variable name in TypeScript

@ashuralyk
Copy link
Contributor Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive Fiber SDK for CCC, complete with a well-structured API, detailed type definitions, and an impressive testing suite that utilizes an in-process Fiber node. The overall quality of the code is high. However, there are a few significant issues that need attention. The most critical is the inclusion of a private key in the repository, which poses a serious security risk. Additionally, I've identified some bugs in a test HTML file and a subtle issue in a type definition class that could lead to runtime errors. I've provided specific comments and suggestions to address these points.

Comment on lines +41 to +47
const { invoiceAddress, invoice } = await sdk.newInvoice({
amount: "0x5f5e100",
currency: "Fibt",
description: "Coffee",
expiry: "0xe10",
finalExpiryDelta: "0x9283C0",
});
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The code examples use magic hex strings for values like amount, expiry, and finalExpiryDelta. This makes the code harder to understand. It would be more readable if you either used decimal numbers with comments or defined constants with descriptive names to represent these values.

}

// ── Run the fiber-js worker IIFE ──────────────────────────────────────────────
eval(workerData.script);
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

Using eval() can be a security risk as it executes code with the privileges of the caller. While in this context the script comes from a trusted dependency (fiber-js), it's a practice that should generally be avoided. If there's any alternative way to load and execute the worker script without eval, it would be preferable.

@ashuralyk
Copy link
Contributor Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new package, @ckb-ccc/fiber, which provides a comprehensive SDK for interacting with the Fiber payment channel network. The implementation is robust, featuring a well-designed API, thorough type definitions, and an impressive testing setup that includes a Node.js runtime for the browser-based fiber-js library. The code quality is high, and the documentation is clear. I've included a couple of suggestions to improve code clarity and maintainability.

await sdk.cancelInvoice(invoice.data.paymentHash);
```

`parseInvoice` on `FiberSDK` takes `{ invoice: string }` and returns a `CkbInvoice` (the API layer returns `{ invoice }` as `ParseInvoiceResult`).
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The explanation of how parseInvoice works on the API layer is an implementation detail that might be confusing for an SDK user. To improve clarity, I suggest removing the parenthetical part and focusing only on the behavior of the FiberSDK method.

Suggested change
`parseInvoice` on `FiberSDK` takes `{ invoice: string }` and returns a `CkbInvoice` (the API layer returns `{ invoice }` as `ParseInvoiceResult`).
`parseInvoice` on `FiberSDK` takes `{ invoice: string }` and returns a `CkbInvoice`.

Comment on lines +22 to +41
export class OpenChannelParams {
constructor(
public readonly peerId: string,
public readonly fundingAmount: ccc.Hex,
private readonly _public?: boolean,
public readonly fundingUdtTypeScript?: ccc.Script,
public readonly shutdownScript?: ccc.Script,
public readonly commitmentDelayEpoch?: ccc.Hex,
public readonly commitmentFeeRate?: ccc.Hex,
public readonly fundingFeeRate?: ccc.Hex,
public readonly tlcExpiryDelta?: ccc.Hex,
public readonly tlcMinValue?: ccc.Hex,
public readonly tlcFeeProportionalMillionths?: ccc.Hex,
public readonly maxTlcValueInFlight?: ccc.Hex,
public readonly maxTlcNumberInFlight?: ccc.Hex,
) {}

get public(): boolean | undefined {
return this._public;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The use of a private _public property with a getter to handle the public keyword is a bit complex. Since public can be used as an object property name without issue, you can simplify this class by using public directly as a constructor parameter. This will make the code more straightforward and easier to maintain.

Suggested change
export class OpenChannelParams {
constructor(
public readonly peerId: string,
public readonly fundingAmount: ccc.Hex,
private readonly _public?: boolean,
public readonly fundingUdtTypeScript?: ccc.Script,
public readonly shutdownScript?: ccc.Script,
public readonly commitmentDelayEpoch?: ccc.Hex,
public readonly commitmentFeeRate?: ccc.Hex,
public readonly fundingFeeRate?: ccc.Hex,
public readonly tlcExpiryDelta?: ccc.Hex,
public readonly tlcMinValue?: ccc.Hex,
public readonly tlcFeeProportionalMillionths?: ccc.Hex,
public readonly maxTlcValueInFlight?: ccc.Hex,
public readonly maxTlcNumberInFlight?: ccc.Hex,
) {}
get public(): boolean | undefined {
return this._public;
}
export class OpenChannelParams {
constructor(
public readonly peerId: string,
public readonly fundingAmount: ccc.Hex,
public readonly public?: boolean,
public readonly fundingUdtTypeScript?: ccc.Script,
public readonly shutdownScript?: ccc.Script,
public readonly commitmentDelayEpoch?: ccc.Hex,
public readonly commitmentFeeRate?: ccc.Hex,
public readonly fundingFeeRate?: ccc.Hex,
public readonly tlcExpiryDelta?: ccc.Hex,
public readonly tlcMinValue?: ccc.Hex,
public readonly tlcFeeProportionalMillionths?: ccc.Hex,
public readonly maxTlcValueInFlight?: ccc.Hex,
public readonly maxTlcNumberInFlight?: ccc.Hex,
) {}

Copy link
Contributor Author

@ashuralyk ashuralyk Mar 23, 2026

Choose a reason for hiding this comment

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

use public as member in a class is prohibited in TypeScript

@Hanssen0
Copy link
Member

/canary

@github-actions
Copy link
Contributor

❌ Canary version deployment failed. View workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants