Skip to content

Commit baa446b

Browse files
committed
Merge remote-tracking branch 'origin/development' into check_source_sfx
2 parents dd81e8a + 201bf0d commit baa446b

File tree

34 files changed

+2066
-6674
lines changed

34 files changed

+2066
-6674
lines changed

client/cli/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

client/cli/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## t3rn CLI
2+
A simple CLI tool for interacting with the t3rn circuit.
3+
4+
### Setup:
5+
Before interacting with the t3rn circuit, we need to configure a couple of things. The is done in `config/setup.ts`.
6+
7+
#### Circuit Section:
8+
Here we simply specify the circuit WS endpoint we want to interact with
9+
```
10+
circuit: {
11+
rpc: "ws://127.0.0.1:9944",
12+
},
13+
```
14+
15+
#### Gateway Section:
16+
Here we specify the different parameters that describe a gateway. This is important for registrations, but also for handling decimal points, address formats etc. in other transactions
17+
18+
The `transferData` section must also be noted. Here we can specify default values for the transfer command. Currently, fee and receiver can be specified.
19+
20+
21+
### Supported Transactions:
22+
A list of the supported transactions.
23+
24+
#### Register Gateway:
25+
Currently, the registration for relaychains is only supported. The registration can be executed by running: `ts-node index.ts register roco`. Note that `roco` matches the gatewayId as specified in the configs.
26+
27+
#### setOperational:
28+
to use a newly registered gateway, it must be set operations. This can be done with: `ts-node index.ts setOperational roco true`
29+
30+
#### Transfer:
31+
A simple transfer, currently only supporting nativ substrate assets.
32+
33+
`ts-node index.ts transfer roco 0.1 receiver (optinal) fee (optional)`
34+
35+
If the optional parameters are omitted, the default values specified in the config will be used.

