Skip to content

Commit 1238802

Browse files
authored
Merge pull request #1385 from Phala-Network/jssdk-format
JSSDK: formatting, linters, tests
2 parents cd4c232 + 058c6c3 commit 1238802

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2819
-1313
lines changed

.github/workflows/test-jssdk.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: CI for JS-SDK
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
paths:
7+
- frontend/packages/sdk/**
8+
pull_request:
9+
paths:
10+
- frontend/packages/sdk/**
11+
12+
jobs:
13+
test-jssdk:
14+
runs-on: ubuntu-latest
15+
defaults:
16+
run:
17+
working-directory: ./frontend/packages/sdk
18+
steps:
19+
- uses: actions/checkout@v2
20+
- uses: actions/setup-node@v2
21+
with:
22+
node-version: '18'
23+
cache: yarn
24+
cache-dependency-path: ./frontend/packages/sdk/yarn.lock
25+
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
26+
- run: yarn install --frozen-lockfile --check-files
27+
- name: Prettier
28+
run: yarn prettier:ci
29+
- name: Lint
30+
run: yarn eslint:ci
31+
- name: Type
32+
run: yarn pretest
33+
- name: Test
34+
run: yarn test:ci
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
**/proto/*
1+
proto/*
2+
**/*.d.ts
23
dist
34
esm
45
protoWrapper.js

frontend/packages/sdk/.eslintrc

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,120 @@
11
{
22
"env": {
3-
"es2021": true,
43
"browser": true,
5-
"node": true
4+
"shared-node-browser": true,
5+
"node": true,
6+
"es6": true
67
},
78
"extends": [
89
"eslint:recommended",
910
"plugin:@typescript-eslint/recommended",
10-
"plugin:prettier/recommended"
11+
"prettier",
12+
"plugin:prettier/recommended",
13+
"plugin:react-hooks/recommended",
14+
"plugin:import/errors",
15+
"plugin:import/warnings"
16+
],
17+
"plugins": [
18+
"@typescript-eslint",
19+
"react",
20+
"prettier",
21+
"react-hooks",
22+
"import",
23+
"vitest"
1124
],
1225
"parser": "@typescript-eslint/parser",
26+
"parserOptions": {
27+
"ecmaversion": 2018,
28+
"sourcetype": "module",
29+
"ecmafeatures": {
30+
"jsx": true
31+
}
32+
},
1333
"rules": {
14-
"no-console": "error",
15-
"@typescript-eslint/no-explicit-any": 0
16-
}
34+
"eqeqeq": "error",
35+
"no-var": "error",
36+
"prefer-const": "error",
37+
"curly": ["warn", "multi-line", "consistent"],
38+
"no-console": "off",
39+
"import/no-unresolved": ["error", { "commonjs": true, "amd": true }],
40+
"import/export": "error",
41+
"import/no-duplicates": ["error"],
42+
"@typescript-eslint/ban-ts-comment": "off",
43+
"no-async-promise-executor": "off",
44+
"no-prototype-builtins": "off",
45+
"no-constant-condition": "off",
46+
"@typescript-eslint/no-unused-vars": [
47+
"warn",
48+
{ "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }
49+
],
50+
"@typescript-eslint/no-use-before-define": "off",
51+
"@typescript-eslint/no-empty-function": "off",
52+
"@typescript-eslint/no-explicit-any": "off",
53+
"vitest/consistent-test-it": [
54+
"error",
55+
{ "fn": "it", "withinDescribe": "it" }
56+
],
57+
"import/namespace": "off",
58+
"import/named": "off",
59+
"import/order": [
60+
"error",
61+
{
62+
"alphabetize": { "order": "asc", "caseInsensitive": true },
63+
"groups": [
64+
"builtin",
65+
"external",
66+
"internal",
67+
"parent",
68+
"sibling",
69+
"index",
70+
"object"
71+
],
72+
"newlines-between": "never",
73+
"pathGroups": [
74+
{
75+
"pattern": "react",
76+
"group": "builtin",
77+
"position": "before"
78+
}
79+
],
80+
"pathGroupsExcludedImportTypes": ["builtin"]
81+
}
82+
],
83+
"react/jsx-uses-react": "off",
84+
"react/react-in-jsx-scope": "off",
85+
"sort-imports": [
86+
"error",
87+
{
88+
"ignoreDeclarationSort": true
89+
}
90+
]
91+
},
92+
"settings": {
93+
"react": {
94+
"version": "detect"
95+
},
96+
"import/extensions": [".js", ".jsx", ".ts", ".tsx"],
97+
"import/parsers": {
98+
"@typescript-eslint/parser": [".js", ".jsx", ".ts", ".tsx"]
99+
},
100+
"import/resolver": {
101+
"alias": {
102+
"extensions": [".js", ".jsx", ".ts", ".tsx"]
103+
}
104+
}
105+
},
106+
"overrides": [
107+
{
108+
"files": ["tests/**/*.ts", "tests/**/*.tsx"],
109+
"rules": {
110+
"import/extensions": ["error", "never"]
111+
}
112+
},
113+
{
114+
"files": ["./*.js"],
115+
"rules": {
116+
"@typescript-eslint/no-var-requires": "off"
117+
}
118+
}
119+
]
17120
}

