Skip to content

Commit 8265567

Browse files
Merge pull request #5062 from BitGo/BTC-1578-coredao
feat(utxo-coredao): initialize utxo-coredao
2 parents 664bd96 + f130367 commit 8265567

File tree

13 files changed

+3040
-2669
lines changed

13 files changed

+3040
-2669
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
/modules/sdk-core/src/bitgo/lightning/ @BitGo/btc-team
2525
/modules/unspents/ @BitGo/btc-team
2626
/modules/utxo-bin/ @BitGo/btc-team
27+
/modules/utxo-coredao/ @BitGo/btc-team
2728
/modules/utxo-lib/ @BitGo/btc-team
2829
/modules/utxo-ord/ @BitGo/btc-team
2930

modules/utxo-coredao/.eslintignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
.idea
3+
public
4+
dist
5+

modules/utxo-coredao/.mocharc.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
require: 'ts-node/register'
2+
timeout: '60000'
3+
reporter: 'min'
4+
reporter-option:
5+
- 'cdn=true'
6+
- 'json=false'
7+
exit: true
8+
spec: ['test/unit/**/*.ts']

modules/utxo-coredao/.npmignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
!dist/
2+
dist/test/
3+
dist/tsconfig.tsbuildinfo
4+
.idea/
5+
.prettierrc.yml
6+
tsconfig.json
7+
src/
8+
test/
9+
scripts/
10+
.nyc_output
11+
CODEOWNERS
12+
node_modules/
13+
.prettierignore
14+
.mocharc.js
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.nyc_output/
2+
dist/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
printWidth: 120
2+
singleQuote: true
3+
trailingComma: 'es5'

modules/utxo-coredao/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# BitGo utxo-CoreDao
2+
3+
Provides the functionality to build and parse coredao transactions.

modules/utxo-coredao/package.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "@bitgo/utxo-coredao",
3+
"version": "1.0.0",
4+
"description": "BitGo SDK for building CoreDao transactions",
5+
"main": "./dist/src/index.js",
6+
"types": "./dist/src/index.d.ts",
7+
"scripts": {
8+
"build": "yarn tsc --build --incremental --verbose .",
9+
"fmt": "prettier --write .",
10+
"check-fmt": "prettier --check .",
11+
"clean": "rm -r ./dist",
12+
"lint": "eslint --quiet .",
13+
"prepare": "npm run build",
14+
"test": "npm run coverage",
15+
"coverage": "nyc -- npm run unit-test",
16+
"unit-test": "mocha"
17+
},
18+
"author": "BitGo SDK Team <[email protected]>",
19+
"license": "MIT",
20+
"engines": {
21+
"node": ">=18 <21"
22+
},
23+
"repository": {
24+
"type": "git",
25+
"url": "https://github.com/BitGo/BitGoJS.git",
26+
"directory": "modules/utxo-coredao"
27+
},
28+
"lint-staged": {
29+
"*.{js,ts}": [
30+
"yarn prettier --write",
31+
"yarn eslint --fix"
32+
]
33+
},
34+
"publishConfig": {
35+
"access": "public"
36+
},
37+
"nyc": {
38+
"extension": [
39+
".ts"
40+
]
41+
},
42+
"dependencies": {
43+
"@bitgo/utxo-lib": "^11.0.0"
44+
}
45+
}