client/cli/commands/operational.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import{ ApiPromise, Keyring, WsProvider } from'@polkadot/api';
2+
3+
export const setOperational = async (circuit: ApiPromise, gatewayData: any, argument: boolean) => {
4+
switch(gatewayData.registrationData.gatewayVendor) {
5+
case "Substrate": {
6+
return circuit.tx.multiFinalityVerifierDefault.setOperational(argument, gatewayData.id)
7+
break;
8+
}
9+
default: {
10+
console.log(`SetOperational not available for Vendor ${gatewayData.registrationData.gatewayVendor}`)
11+
return
12+
}
13+
}
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { registerSubstrate } from "./substrate";
2+
3+
export const register = async (circuitApi: any, gatewayData: any) => {
4+
switch(gatewayData.registrationData.gatewayVendor) {
5+
case "Substrate": {
6+
return registerSubstrate(circuitApi, gatewayData)
7+
}
8+
default: {
9+
console.log(`Registration not available for Vendor ${gatewayData.registrationData.gatewayVendor}`)
10+
return
11+
}
12+
}
13+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import{ ApiPromise, Keyring, WsProvider } from'@polkadot/api';
2+
import { extractAuthoritySetFromFinalityProof } from "../../utils/decoder";
3+
4+
const axios = require('axios').default;
5+
6+
export const registerSubstrate = async (circuit: ApiPromise, gatewayData: any) => {
7+
const target = await ApiPromise.create({
8+
provider: new WsProvider(gatewayData.rpc),
9+
})
10+
11+
if(gatewayData.registrationData.relaychain === null) { // relaychain
12+
return registerRelaychain(circuit, target, gatewayData)
13+
} else {
14+
console.log("Not implemented!")
15+
return
16+
// registerParachain(target, gatewayData)
17+
}
18+
}
19+
20+
const registerRelaychain = async (circuit: ApiPromise, target: ApiPromise, gatewayData: any) => {
21+
const abiConfig = createAbiConfig(circuit, gatewayData.registrationData.gatewayConfig)
22+
const gatewayGenesis = createGatewayGenesis(circuit, target);
23+
const gatewaySysProps = createGatewaySysProps(circuit, gatewayData.registrationData.gatewaySysProps)
24+
const { registrationHeader, authorities, authoritySetId } = await fetchConsensusData(circuit, target, gatewayData)
25+
const allowedSideEffects = circuit.createType('Vec<AllowedSideEffect>', gatewayData.registrationData.allowedSideEffects)
26+
return circuit.tx.circuitPortal.registerGateway(
27+
gatewayData.rpc,
28+
gatewayData.id,
29+
null,
30+
abiConfig,
31+
circuit.createType('GatewayVendor', 'Substrate'),
32+
circuit.createType('GatewayType', { ProgrammableExternal: 1 }),
33+
gatewayGenesis,
34+
gatewaySysProps,
35+
registrationHeader,
36+
authorities,
37+
authoritySetId,
38+
allowedSideEffects
39+
);
40+
}
41+
42+
const createGatewayGenesis = async (circuit: ApiPromise, target: ApiPromise) => {
43+
const [metadata, genesisHash] = await Promise.all([
44+
await target.runtimeMetadata,
45+
await target.genesisHash,
46+
]);
47+
return circuit.createType('GatewayGenesisConfig', [
48+
circuit.createType('Option<Bytes>', metadata.asV14.pallets.toHex()),
49+
metadata.asV14.extrinsic.version,
50+
genesisHash,
51+
]);
52+
}
53+
54+
const createAbiConfig = (circuiApi: ApiPromise, gatewayConfig: any) => {
55+
return circuiApi.createType('GatewayABIConfig', [
56+
circuiApi.createType('u16', gatewayConfig.blockNumberTypeSize),
57+
circuiApi.createType('u16', gatewayConfig.hashSize),
58+
circuiApi.createType('HasherAlgo', gatewayConfig.hasher),
59+
circuiApi.createType('CryptoAlgo', gatewayConfig.crypto),
60+
circuiApi.createType('u16', gatewayConfig.addressLength),
61+
circuiApi.createType('u16', gatewayConfig.valueTypeSize),
62+
circuiApi.createType('u16', gatewayConfig.decimals),
63+
circuiApi.createType('Vec<StructDecl>', gatewayConfig.structs),
64+
]);
65+
}
66+
67+
const createGatewaySysProps = (circuiApi: ApiPromise, gatewaySysProps: any) => {
68+
return circuiApi.createType('GatewaySysProps', [
69+
circuiApi.createType('u16', gatewaySysProps.ss58Format),
70+
circuiApi.createType('Vec<u8>', gatewaySysProps.tokenSymbol),
71+
circuiApi.createType('u8', gatewaySysProps.tokenDecimals),
72+
]);
73+
}
74+
75+
const fetchConsensusData = async (circuit: ApiPromise, target: ApiPromise, gatewayData: any) => {
76+
const registrationHeight = await fetchLatestAuthoritySetUpdateBlock(gatewayData)
77+
console.log("Latest AuthoritySetUpdate:", registrationHeight)
78+
79+
const registrationHeader = await target.rpc.chain.getHeader(
80+
await target.rpc.chain.getBlockHash(registrationHeight)
81+
)
82+
83+
const finalityProof = await target.rpc.grandpa.proveFinality(registrationHeight);
84+
const authorities= extractAuthoritySetFromFinalityProof(finalityProof)
85+
const authoritySetId = await target.query.grandpa.currentSetId()
86+
return {
87+
registrationHeader: circuit.createType('Bytes', registrationHeader.toHex()),
88+
authorities: circuit.createType('Option<Vec<AccountId>>', authorities),
89+
authoritySetId: circuit.createType('Option<SetId>', authoritySetId),
90+
}
91+
}
92+
93+
//for registrations we want to get the justification cotaining the latest authoritySetUpdate, as we can be sure that all authorties are included.
94+
const fetchLatestAuthoritySetUpdateBlock = async (gatewayData: any) => {
95+
return axios.post(gatewayData.subscan + '/api/scan/events', {
96+
row: 1,
97+
page: 1,
98+
module: "grandpa",
99+
call: "newauthorities"
100+
},
101+
{
102+
headers: {
103+
'content-type': 'text/json'
104+
}
105+
}
106+
)
107+
.then(function (response) {
108+
return response.data.data.events.map(entry => entry.block_num)[0]
109+
})
110+
}

client/cli/commands/transfer.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { transferAmount } from "../utils/encoder";
2+
import{ ApiPromise, Keyring, WsProvider }from'@polkadot/api';
3+
4+
export const transfer = async (circuit: ApiPromise, gatewayData: any, amount: number, sender: string, receiver: string, fee: number) => {
5+
const keyring = new Keyring({ type: "sr25519" })
6+
const signer =
7+
process.env.CIRCUIT_KEY === undefined
8+
? keyring.addFromUri("//Alice")
9+
: keyring.addFromMnemonic(process.env.CIRCUIT_KEY)
10+
return new Promise((res, rej) => {
11+
circuit.tx.circuit
12+
.onExtrinsicTrigger(
13+
[
14+
{
15+
target: gatewayData.id,
16+
prize: 0,
17+
ordered_at: 0,
18+
encoded_action: [116, 114, 97, 110], //tran
19+
encoded_args: [sender, receiver, amount],
20+
signature: null,
21+
enforce_executioner: null,
22+
}
23+
],
24+
fee,
25+
false
26+
)
27+
.signAndSend(signer, async result => {
28+
// @ts-ignore
29+
if (result && result.toHuman().dispatchError !== undefined) { // The pallet doesn't return a proper error
30+
// @ts-ignore
31+
rej(result.toHuman().dispatchError)
32+
} else if (result.isInBlock) {
33+
res(true)
34+
}
35+
})
36+
})
37+
38+
39+
}

client/cli/config/rpc.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"circuitPortal": {
3+
"readLatestGatewayHeight": {
4+
"description": "Returns the gateways height knows by circuit",
5+
"params": [
6+
{
7+
"name": "chain_id",
8+
"type": "[u8; 4]"
9+
},
10+
{
11+
"name": "at",
12+
"type": "Hash",
13+
"isOptional": true
14+
}
15+
],
16+
"type": "ReadLatestGatewayHeight"
17+
}
18+
},
19+
"xdns": {
20+
"fetchRecords": {
21+
"description": "Fetches all available XDNS Records on Circuit",
22+
"params": [
23+
{
24+
"name": "at",
25+
"type": "Hash",
26+
"isOptional": true
27+
}
28+
],
29+
"type": "FetchXdnsRecordsResponse"
30+
},
31+
"fetchAbi": {
32+
"description": "Fetches abi of a specific gateway",
33+
"params": [
34+
{
35+
"name": "chain_id",
36+
"type": "ChainId"
37+
},
38+
{
39+
"name": "at",
40+
"type": "Hash",
41+
"isOptional": true
42+
}
43+
],
44+
"type": "GatewayABIConfig"
45+
}
46+
}
47+
}

client/cli/config/setup.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export default {
2+
circuit: {
3+
rpc: "ws://127.0.0.1:9944",
4+
},
5+
gateways: [
6+
{
7+
name: "Rococo",
8+
id: "roco",
9+
rpc: "wss://rococo-rpc.polkadot.io",
10+
subscan: "https://rococo.api.subscan.io",
11+
transferData: {
12+
receiver: "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
13+
fee: 0,
14+
},
15+
registrationData: {
16+
relaychain: null,
17+
gatewayConfig: {
18+
blockNumberTypeSize: 32,
19+
hashSize: 32,
20+
hasher: "Blake2",
21+
crypto: "sr25519",
22+
addressLength: 32,
23+
valueTypeSize: 8,
24+
decimals: 12,
25+
structs: []
26+
},
27+
gatewayVendor: "Substrate",
28+
gatewayType: { ProgrammableExternal: 1 },
29+
gatewaySysProps: {
30+
tokenSymbol: "ROC",
31+
tokenDecimals: 12,
32+
ss58Format: 60
33+
},
34+
allowedSideEffects: ["tran"]
35+
}
36+
}
37+
]
38+
}

0 commit comments

Comments
 (0)