Skip to content

Commit c42da28

Browse files
authored
feat(CRO): CWC-272 add Cronos smart contract (#273)
1 parent 12221da commit c42da28

File tree

11 files changed

+259
-78
lines changed

11 files changed

+259
-78
lines changed

.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"tabWidth": 2,
44
"useTabs": false,
55
"singleQuote": true,
6+
"jsxSingleQuote": true,
67
"semi": true
78
}

packages/coin-cro/package.json

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,30 @@
88
"scripts": {
99
"build:types": "tsc --emitDeclarationOnly",
1010
"build:ts": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
11-
"build": "npm run build:types && npm run build:ts",
12-
"test": "jest --verbose"
11+
"build": "del-cli lib && npm run build:types && npm run build:ts",
12+
"test": "jest"
13+
},
14+
"dependencies": {
15+
"bip32": "^2.0.4",
16+
"eth-sig-util": "^3.0.1",
17+
"keccak": "^3.0.2",
18+
"rlp": "^2.2.7",
19+
"web3": "^1.7.0"
20+
},
21+
"peerDependencies": {
22+
"@coolwallet/core": "^1.0.14"
1323
},
1424
"devDependencies": {
1525
"@babel/cli": "^7.16.8",
1626
"@babel/core": "^7.16.7",
1727
"@babel/plugin-proposal-class-properties": "^7.7.4",
1828
"@babel/preset-env": "^7.7.1",
1929
"@babel/preset-typescript": "^7.7.7",
20-
"@coolwallet/core": "file:../core",
30+
"@coolwallet/core": "^1.0.14",
2131
"@types/eth-sig-util": "^2.1.1",
2232
"@types/node": "^14.0.13",
33+
"@types/keccak": "^3.0.1",
34+
"del-cli": "^4.0.1",
2335
"typescript": "^4.4.3"
2436
},
2537
"repository": {
@@ -28,13 +40,5 @@
2840
},
2941
"bugs": {
3042
"url": "https://github.com/CoolBitX-Technology/coolwallet3-sdk/issues"
31-
},
32-
"dependencies": {
33-
"@types/keccak": "^3.0.1",
34-
"bip32": "^2.0.4",
35-
"eth-sig-util": "^3.0.1",
36-
"keccak": "^3.0.2",
37-
"rlp": "^2.2.7",
38-
"web3": "^1.7.0"
3943
}
4044
}

packages/coin-cro/src/config/params.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,17 @@ export const ERC20 = {
1919
};
2020

2121
export const SmartContract = {
22-
script: '',
23-
signature: ''.padStart(144, '0'),
22+
script: `03040601C707000000003CA00700C2ACD70032FFF8C2ACD7001EFFF6C2ACD70028FFF6CC071094CAA02700C2A2D700FFF6C2AC97003ACC0E1019C2E09700CC07C0028080BE0710DC07C00343524FD207C005534D415254D207CC05065052455353425554546F4E`,
23+
signature: `3045022072902FD446A0E80824EAEF45ACCA5F800BE52AD3CE9D011AF90C8D85710059D0022100C467A0FE1BF941B4900CB269B80BD2D1999EEB5B8633676AA0383E8EDE863FA3`.padStart(144, '0'),
2424
get scriptWithSignature(): string {
2525
return this.script + this.signature;
2626
},
2727
};
28+
29+
export const SmartContractSegment = {
30+
script: `03050601C707000000003CA00700C2ACD70032FFF8C2ACD7001EFFF6C2ACD70028FFF6CC071094CAA02700C2A2D700FFF6C4ACC7003A04CC0E1019C2E09700CC07C0028080BE0710DC07C00343524FD207C005534D415254D207CC05065052455353425554546F4E`,
31+
signature: `3046022100A0188B33A3CCCF98BF055FB82BF621E9D43AFE7DD066D907DD446688E91141C0022100EF67E474862FA59DC5DE49079FD5258CDB6939C41C84E0170132399E1CB96592`.padStart(144, '0'),
32+
get scriptWithSignature(): string {
33+
return this.script + this.signature;
34+
},
35+
}