modules/utxo-coredao/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './transaction';
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Source: https://docs.coredao.org/docs/Learn/products/btc-staking/design
2+
export const CORE_DAO_TESTNET_CHAIN_ID = Buffer.alloc(2, 0x1115);
3+
export const CORE_DAO_MAINNET_CHAIN_ID = Buffer.alloc(2, 0x1116);
4+
export const CORE_DAO_SATOSHI_PLUS_IDENTIFIER = Buffer.alloc(4, 0x5341542b);
5+
6+
/**
7+
* Create a CoreDAO OP_RETURN output script
8+
*
9+
* @param version Version of the OP_RETURN
10+
* @param chainId Chain ID
11+
* @param delegator Delegator address
12+
* @param validator Validator address
13+
* @param fee Fee for relayer
14+
* @param redeemScript Redeem script of the staking output
15+
* @param timelock Timelock for the staking output
16+
* @returns Buffer OP_RETURN buffer
17+
*/
18+
export function createCoreDaoOpReturnOutputScript({
19+
version,
20+
chainId,
21+
delegator,
22+
validator,
23+
fee,
24+
redeemScript,
25+
timelock,
26+
}: {
27+
version: number;
28+
chainId: Buffer;
29+
delegator: Buffer;
30+
validator: Buffer;
31+
fee: number;
32+
redeemScript?: Buffer;
33+
timelock?: number;
34+
}): Buffer {
35+
/**
36+
* As of v2, this is the construction of the OP_RETURN:
37+
* Source: https://docs.coredao.org/docs/Learn/products/btc-staking/design#op_return-output
38+
*
39+
* The OP_RETURN output should contain all staking information in order, and be composed in the following format:
40+
*
41+
* OP_RETURN: identifier 0x6a
42+
* LENGTH: which represents the total byte length after the OP_RETURN opcode. Note that all data has to be pushed with its appropriate size byte(s). [1]
43+
* Satoshi Plus Identifier: (SAT+) 4 bytes
44+
* Version: (0x01) 1 byte
45+
* Chain ID: (0x1115 for Core Testnet and 0x1116 for Core Mainnet) 2 bytes
46+
* Delegator: The Core address to receive rewards, 20 bytes
47+
* Validator: The Core validator address to stake to, 20 bytes
48+
* Fee: Fee for relayer, 1 byte, range [0,255], measured in CORE
49+
* (Optional) RedeemScript
50+
* (Optional) Timelock: 4 bytes
51+
*
52+
* [1] Any bytes bigger than or equal to 0x4c is pushed by using 0x4c (ie. OP_PUSHDATA)
53+
* followed by the length followed by the data (byte[80] -> OP_PUSHDATA + 80 + byte[80])
54+
*
55+
* Either RedeemScript or Timelock must be available, the purpose is to allow relayer to
56+
* obtain the RedeemScript and submit transactions on Core. If a RedeemScript is provided,
57+
* relayer will use it directly. Otherwise, relayer will construct the redeem script based
58+
* on the timelock and the information in the transaction inputs.
59+
*/
60+
if (version < 0 || version > 255) {
61+
throw new Error('Invalid version - out of range');
62+
}
63+
const versionBuffer = Buffer.alloc(1, version);
64+
65+
if (!(chainId.equals(CORE_DAO_TESTNET_CHAIN_ID) || chainId.equals(CORE_DAO_MAINNET_CHAIN_ID))) {
66+
throw new Error('Invalid chain ID');
67+
}
68+
69+
if (delegator.length !== 20) {
70+
throw new Error('Invalid delegator address');
71+
}
72+
73+
if (validator.length !== 20) {
74+
throw new Error('Invalid validator address');
75+
}
76+
77+
if (fee < 0 || fee > 255) {
78+
throw new Error('Invalid fee - out of range');
79+
}
80+
const feeBuffer = Buffer.alloc(1, fee);
81+
82+
if (feeBuffer.length !== 1) {
83+
throw new Error('Invalid fee');
84+
}
85+
86+
if (!redeemScript && !timelock) {
87+
throw new Error('Either redeemScript or timelock must be provided');
88+
}
89+
const redeemScriptBuffer = redeemScript ?? Buffer.from([]);
90+
if (timelock && (timelock < 0 || timelock > 4294967295)) {
91+
throw new Error('Invalid timelock - out of range');
92+
}
93+
const timelockBuffer = timelock ? Buffer.alloc(4, timelock).reverse() : Buffer.from([]);
94+
95+
const totalLength =
96+
CORE_DAO_SATOSHI_PLUS_IDENTIFIER.length +
97+
versionBuffer.length +
98+
chainId.length +
99+
delegator.length +
100+
validator.length +
101+
feeBuffer.length +
102+
redeemScriptBuffer.length +
103+
timelockBuffer.length +
104+
// This is to account for the LENGTH byte
105+
1;
106+
107+
// If the length is >= 0x4c (76), we need to use the OP_PUSHDATA (0x4c) opcode and then the length
108+
const totalLengthBuffer =
109+
totalLength >= 76
110+
? Buffer.concat([
111+
Buffer.from([0x4c]),
112+
Buffer.alloc(
113+
1,
114+
// This is to account for the extra OP_PUSHDATA byte
115+
totalLength + 1
116+
),
117+
])
118+
: Buffer.alloc(1, totalLength);
119+
120+
return Buffer.concat([
121+
Buffer.from([0x6a]),
122+
totalLengthBuffer,
123+
CORE_DAO_SATOSHI_PLUS_IDENTIFIER,
124+
versionBuffer,
125+
chainId,
126+
delegator,
127+
validator,
128+
feeBuffer,
129+
redeemScriptBuffer,
130+
timelockBuffer,
131+
]);
132+
}

0 commit comments

Comments
 (0)