Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .changeset/legal-laws-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ckb-ccc/core": minor
---

feat(core): `SignerCkbAlwaysSuccess`

1 change: 1 addition & 0 deletions packages/core/src/signer/ckb/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./secp256k1Signing.js";
export * from "./signerCkbAlwaysSuccess.js";
export * from "./signerCkbPrivateKey.js";
export * from "./signerCkbPublicKey.js";
export * from "./signerCkbScriptReadonly.js";
Expand Down
56 changes: 56 additions & 0 deletions packages/core/src/signer/ckb/signerCkbAlwaysSuccess.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { describe, expect, it } from "vitest";
Comment thread
Hanssen0 marked this conversation as resolved.
import { ccc } from "../../index.js";

describe("SignerCkbAlwaysSuccess", () => {
const scriptInfo = ccc.ScriptInfo.from({
codeHash:
"0x0000000000000000000000000000000000000000000000000000000000000000",
hashType: "data1",
cellDeps: [
{
cellDep: {
outPoint: {
txHash:
"0x0000000000000000000000000000000000000000000000000000000000000000",
index: 0,
},
depType: "code",
},
},
],
});
const client = {
addressPrefix: "ckt",
getKnownScript: async () => scriptInfo,
getCellDeps: async () => scriptInfo.cellDeps.map(({ cellDep }) => cellDep),
} as unknown as ccc.Client;
const signer = new ccc.SignerCkbAlwaysSuccess(client);

it("uses the always-success script with empty args", async () => {
const addresses = await signer.getAddressObjs();

expect(addresses).toHaveLength(1);
expect(signer.type).toBe(ccc.SignerType.CKB);
expect(signer.signType).toBe(ccc.SignerSignType.Unknown);
expect(await signer.isConnected()).toBe(true);
expect(addresses[0].script).toEqual(
ccc.Script.from({
codeHash: scriptInfo.codeHash,
hashType: scriptInfo.hashType,
args: "0x",
}),
);
});
Comment thread
Hanssen0 marked this conversation as resolved.

it("adds the always-success cell dep while signing", async () => {
const tx = ccc.Transaction.default();

const signed = await signer.signTransaction(tx);

expect(signed.cellDeps).toHaveLength(1);
expect(signed.cellDeps[0].eq(scriptInfo.cellDeps[0].cellDep)).toBe(true);

const signedAgain = await signer.signTransaction(signed);
expect(signedAgain.cellDeps).toHaveLength(1);
});
Comment thread
Hanssen0 marked this conversation as resolved.
});
71 changes: 71 additions & 0 deletions packages/core/src/signer/ckb/signerCkbAlwaysSuccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Address } from "../../address/index.js";
import { Transaction, TransactionLike } from "../../ckb/index.js";
import { Client, KnownScript } from "../../client/index.js";
import { Signer, SignerSignType, SignerType } from "../signer/index.js";

/**
* A signer for the well-known always-success lock script.
*
* The always-success script does not require a signature, so signing a
* transaction only needs to add its cell dependency.
*
* @public
*/
export class SignerCkbAlwaysSuccess extends Signer {
get type(): SignerType {
return SignerType.CKB;
}

get signType(): SignerSignType {
return SignerSignType.Unknown;
}

/**
* Creates an instance of SignerCkbAlwaysSuccess.
*
* @param client - The client instance used for communication and resolving
* the always-success deployment.
*/
constructor(client: Client) {
super(client);
}

async connect(): Promise<void> {}

async isConnected(): Promise<boolean> {
return true;
}

async getInternalAddress(): Promise<string> {
return this.getRecommendedAddress();
}

/**
* Gets the address of the always-success lock script.
*/
async getAddressObjs(): Promise<Address[]> {
return [
await Address.fromKnownScript(
this.client,
KnownScript.AlwaysSuccess,
"0x",
),
];
}

/**
* Adds the always-success cell dependency to a transaction.
*/
async prepareTransaction(txLike: TransactionLike): Promise<Transaction> {
const tx = Transaction.from(txLike);
await tx.addCellDepsOfKnownScripts(this.client, KnownScript.AlwaysSuccess);
return tx;
}

/**
* The always-success script requires no signature.
*/
async signOnlyTransaction(txLike: TransactionLike): Promise<Transaction> {
return Transaction.from(txLike);
}
}