frontend/packages/sdk/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
proto
2+
!/src/pruntime/proto/*
23
node_modules
34
dist
45
!dist/.gitignore

frontend/packages/sdk/README.md

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,28 @@ yarn add @phala/sdk
1515
You need create the `apiPromise` instance first, also the `OnChainRegistry` instance for the next:
1616

1717
```js
18-
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';
19-
import { options, OnChainRegistry, signCertificate, PinkContractPromise } from '@phala/sdk';
18+
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'
19+
import { options, OnChainRegistry, signCertificate, PinkContractPromise } from '@phala/sdk'
2020

2121
const RPC_MAINNET_URL = 'wss://api.phala.network/ws'
2222
const RPC_TESTNET_URL = 'wss://poc5.phala.network/ws'
2323

2424
async function main() {
25-
const api = await ApiPromise.create(options({
26-
provider: new WsProvider(RPC_TESTNET_URL),
27-
noInitWarn: true,
28-
}))
29-
const phatRegistry = await OnChainRegistry.create(api)
25+
const api = await ApiPromise.create(
26+
options({
27+
provider: new WsProvider(RPC_TESTNET_URL),
28+
noInitWarn: true,
29+
})
30+
)
31+
const phatRegistry = await OnChainRegistry.create(api)
3032
}
3133

32-
main().then(() => process.exit(0)).catch(err => {
33-
console.error(err)
34-
process.exit(1)
35-
})
34+
main()
35+
.then(() => process.exit(0))
36+
.catch((err) => {
37+
console.error(err)
38+
process.exit(1)
39+
})
3640
```
3741

3842
You might already upload and instantiate your Phat Contract, and you need prepare 3 things before go next:
@@ -47,38 +51,38 @@ You might already upload and instantiate your Phat Contract, and you need prepar
4751
We continue with `//Alice` in follow up code snippets, so all 3 things can be ready like:
4852

4953
```javascript
50-
const keyring = new Keyring({ type: 'sr25519' });
51-
const pair = keyring.addFromUri('//Alice');
52-
const contractId = '';
53-
const abi = JSON.parse(fs.readFileSync('./your_local_path/target/ink/metadata.json', 'utf-8'));
54+
const keyring = new Keyring({ type: 'sr25519' })
55+
const pair = keyring.addFromUri('//Alice')
56+
const contractId = ''
57+
const abi = JSON.parse(fs.readFileSync('./your_local_path/target/ink/metadata.json', 'utf-8'))
5458
```
5559

5660
Now let's initializing the `PinkContractPromise` instance first.
5761

5862
```javascript
59-
const contractKey = await phatRegistry.getContractKeyOrFail(contractId);
60-
const contract = new PinkContractPromise(api, phatRegistry, abi, contractId, contractKey);
63+
const contractKey = await phatRegistry.getContractKeyOrFail(contractId)
64+
const contract = new PinkContractPromise(api, phatRegistry, abi, contractId, contractKey)
6165
```
6266

6367
In the original version of polkadot.js, `tx` refer to the `write` operation and `query` refer to the `read` operation. But in Phat Contract, they got different concepts. **`tx` means on-chain operations, `query` means off-chain operations**. We recommended you put your computation logic in off-chain codes as much as possible.
6468

6569
We also need sign a certificate when using Phat Contract. Unlike signing for a transaction, the certificate is reusable. We recommended you cache it for a period of time.
6670

6771
```javascript
68-
const cert = await signCertificate({ pair });
72+
const cert = await signCertificate({ pair })
6973
```
7074

7175
For off-chain computations (or `query` calls), we don't need set `gasLimit` and `storageDepositLimit` like what we did in the original polkadot contract, we use `cert` instead:
7276

7377
```javascript
7478
// (We perform the send from an account, here using Alice's address)
75-
const { gasRequired, storageDeposit, result, output } = await contract.query.methodName(pair.address, { cert });
79+
const { gasRequired, storageDeposit, result, output } = await contract.query.methodName(pair.address, { cert })
7680
```
7781

7882
For on-chain computations (or `tx` calls), you need estimate gas fee first. It's same as the original polkadot.js API Contract:
7983

8084
```javascript
81-
const incValue = 1;
85+
const incValue = 1
8286

8387
const { gasRequired, storageDeposit } = await contract.query.inc(pair.address, { cert }, incValue)
8488
const options = {
@@ -90,7 +94,6 @@ await contract.tx.inc(options, incValue).signAndSend(pair, { nonce: -1 })
9094

9195
And that is basic workaround with Phat Contract, it may cover almost all of your use scenarios.
9296

93-
9497
## Adavantage Topics
9598

9699
### Sign Certificate with Browser Wallet Extensions
@@ -102,17 +105,17 @@ We have two ways interact with extensions.
102105
First one is the documented in the [polkadot{js} extension documentation](https://polkadot.js.org/docs/extension/cookbook):
103106

104107
```javascript
105-
import { web3Accounts, web3Enable, web3FromSource } from '@polkadot/extension-dapp';
108+
import { web3Accounts, web3Enable, web3FromSource } from '@polkadot/extension-dapp'
106109

107110
// this call fires up the authorization popup
108-
const extensions = await web3Enable('My cool Phat Contract dApp');
111+
const extensions = await web3Enable('My cool Phat Contract dApp')
109112

110-
const availableAccounts = await web3Accounts();
111-
const account = availableAccounts[0]; // assume you choice the first visible account.
112-
const injector = await web3FromSource(account.meta.source);
113-
const signer = injector.signer;
113+
const availableAccounts = await web3Accounts()
114+
const account = availableAccounts[0] // assume you choice the first visible account.
115+
const injector = await web3FromSource(account.meta.source)
116+
const signer = injector.signer
114117

115-
const cert = await signCertificate({ signer, account });
118+
const cert = await signCertificate({ signer, account })
116119
```
117120

118121
The second one is less document but more progressive one. You can access the `window.injectedWeb3` object and inspect which Wallet Extension has been installed, let the user pick the one already in used, and interact with it directly.
@@ -121,15 +124,15 @@ The second one is less document but more progressive one. You can access the `wi
121124
// polkadot-js: the original polkadot-js extension
122125
// talisman: the Talisman extension
123126
// subwallet-js: the SubWallet extension
124-
const provider = 'polkadot-js';
127+
const provider = 'polkadot-js'
125128

126-
const injector = window.injectedWeb3[provider];
127-
const extension = await injector.enable('My cool Phat Contract dApp');
128-
const accounts = await extension.accounts.get(true);
129-
const account = availableAccounts[0]; // assume you choice the first visible account.
130-
const signer = extension.signer;
129+
const injector = window.injectedWeb3[provider]
130+
const extension = await injector.enable('My cool Phat Contract dApp')
131+
const accounts = await extension.accounts.get(true)
132+
const account = availableAccounts[0] // assume you choice the first visible account.
133+
const signer = extension.signer
131134

132-
const cert = await signCertificate({ signer, account });
135+
const cert = await signCertificate({ signer, account })
133136
```
134137

135138
### Fetch Logs
@@ -163,7 +166,6 @@ Let said we have 70 records in logserver:
163166

164167
You can check out a simple example (here)[https://github.com/Leechael/phat-contract-cli-upload/blob/main/tail.js]
165168

166-
167169
### Retrieving Contract Information
168170

169171
We divide into multiple scenarios.
@@ -173,7 +175,7 @@ We divide into multiple scenarios.
173175
You can fetch it from on-chain storage:
174176

175177
```javascript
176-
const contractKey = await this.api.query.phalaRegistry.contractKeys(contractId);
178+
const contractKey = await this.api.query.phalaRegistry.contractKeys(contractId)
177179
```
178180

179181
We also provides it with `OnChainRegistry`:
@@ -204,22 +206,18 @@ const { output } = await systemContract.query['system::codeExists']<Bool>(accoun
204206
const hasExists = output && output.isOk && output.asOk.isTrue
205207
```
206208

207-
208209
### Upload & Instantiate Contracts
209210

210211
TODO
211212

212-
213213
### Use specified Cluster & Worker
214214

215215
TODO
216216

217-
218217
### Cluster tokenomics & staking for computations
219218

220219
TODO
221220

222-
223221
## Experimental Features
224222

225223
Some experimental features may change in the future, we will prefix the function name with `unstable_`.
@@ -238,7 +236,7 @@ import { privateKeyToAccount } from 'viem/accounts'
238236
import { etherAddressToCompactPubkey, unstable_signEip712Certificate } from '@phala/sdk'
239237

240238
const account = privateKeyToAccount('<YOUR_PRIVATE_KEY>')
241-
const client = createTestClient({ account, chain: mainnet, mode: 'anvil', transport: http(), })
239+
const client = createTestClient({ account, chain: mainnet, mode: 'anvil', transport: http() })
242240
const compactPubkey = await etherAddressToCompactPubkey(client, account)
243241
const cert = await unstable_signEip712Certificate({ client, account, compactPubkey })
244242
// init & create your own PinkContractPromise instance.

0 commit comments

Comments
 (0)