Skip to content

Commit d5fad3f

Browse files
committed
init
1 parent f96d789 commit d5fad3f

17 files changed

+912
-0
lines changed

.eslintignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
build/
3+
test/

.eslintrc.json

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "semistandard",
3+
"parser": "@typescript-eslint/parser",
4+
"plugins": [
5+
"@typescript-eslint"
6+
],
7+
"parserOptions": {
8+
"ecmaVersion": 2021,
9+
"sourceType": "module"
10+
},
11+
"rules": {
12+
}
13+
}

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea
2+
node_modules
3+
dist
4+
package-lock.json
5+
.vscode

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Savour Labs
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

babel.config.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
presets: [
3+
['@babel/preset-env', { targets: { node: 'current' } }],
4+
'@babel/preset-typescript'
5+
],
6+
};

index.ts

Whitespace-only changes.

jest.config.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
testEnvironment: 'node',
4+
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
5+
coveragePathIgnorePatterns: ['<rootDir>/test/'],
6+
testRegex: 'test/(.+)\\.test\\.(jsx?|tsx?)$',
7+
setupFilesAfterEnv: ['./jest.setup.js'],
8+
};

jest.setup.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
jest.setTimeout(300000)

package.json

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "wallet-sdk-s3",
3+
"version": "1.0.0",
4+
"main": "index.ts",
5+
"scripts": {
6+
"test": "jest"
7+
},
8+
"author": "rex",
9+
"license": "ISC",
10+
"description": "",
11+
"repository": {
12+
"type": "git",
13+
"url": "git+https://github.com/SlimeMutation/wallet-sdk-s3.git"
14+
},
15+
"bugs": {
16+
"url": "https://github.com/SlimeMutation/wallet-sdk-s3/issues"
17+
},
18+
"homepage": "https://github.com/SlimeMutation/wallet-sdk-s3#readme",
19+
"dependencies": {
20+
"bip32": "^4.0.0",
21+
"bip39": "^3.0.4",
22+
"bitcoinjs-lib": "^6.1.5",
23+
"bitcore-lib": "8.25.31",
24+
"ecpair": "^2.1.0",
25+
"tiny-secp256k1": "^2.2.3"
26+
},
27+
"devDependencies": {
28+
"@babel/core": "^7.22.9",
29+
"@babel/preset-env": "^7.22.9",
30+
"@babel/preset-typescript": "^7.22.5",
31+
"@midwayjs/cli": "1.0.0",
32+
"@midwayjs/luckyeye": "1.0.0",
33+
"@midwayjs/mock": "2.3.0",
34+
"@types/bitcore-lib": "^0.15.6",
35+
"@types/bs58check": "^2.1.0",
36+
"@types/jest": "26.0.10",
37+
"@types/koa-bodyparser": "4.3.0",
38+
"@types/node": "14",
39+
"@typescript-eslint/eslint-plugin": "^5.13.0",
40+
"@typescript-eslint/parser": "^5.13.0",
41+
"babel-jest": "^29.6.2",
42+
"cross-env": "6.0.0",
43+
"eslint": "^8.4.1",
44+
"eslint-config-semistandard": "^17.0.0",
45+
"jest": "^29.0.0",
46+
"jest-environment-node": "^29.7.0",
47+
"mwts": "^1.0.5",
48+
"tronweb": "^2.10.1",
49+
"ts-jest": "^29.0.0",
50+
"ts-node": "10.4.0",
51+
"typescript": "5.0.2"
52+
}
53+
}

