Skip to content

Commit

Permalink
feat(common-scripts): support eth displaying for omnilock (#718)
Browse files Browse the repository at this point in the history
  • Loading branch information
homura authored Jun 24, 2024
1 parent f2f5666 commit d279b87
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changeset/lemon-tomatoes-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ckb-lumos/common-scripts": minor
"@ckb-lumos/lumos": minor
---

feat: support eth displaying auth mode for omnilock
3 changes: 2 additions & 1 deletion packages/common-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"@ckb-lumos/helpers": "0.23.0",
"@ckb-lumos/rpc": "0.23.0",
"@ckb-lumos/toolkit": "0.23.0",
"bs58": "^5.0.0",
"bech32": "^2.0.0",
"bs58": "^5.0.0",
"immutable": "^4.3.0"
},
"repository": {
Expand Down Expand Up @@ -57,6 +57,7 @@
"devDependencies": {
"@ckb-lumos/debugger": "0.23.0",
"@ckb-lumos/hd": "0.23.0",
"@ethereumjs/util": "^9.0.3",
"@types/keccak": "^3.0.1",
"@unisat/wallet-sdk": "^1.1.2",
"keccak": "^3.0.1",
Expand Down
44 changes: 44 additions & 0 deletions packages/common-scripts/src/omnilock-ethereum-displaying.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { BytesLike, bytes } from "@ckb-lumos/codec";
import { hexify } from "@ckb-lumos/codec/lib/bytes";

const COMMON_PREFIX = "CKB transaction: 0x";

export interface Provider {
request: {
(payload: {
method: "personal_sign";
params: [from: string, message: string];
}): Promise<string>;
};
}

export async function signMessage(
address: string,
digest: BytesLike,
provider?: Provider
): Promise<string> {
/* c8 ignore start */
const internal: Provider | undefined =
provider ?? (globalThis as { ethereum?: Provider }).ethereum;

if (!internal) {
throw new Error(
"No provider found, make sure you have installed MetaMask or the other EIP1193 compatible wallet"
);
}
/* c8 ignore end */

const sig = await internal.request({
method: "personal_sign",
params: [address, `${COMMON_PREFIX}${hexify(digest).slice(2)}`],
});

const signature = bytes.bytify(sig);

const [tweakedV] = signature.slice(-1);
// https://eips.ethereum.org/EIPS/eip-155
const PARITY_FLAG = 27;
const v = tweakedV >= PARITY_FLAG ? tweakedV - PARITY_FLAG : tweakedV;
signature.set([v], signature.length - 1);
return bytes.hexify(signature);
}
16 changes: 16 additions & 0 deletions packages/common-scripts/src/omnilock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type OmnilockInfo = {
export type OmnilockAuth =
| IdentityCkb
| IdentityEthereum
| IdentityEthereumDisplaying
| IdentityBitcoin
| IdentitySolana;

Expand All @@ -68,6 +69,11 @@ export type IdentityEthereum = {
content: BytesLike;
};

export type IdentityEthereumDisplaying = {
flag: "ETHEREUM-DISPLAYING";
content: BytesLike;
};

export type IdentityBitcoin = {
flag: "BITCOIN";
/**
Expand Down Expand Up @@ -173,6 +179,14 @@ export function createOmnilockScript(
omnilockArgs
)
);
case "ETHEREUM-DISPLAYING":
return bytes.hexify(
bytes.concat(
[IdentityFlagsType.IdentityFlagsEthereumDisplaying],
omnilockInfo.auth.content,
omnilockArgs
)
);
case "SECP256K1_BLAKE160":
return bytes.hexify(
bytes.concat(
Expand Down Expand Up @@ -408,6 +422,7 @@ export async function setupInputCell(

case IdentityFlagsType.IdentityFlagsCkb:
case IdentityFlagsType.IdentityFlagsEthereum:
case IdentityFlagsType.IdentityFlagsEthereumDisplaying:
case IdentityFlagsType.IdentityFlagsBitcoin: {
return SECP256K1_SIGNATURE_PLACEHOLDER_LENGTH;
}
Expand Down Expand Up @@ -456,6 +471,7 @@ export function prepareSigningEntries(
return _prepareSigningEntries(txSkeleton, config, "OMNILOCK");
}

export * as ethereumDisplaying from "./omnilock-ethereum-displaying";
export { bitcoin };
export { solana };

Expand Down
108 changes: 108 additions & 0 deletions packages/common-scripts/tests/omnilock-ethereum-displaying.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import test from "ava";
import { createOmnilockScript, OmnilockWitnessLock } from "../src/omnilock";
import { Provider, signMessage } from "../src/omnilock-ethereum-displaying";
import { BytesLike, bytes } from "@ckb-lumos/codec";
import { TransactionSkeleton } from "@ckb-lumos/helpers";
import {
CKBDebuggerDownloader,
createTestContext,
getDefaultConfig,
} from "@ckb-lumos/debugger";
import common from "../src/common";
import { mockOutPoint } from "@ckb-lumos/debugger/lib/context";
import { blockchain, utils } from "@ckb-lumos/base";
import {
ecsign,
fromSigned,
hashPersonalMessage,
privateToAddress,
toUnsigned,
} from "@ethereumjs/util";
import { Uint8 } from "@ckb-lumos/codec/lib/number";
import { randomBytes } from "node:crypto";

const context = createTestContext(getDefaultConfig());
const managerConfig = { PREFIX: "ckt", SCRIPTS: context.scriptConfigs };

test.before(async () => {
await new CKBDebuggerDownloader().downloadIfNotExists();
});

test("Omnilock with IdentityEthereumDisplayingFlag", async (t) => {
const privateKey = randomBytes(32);
const provider = makeProvider(privateKey);

const lock = createOmnilockScript(
{
auth: { flag: "ETHEREUM-DISPLAYING", content: provider.selectedAddress },
},
{ config: managerConfig }
);

const txSkeleton = TransactionSkeleton().asMutable();

await common.setupInputCell(

Check warning on line 44 in packages/common-scripts/tests/omnilock-ethereum-displaying.test.ts

View workflow job for this annotation

GitHub Actions / lint-staged

Caution: `common` also has a named export `setupInputCell`. Check if you meant to write `import {setupInputCell} from '../src/common'` instead
txSkeleton,
{
cellOutput: { lock, capacity: "0x1" },
data: "0x",
outPoint: mockOutPoint(),
},
undefined,
{ config: managerConfig }
);

common.prepareSigningEntries(txSkeleton, { config: managerConfig });

Check warning on line 55 in packages/common-scripts/tests/omnilock-ethereum-displaying.test.ts

View workflow job for this annotation

GitHub Actions / lint-staged

Caution: `common` also has a named export `prepareSigningEntries`. Check if you meant to write `import {prepareSigningEntries} from '../src/common'` instead

const signedMessage = await signMessage(
provider.selectedAddress,
txSkeleton.get("signingEntries").get(0)!.message,
provider
);

const signedWitness = bytes.hexify(
blockchain.WitnessArgs.pack({
lock: OmnilockWitnessLock.pack({ signature: signedMessage }),
})
);

txSkeleton.update("witnesses", (witnesses) =>
witnesses.set(0, signedWitness)
);

const result = await context.executor.execute(txSkeleton, {
scriptHash: utils.computeScriptHash(lock),
scriptGroupType: "lock",
});

t.is(result.code, 0);
});

function makeProvider(
privateKey: BytesLike
): Provider & { selectedAddress: string } {
const privKey = bytes.bytify(privateKey);
const selectedAddress = bytes.hexify(privateToAddress(privKey));

return {
selectedAddress,
request: async ({ params }) => {
const message = new TextEncoder().encode(params[1]);
const msgHash = hashPersonalMessage(message);
const sig = ecsign(msgHash, privKey);

const serialized = concatSig(Uint8.pack(sig.v), sig.r, sig.s);
return serialized;
},
};
}

function concatSig(v: Uint8Array, r: Uint8Array, s: Uint8Array): string {
const rSig = fromSigned(r);
const sSig = fromSigned(s);

const rStr = toUnsigned(rSig);
const sStr = toUnsigned(sSig);

return bytes.hexify(bytes.concat(rStr, sStr, v));
}
1 change: 1 addition & 0 deletions packages/lumos/src/common-scripts/omnilock.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export {
bitcoin,
solana,
ethereumDisplaying,
OmnilockWitnessLock,
createOmnilockScript,
setupInputCell,
Expand Down
51 changes: 51 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 comment on commit d279b87

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

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

🚀 New canary release: 0.0.0-canary-d279b87-20240624101315

npm install @ckb-lumos/[email protected]

Please sign in to comment.