packages/coin-cro/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ export default class CRO extends COIN.ECDSACoin implements COIN.Coin {
8383
async signSmartContractTransaction(signTxData: types.signTx): Promise<string> {
8484
const { transport, appPrivateKey, appId, addressIndex, transaction } = signTxData;
8585
const publicKey = await this.getPublicKey(transport, appPrivateKey, appId, addressIndex);
86+
// if data bytes is larger than 8192 sign it segmentally.
87+
if (transaction.data.length > 8192 * 2) {
88+
const argument = await scriptUtils.getSmartContractSegmentArgument(transaction, addressIndex);
89+
const script = params.SmartContractSegment.scriptWithSignature;
90+
91+
return ethSign.signSegmentSmartContractTransaction(signTxData, script, argument, publicKey);
92+
}
8693
const argument = await scriptUtils.getSmartContractArgument(transaction, addressIndex);
8794
const script = params.SmartContract.scriptWithSignature;
8895

packages/coin-cro/src/sign.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,44 @@ export const signTransaction = async (
6060
}
6161
};
6262

63+
export const signSmartContractTransaction = async (
64+
signTxData: signTx,
65+
script: string,
66+
argument: string,
67+
publicKey: string
68+
): Promise<string> => {
69+
const { transport, transaction } = signTxData;
70+
71+
const rawPayload = ethUtil.getRawHex(transaction);
72+
73+
const preActions = [];
74+
75+
preActions.push(() => apdu.tx.sendScript(transport, script));
76+
77+
const action = () => apdu.tx.executeScript(transport, signTxData.appId, signTxData.appPrivateKey, argument);
78+
79+
const canonicalSignature = await tx.flow.getSingleSignatureFromCoolWallet(
80+
transport,
81+
preActions,
82+
action,
83+
false,
84+
signTxData.confirmCB,
85+
signTxData.authorizedCB,
86+
true
87+
);
88+
89+
if (!Buffer.isBuffer(canonicalSignature)) {
90+
const { v, r, s } = await ethUtil.genEthSigFromSESig(canonicalSignature, rlp.encode(rawPayload), publicKey);
91+
const serializedTx = ethUtil.composeSignedTransacton(rawPayload, v, r, s, CHAIN_ID);
92+
return serializedTx;
93+
} else {
94+
throw new error.SDKError(signTransaction.name, 'canonicalSignature type error');
95+
}
96+
};
97+
6398
/**
64-
* sign ETH Smart Contract Transaction
99+
* sign ETH Smart Contract Transaction segmentally
100+
*
65101
* @param {Transport} transport
66102
* @param {string} appId
67103
* @param {String} appPrivateKey
@@ -74,7 +110,7 @@ export const signTransaction = async (
74110
* @param {Function} authorizedCB
75111
* @return {Promise<string>}
76112
*/
77-
export const signSmartContractTransaction = async (
113+
export const signSegmentSmartContractTransaction = async (
78114
signTxData: signTx,
79115
script: string,
80116
argument: string,

packages/coin-cro/src/utils/scriptUtils.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,27 @@ export const getERC20Argument = async (transaction: Transaction, tokenSignature:
5252

5353
/**
5454
* [contractAddress(20B)] [value(10B)] [gasPrice(10B)] [gasLimit(10B)] [nonce(8B)] [chainId(2B)] [contractData(Variety)]
55+
*
5556
* @param transaction
5657
*/
5758
export const getSmartContractArgument = async (transaction: Transaction, addressIndex: number) => {
59+
const argument =
60+
handleHex(transaction.to) + // contractAddress : 81bb32e4A7e4d0500d11A52F3a5F60c9A6Ef126C
61+
handleHex(transaction.value).padStart(20, '0') + // 000000b1a2bc2ec50000
62+
handleHex(transaction.gasPrice).padStart(20, '0') + // 0000000000020c855800
63+
handleHex(transaction.gasLimit).padStart(20, '0') + // 0000000000000000520c
64+
handleHex(transaction.nonce).padStart(16, '0') + // 0000000000000289
65+
handleHex(transaction.data); // variant data
66+
67+
return '15' + (await utils.getPath(COIN_TYPE, addressIndex)) + argument;
68+
};
69+
70+
/**
71+
* [contractAddress(20B)] [value(10B)] [gasPrice(10B)] [gasLimit(10B)] [nonce(8B)] [chainId(2B)] [dataLength(4B)]
72+
*
73+
* @param transaction
74+
*/
75+
export const getSmartContractSegmentArgument = async (transaction: Transaction, addressIndex: number) => {
5876
const argument =
5977
handleHex(transaction.to) + // contractAddress : 81bb32e4A7e4d0500d11A52F3a5F60c9A6Ef126C
6078
handleHex(transaction.value).padStart(20, '0') + // 000000b1a2bc2ec50000

packages/coin-cro/webpack.config.js

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.inputs-component {
2+
width: 100%;
3+
font-size: 1.25rem;
4+
line-height: 1.75rem;
5+
margin-top: 1rem;
6+
flex-wrap: nowrap;
7+
}
8+
9+
.inputs-component .text-area {
10+
display: flex;
11+
width: 100%;
12+
justify-items: center;
13+
border-radius: 0.25rem;
14+
background-color: #808080;
15+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
16+
'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
17+
}
18+
19+
.inputs-component .input-col {
20+
padding: 0;
21+
margin-right: 1rem;
22+
}
23+
24+
.inputs-component .button-group {
25+
display: flex;
26+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React, { memo, FC } from 'react';
2+
import { Row, Col, ButtonGroup, Button as BootStrapButton, Form } from 'react-bootstrap';
3+
import './Inputs.css'
4+
5+
const row = 'inputs-component';
6+
7+
const textArea = 'text-area';
8+
9+
const inputCol = 'input-col';
10+
11+
const buttonGroup = 'button-group';
12+
13+
const button = 'button';
14+
15+
interface Input {
16+
xs?: number;
17+
value: string;
18+
placeholder: string;
19+
onChange(value: string): void;
20+
}
21+
22+
interface Props {
23+
title: string;
24+
inputs: Input[];
25+
content: string;
26+
onClick(): void;
27+
btnTitle?: string;
28+
variant?: string;
29+
disabled?: boolean;
30+
}
31+
32+
const ButtonInputs: FC<Props> = (props: Props) => {
33+
return (
34+
<Row className={row}>
35+
<Col xs={2}>{props.title}</Col>
36+
{props.inputs.map((input, i) => (
37+
<Col xs={input.xs ?? 2} key={'' + i + ''} className={inputCol}>
38+
<Form.Control
39+
value={input.value}
40+
onChange={(event) => {
41+
input.onChange(event.target.value);
42+
}}
43+
placeholder={input.placeholder}
44+
/>
45+
</Col>
46+
))}
47+
<Col className={textArea}>{props.content}</Col>
48+
<Col xs={2}>
49+
<ButtonGroup className={buttonGroup}>
50+
<BootStrapButton className={button} variant={props.variant} disabled={props.disabled} onClick={props.onClick}>
51+
{props.btnTitle}
52+
</BootStrapButton>
53+
</ButtonGroup>
54+
</Col>
55+
</Row>
56+
);
57+
};
58+
59+
ButtonInputs.defaultProps = { disabled: false, variant: 'outline-light', btnTitle: 'Get' };
60+
61+
export default memo(ButtonInputs);

0 commit comments

Comments
 (0)