src/bitcoin/address.ts

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import * as bitcoin from 'bitcoinjs-lib';
2+
const ecc = require('tiny-secp256k1');
3+
const { BIP32Factory } = require('bip32');
4+
const bip32 = BIP32Factory(ecc);
5+
6+
export type NetworkType = 'bitcoin' | 'testnet' | 'regtest';
7+
8+
interface CreateAddressParams {
9+
seedHex: string;
10+
receiveOrChange: string;
11+
addressIndex: number;
12+
network: NetworkType;
13+
method: string;
14+
}
15+
16+
export function createAddress(params: CreateAddressParams): { privateKey: string; publicKey: string; address: string } {
17+
const { seedHex, receiveOrChange, addressIndex, network, method } = params;
18+
const root = bip32.fromSeed(Buffer.from(seedHex, 'hex'));
19+
let path = "m/44'/0'/0'/0/" + addressIndex + '';
20+
if (receiveOrChange === '1') {
21+
path = "m/44'/0'/0'/1/" + addressIndex + '';
22+
}
23+
const child = root.derivePath(path);
24+
let address = '';
25+
switch (method) {
26+
case 'p2pkh': {
27+
const p2pkhAddress = bitcoin.payments.p2pkh({
28+
pubkey: child.publicKey,
29+
network: bitcoin.networks[network as keyof typeof bitcoin.networks]
30+
});
31+
if (!p2pkhAddress.address) {
32+
throw new Error('Failed to generate p2pkh address');
33+
}
34+
address = p2pkhAddress.address;
35+
break;
36+
}
37+
case 'p2wpkh': {
38+
const p2wpkhAddress = bitcoin.payments.p2wpkh({
39+
pubkey: child.publicKey,
40+
network: bitcoin.networks[network as keyof typeof bitcoin.networks]
41+
});
42+
if (!p2wpkhAddress.address) {
43+
throw new Error('Failed to generate p2wpkh address');
44+
}
45+
address = p2wpkhAddress.address;
46+
break;
47+
}
48+
case 'p2sh': {
49+
const p2shAddress = bitcoin.payments.p2sh({
50+
redeem: bitcoin.payments.p2wpkh({
51+
pubkey: child.publicKey,
52+
network: bitcoin.networks[network as keyof typeof bitcoin.networks]
53+
})
54+
});
55+
if (!p2shAddress.address) {
56+
throw new Error('Failed to generate p2sh address');
57+
}
58+
address = p2shAddress.address;
59+
break;
60+
}
61+
default:
62+
throw new Error(`Unsupported method: ${method}`);
63+
}
64+
65+
return {
66+
privateKey: Buffer.from(child.privateKey).toString('hex'),
67+
publicKey: Buffer.from(child.publicKey).toString('hex'),
68+
address
69+
};
70+
}
71+
72+
interface CreateMultiSignAddressParams {
73+
pubkeys: Buffer[];
74+
network: NetworkType;
75+
method: string;
76+
threshold: number;
77+
}
78+
79+
export function createMultiSignAddress(params: CreateMultiSignAddressParams): string {
80+
const { pubkeys, network, method, threshold } = params;
81+
82+
const getAddress = (payment: any): string => {
83+
const address = payment.address;
84+
if (!address) {
85+
throw new Error('Failed to generate multisig address');
86+
}
87+
return address;
88+
};
89+
90+
switch (method) {
91+
case 'p2pkh': {
92+
const payment = bitcoin.payments.p2sh({
93+
redeem: bitcoin.payments.p2ms({
94+
m: threshold,
95+
network: bitcoin.networks[network as keyof typeof bitcoin.networks],
96+
pubkeys
97+
})
98+
});
99+
return getAddress(payment);
100+
}
101+
case 'p2wpkh': {
102+
const payment = bitcoin.payments.p2wsh({
103+
redeem: bitcoin.payments.p2ms({
104+
m: threshold,
105+
network: bitcoin.networks[network as keyof typeof bitcoin.networks],
106+
pubkeys
107+
})
108+
});
109+
return getAddress(payment);
110+
}
111+
case 'p2sh': {
112+
const payment = bitcoin.payments.p2sh({
113+
redeem: bitcoin.payments.p2wsh({
114+
redeem: bitcoin.payments.p2ms({
115+
m: threshold,
116+
network: bitcoin.networks[network as keyof typeof bitcoin.networks],
117+
pubkeys
118+
})
119+
})
120+
});
121+
return getAddress(payment);
122+
}
123+
default:
124+
throw new Error(`Unsupported multisig method: ${method}`);
125+
}
126+
}
127+
128+
interface CreateSchnorrAddressParams {
129+
seedHex: string;
130+
receiveOrChange: string;
131+
addressIndex: number;
132+
}
133+
134+
interface SchnorrAddressResult {
135+
privateKey: string;
136+
publicKey: string;
137+
address: string;
138+
}
139+
140+
export function createSchnorrAddress(params: CreateSchnorrAddressParams): SchnorrAddressResult {
141+
bitcoin.initEccLib(ecc);
142+
const { seedHex, receiveOrChange, addressIndex } = params;
143+
144+
const root = bip32.fromSeed(Buffer.from(seedHex, 'hex'));
145+
let path = "m/44'/0'/0'/0/" + addressIndex + '';
146+
if (receiveOrChange === '1') {
147+
path = "m/44'/0'/0'/1/" + addressIndex + '';
148+
}
149+
150+
const childKey = root.derivePath(path);
151+
const privateKey = childKey.privateKey;
152+
if (!privateKey) {
153+
throw new Error('No private key found');
154+
}
155+
156+
const publicKey = childKey.publicKey;
157+
if (!publicKey) {
158+
throw new Error('No public key found');
159+
}
160+
161+
// 生成 P2TR 地址
162+
const payment = bitcoin.payments.p2tr({
163+
internalPubkey: publicKey.length === 32 ? publicKey : publicKey.slice(1, 33)
164+
});
165+
166+
if (!payment.address) {
167+
throw new Error('Failed to generate Schnorr address');
168+
}
169+
170+
return {
171+
privateKey: Buffer.from(privateKey).toString('hex'),
172+
publicKey: Buffer.from(publicKey).toString('hex'),
173+
address: payment.address
174+
};
175+
}

0 commit comments

Comments
 (0)