diff --git a/.github/workflows/test:chains.yml b/.github/workflows/test:chains.yml
deleted file mode 100644
index 4e26b292b..000000000
--- a/.github/workflows/test:chains.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-name: Chain tests
-
-# INFO: This workflow can't push to the repository
-permissions: read-all
-
-# INFO: Run workflow on changes to the sdks
-on:
- push:
- paths:
- - 'sdk/localsdk/multichain/**'
-
-jobs:
- test:
- name: XM Chain tests
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v3
- - name: Setup Node 18
- uses: actions/setup-node@v3
- with:
- node-version: 18.x
- - name: Cache dependencies
- uses: actions/cache@v3
- with:
- path: ~/.npm
- key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
- restore-keys: |
- ${{ runner.os }}-node-
- - name: Install dependencies
- run: |
- yarn install --frozen-lockfile
- - name: Run tests
- run: |
- yarn test:chains
diff --git a/.gitignore b/.gitignore
index f9c5f3335..56dd4c2b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,5 @@ src/features/experimental/fhe/fhe_test.ts
yarn.lock
publickey
publickey
+documentation/schemas/.$*
+appmap.yml
diff --git a/data/genesis.json b/data/genesis.json
index c8bd6c4ae..9d843ac06 100644
--- a/data/genesis.json
+++ b/data/genesis.json
@@ -11,6 +11,10 @@
[
"ccc6ba0c609435a05fdbf236e7df7d60f024ed26c19d8f64b024e6163036247a",
"1000000000000000000000000000"
+ ],
+ [
+ "6f1df0905c986d41bcb01c8b542c0af8263c03ba52a3dd3af9123d99fc8e1067",
+ "1000000000000000000000000000"
]
],
"timestamp": "1692734616000",
diff --git a/documentation/Best Practices.md b/documentation/Best Practices.md
new file mode 100644
index 000000000..07666cd71
--- /dev/null
+++ b/documentation/Best Practices.md
@@ -0,0 +1,13 @@
+# Best Practices when coding in this repository
+
+## Imports
+As per `tsconfig.json`, the root of the repository is set to `./`.
+For this reason, is easy to keep all the imports sorted and tidy by avoiding relative paths such as `../mymodule.ts` and using directly `src/libs/mymodule.ts` for example.
+
+## Interfaces
+To keep everything ordered, please use the `types` folder in your subdirectory (i.e. `src/libs/blockchain/types`) and import from there. Please avoid defining and exporting interfaces all around the place.
+
+Classes should have their own file too, while not residing in a dedicated folder.
+
+## Linting and Formatting
+`trunk` linter is used and enabled globally. Configuration should be already shipped. Alternatively, you can use `prettier-eslint`. Please avoid using other formatting tools to avoid huge "false-commits".
\ No newline at end of file
diff --git a/documentation/code diagrams/Web2.drawio b/documentation/code diagrams/Web2.drawio
deleted file mode 100644
index 74c6a6c6a..000000000
--- a/documentation/code diagrams/Web2.drawio
+++ /dev/null
@@ -1,159 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/documentation/code diagrams/blockchain_diagram.png b/documentation/code diagrams/blockchain_diagram.png
new file mode 100644
index 000000000..3b59bdbef
Binary files /dev/null and b/documentation/code diagrams/blockchain_diagram.png differ
diff --git a/documentation/code diagrams/communications_diagram.png b/documentation/code diagrams/communications_diagram.png
new file mode 100644
index 000000000..5b2f2fbb0
Binary files /dev/null and b/documentation/code diagrams/communications_diagram.png differ
diff --git a/documentation/code diagrams/consensus_diagram.png b/documentation/code diagrams/consensus_diagram.png
new file mode 100644
index 000000000..ae1821e79
Binary files /dev/null and b/documentation/code diagrams/consensus_diagram.png differ
diff --git a/documentation/code diagrams/multichain_diagram.png b/documentation/code diagrams/multichain_diagram.png
new file mode 100644
index 000000000..a17039f6d
Binary files /dev/null and b/documentation/code diagrams/multichain_diagram.png differ
diff --git a/documentation/code diagrams/network_diagram.png b/documentation/code diagrams/network_diagram.png
new file mode 100644
index 000000000..6ab5cc78c
Binary files /dev/null and b/documentation/code diagrams/network_diagram.png differ
diff --git a/documentation/code diagrams/web2_diagram.png b/documentation/code diagrams/web2_diagram.png
new file mode 100644
index 000000000..57e7df657
Binary files /dev/null and b/documentation/code diagrams/web2_diagram.png differ
diff --git a/documentation/faq.docx b/documentation/faq.docx
new file mode 100644
index 000000000..d4231639f
Binary files /dev/null and b/documentation/faq.docx differ
diff --git a/documentation/schemas/.$development.drawio.bkp b/documentation/schemas/.$development.drawio.bkp
new file mode 100644
index 000000000..f315ebb38
--- /dev/null
+++ b/documentation/schemas/.$development.drawio.bkp
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/schemas/development.drawio b/documentation/schemas/development.drawio
new file mode 100644
index 000000000..58b9de10e
--- /dev/null
+++ b/documentation/schemas/development.drawio
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/schemas/development.drawio.png b/documentation/schemas/development.drawio.png
new file mode 100644
index 000000000..df5d304b0
Binary files /dev/null and b/documentation/schemas/development.drawio.png differ
diff --git a/documentation/schemas/new_tx_order.drawio b/documentation/schemas/new_tx_order.drawio
new file mode 100644
index 000000000..46cc8fa5f
--- /dev/null
+++ b/documentation/schemas/new_tx_order.drawio
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/schemas/new_tx_order.drawio.png b/documentation/schemas/new_tx_order.drawio.png
new file mode 100644
index 000000000..96299a87d
Binary files /dev/null and b/documentation/schemas/new_tx_order.drawio.png differ
diff --git a/package.json b/package.json
index 59d1bf8b6..5214657c4 100644
--- a/package.json
+++ b/package.json
@@ -10,10 +10,15 @@
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"lint:fix": "eslint . --fix --ext .ts",
"prettier-format": "prettier --config .prettierrc.json modules/**/*.ts --write",
- "start:bun": "bun -r tsconfig-paths/register src/index.ts",
- "start": "tsx -r tsconfig-paths/register src/index.ts",
"format": "prettier --plugin-search-dir . --write .",
+ "start": "tsx -r tsconfig-paths/register src/index.ts",
+ "start:bun": "bun -r tsconfig-paths/register src/index.ts",
+ "start:clean": "rm -rf data/chain.db && tsx -r tsconfig-paths/register src/index.ts",
+ "start:purge": "rm -rf .demos_identity && rm -rf data/chain.db && tsx -r tsconfig-paths/register src/index.ts",
"dev": "ts-node-dev --import tsx --respawn --transpile-only src/index.ts",
+ "upgrade_sdk": "yarn upgrade @kynesyslabs/demosdk --latest",
+ "upgrade_deps": "yarn upgrade-interactive --latest",
+ "upgrade_deps:force": "ncu -u && yarn",
"test:chains": "jest --testMatch '**/tests/**/*.ts' --testPathIgnorePatterns src/* tests/utils/* tests/**/_template* --verbose"
},
"devDependencies": {
@@ -42,39 +47,31 @@
"typescript": "^4.9.3"
},
"dependencies": {
- "@cosmjs/proto-signing": "^0.32.3",
- "@cosmjs/stargate": "^0.32.3",
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
- "@fortawesome/free-brands-svg-icons": "^6.4.2",
- "@fortawesome/free-solid-svg-icons": "^6.4.2",
- "@multiversx/sdk-core": "^12.18.0",
- "@multiversx/sdk-network-providers": "^2.2.1",
- "@multiversx/sdk-wallet": "^4.3.0",
- "@solana/web3.js": "^1.78.0",
+ "@fortawesome/free-brands-svg-icons": "^6.5.2",
+ "@fortawesome/free-solid-svg-icons": "^6.5.2",
+ "@kynesyslabs/demosdk": "^1.0.13",
"@types/express": "^4.17.21",
"@types/http-proxy": "^1.17.14",
"@types/node-forge": "^1.3.6",
- "ace-builds": "^1.31.0",
+ "ace-builds": "^1.33.0",
"argon2": "^0.31.2",
"axios": "^1.6.5",
"axios-retry": "^3.5.1",
"bcrypto": "^5.4.0",
- "bip32": "^4.0.0",
- "bitcoinjs-lib": "^6.1.3",
"buffer": "^6.0.3",
"concurrently": "^8.2.1",
"crypto-browserify": "^3.12.0",
"debounce": "^1.2.1",
"dotenv": "^16.3.1",
"eiows": "^6.7.2",
- "ethers": "^6.11.1",
"evm-chains": "^0.2.0",
- "express": "^4.18.2",
+ "express": "^4.19.2",
"file-saver": "^2.0.5",
"fuse.js": "^6.6.2",
"http-proxy": "^1.18.1",
"https-browserify": "^1.0.0",
- "javascript-time-ago": "^2.5.9",
+ "javascript-time-ago": "^2.5.10",
"js-sha256": "^0.9.0",
"lodash.clonedeep": "^4.5.0",
"mceliece": "^5.0.4",
@@ -83,6 +80,7 @@
"node-forge": "^1.3.1",
"node-mceliece": "^1.0.0",
"node-seal": "^5.1.3",
+ "npm-check-updates": "^16.14.18",
"nprogress": "^0.2.0",
"ntru": "^4.0.4",
"object-sizeof": "^2.6.3",
@@ -101,7 +99,6 @@
"socket.io-client": "^4.7.2",
"sphincs": "^3.0.4",
"sqlite3": "^5.1.6",
- "stellar-sdk": "^11.1.0",
"stream-browserify": "^3.0.0",
"stream-http": "^3.2.0",
"superdilithium": "^2.0.6",
@@ -112,7 +109,6 @@
"typeorm": "^0.3.17",
"uuid": "^9.0.0",
"ws": "^8.13.0",
- "xrpl": "^2.12.0",
"zlib": "^1.0.5"
},
"type": "module",
diff --git a/sdk/localsdk/multichain/btc.ts b/sdk/localsdk/multichain/btc.ts
deleted file mode 100644
index 28ed9ecc3..000000000
--- a/sdk/localsdk/multichain/btc.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import BIP32Factory, { BIP32Interface } from "bip32"
-import * as bip39 from "bip39"
-import * as bitcoin from "bitcoinjs-lib"
-import * as ecc from "tiny-secp256k1"
-
-import defaultChainAsync from "./types/defaultChainAsync"
-
-const bip32 = BIP32Factory(ecc)
-
-// NOTE BIP32 implementation follows:
-// LINK https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts
-
-export default class BTC extends defaultChainAsync {
- constructor(rpc_url: string) {
- super(rpc_url)
- this.name = "BTC"
- }
-
- async connect(rpc_url: string): Promise {
- throw new Error("Method not implemented.")
- }
- async disconnect(): Promise {
- throw new Error("Method not implemented.")
- }
- async getBalance(address: string): Promise {
- const response = await fetch(
- `https://blockchain.info/q/addressbalance/${address}`,
- )
- const balance = await response.text()
- return balance
- }
-
- pay(receiver: string, amount: string): Promise {
- throw new Error("Method not implemented.")
- }
- async info(account: BIP32Interface): Promise {
- let address = bitcoin.payments.p2pkh({
- pubkey: account.publicKey,
- }).address!
- return JSON.stringify(address)
- }
-
- createWallet(): any {
- // TODO Generate mnemonic
- let mnemonic
- let path = "m/0'/0/0"
- let seed = bip39.mnemonicToSeedSync(mnemonic)
- let root = bip32.fromSeed(seed)
- this.wallet = root.derivePath(path) // REVIEW is this right?
- }
-
- // INFO Accepting base58 encoded private keys like:
- // tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK
- // NOTE Alternatively you can pass in a mnemonic phrase to generate the private key.
- connectWallet(privateKey: string, mnemonic: boolean = false) {
- if (!mnemonic) {
- this.wallet = bip32.fromBase58(privateKey)
- } else {
- // Generating the seed and the private key from the mnemonic
- let seed = bip39.mnemonicToSeedSync(privateKey)
- let node = bip32.fromSeed(seed)
- let strng = node.toBase58()
- this.wallet = bip32.fromBase58(strng)
- }
- }
- signTransaction(raw_transaction: any): Promise {
- throw new Error("Method not implemented.")
- }
- sendTransaction(signed_transaction: any) {
- throw new Error("Method not implemented.")
- }
-}
diff --git a/sdk/localsdk/multichain/configs/ibcProviders.ts b/sdk/localsdk/multichain/configs/ibcProviders.ts
index b55d71b3c..8d4a43ad5 100644
--- a/sdk/localsdk/multichain/configs/ibcProviders.ts
+++ b/sdk/localsdk/multichain/configs/ibcProviders.ts
@@ -1,6 +1,6 @@
export default {
cosmos: {
mainnet: "",
- testnet: "https://rpc.sentry-01.theta-testnet.polypore.xyz"
- }
+ testnet: "https://rpc.sentry-01.theta-testnet.polypore.xyz",
+ },
}
\ No newline at end of file
diff --git a/sdk/localsdk/multichain/evm.ts b/sdk/localsdk/multichain/evm.ts
deleted file mode 100644
index 46fb5bdef..000000000
--- a/sdk/localsdk/multichain/evm.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-import {
- Contract,
- JsonRpcProvider,
- parseEther,
- TransactionReceipt,
- TransactionRequest,
- Wallet,
-} from "ethers"
-import required from "src/utilities/required"
-
-import defaultChainAsync, { IEVM } from "./types/defaultChainAsync"
-import { TransactionResponse } from "./types/multichain"
-
-export default class EVM extends defaultChainAsync implements IEVM {
- // A singleton for each chain_id
- private static instances: Map = new Map()
-
- // Chain properties
- provider: JsonRpcProvider = null
- wallet: Wallet = null
- empty_transaction: TransactionRequest
- isEIP1559: boolean = true
-
- // Specific EVM properties
- contracts: Map // Will store all the contracts instances as address: ethers.Contract}
-
- /**
- * The Singleton's constructor should always be private to prevent direct
- * construction calls with the `new` operator.
- */
-
- private constructor(
- chain_id: number,
- rpc_url: string,
- isEIP1559: boolean = true,
- ) {
- super(rpc_url)
- this.name = "evm"
- this.isEIP1559 = isEIP1559
- }
-
- async connect(rpc_url: string) {
- console.log("Connecting EVM RPC provider: " + rpc_url)
- this.provider = new JsonRpcProvider(rpc_url)
-
- // INFO: Fetch network data
- const network = await this.provider.getNetwork()
-
- // INFO: Check if network data is truthy
- this.connected = Boolean(network.name)
-
- return this.connected
- }
-
- async disconnect() {
- // TODO
- }
-
- createWallet(): any {}
-
- // INFO Connect a wallet to the EVM provider using a private key
- connectWallet(privateKey: string): Wallet {
- this.wallet = new Wallet(privateKey, this.provider)
- this.wallet.connect(this.provider)
- return this.wallet
- }
-
- // INFO Getting a balance for an address
- async getBalance(address: string): Promise {
- const balance = await this.provider.getBalance(address)
- return balance.toString()
- }
-
- // Redirection
- async transfer(receiver: string, amount: string): Promise {
- return await this.pay(receiver, amount)
- }
-
- // INFO Simply sending an amount to an address
- // NOTE Returns the transaction hash as a string
- // ANCHOR MVP
- async pay(address: string, amount: string) {
- required(this.wallet)
- let tx = { to: address, value: parseEther(amount) }
- let tx_hashed = await this.sendTransaction(tx)
- console.log(tx_hashed)
- return tx_hashed
- }
-
- async info(): Promise {
- let info = ""
- // TODO
- return info
- }
-
- async getContractInstance(address: string, abi: string): Promise {
- console.log(this)
- if (!this.provider) {
- throw new Error("Provider not connected")
- }
- let contract = new Contract(address, abi, this.provider)
- return contract
- }
-
- // INFO Here we simply return the correct skeleton for a normal transaction
- async createRawTransaction(): Promise {
- return this.empty_transaction
- }
-
- async signTransaction(raw_transaction: TransactionRequest) {
- required(this.wallet)
- return await this.wallet.signTransaction(raw_transaction)
- }
-
- async signTransactions(raw_tx: any[], options?: {}): Promise {
- throw new Error("Method not implemented.")
- }
-
- // INFO If the wallet is connected, send a transaction
- // ANCHOR MVP
- async sendTransaction(transaction: TransactionRequest) {
- required(this.wallet, "Wallet not connected")
- const txResponse = await this.wallet.sendTransaction(transaction) // NOTE It will be signed automatically
- return {
- result: "success",
- hash: txResponse.hash,
- }
- }
-
- async sendRawTransaction(raw_transaction: string): Promise {
- throw new Error("Method not implemented.")
- }
-
- async sendSignedTransaction(
- signed_transaction: string,
- ): Promise {
- if (!this.provider) {
- throw new Error("Provider not connected")
- }
- const res = await this.provider.broadcastTransaction(signed_transaction)
-
- return {
- result: "success",
- hash: res.hash,
- }
- }
-
- async waitForReceipt(tx_hash: string): Promise {
- return await this.provider.getTransactionReceipt(tx_hash)
- }
-
- // REVIEW Reader for contracts
- // ANCHOR MVP
- async readFromContract(
- contract_instance: Contract,
- function_name: string,
- args: any,
- ): Promise {
- return await contract_instance[function_name](...args)
- }
-
- // REVIEW Writer for contracts
- async writeToContract(
- contract_instance: Contract,
- function_name: string,
- args: any,
- ): Promise {
- required(this.wallet)
- return await contract_instance[function_name](...args) // NOTE Ensure it is writeable i guess
- }
-
- // SECTION Event listener
- async listenForEvent(
- event: string,
- contract: string,
- abi: any[],
- ): Promise {
- if (!this.provider) {
- throw new Error("Provider not connected")
- }
- let contractInstance = new Contract(contract, abi, this.provider)
- // REVIEW THis could work
- return contractInstance.on(event, (data: any) => {
- ////console.log(data)
- // TODO Do something with the data
- })
- }
-
- async listenForAllEvents(contract: string, abi: any[]): Promise {
- if (!this.provider) {
- throw new Error("Provider not connected")
- }
- let contractInstance = new Contract(contract, abi, this.provider)
- // REVIEW 99% Won't work
- return contractInstance.on("*", (data: any) => {
- ////console.log(data)
- // TODO Do something with the data
- })
- }
- // !SECTION Event Listener
-
- /**
- * The static method that controls the access to the singleton instance.
- *
- * This implementation let you subclass the Singleton class while keeping
- * just one instance of each subclass around.
- */
-
- // INFO Getting an instance (if it exists) or false so that we can call createInstance
- public static getInstance(chain_id: number): EVM {
- if (!EVM.instances[chain_id]) {
- return null
- }
- return EVM.instances[chain_id]
- }
-
- // INFO Creating an instance from a rpc url if not already created
- public static createInstance(chain_id: number, rpc_url: string): EVM {
- if (!EVM.instances[chain_id]) {
- EVM.instances[chain_id] = new EVM(chain_id, rpc_url)
- }
- return EVM.instances[chain_id]
- }
-}
diff --git a/sdk/localsdk/multichain/ibc.ts b/sdk/localsdk/multichain/ibc.ts
deleted file mode 100644
index 7c5181d9f..000000000
--- a/sdk/localsdk/multichain/ibc.ts
+++ /dev/null
@@ -1,323 +0,0 @@
-import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"
-import {
- DirectSecp256k1HdWallet,
- DirectSecp256k1Wallet,
-} from "@cosmjs/proto-signing"
-import {
- SigningStargateClient,
- StargateClient,
- calculateFee,
-} from "@cosmjs/stargate"
-
-import { IBCTransaction, IPayOptions } from "./types/transfers"
-import DefaultChainAsync from "./types/defaultChainAsync"
-import required from "src/utilities/required"
-
-interface IBCConnectWalletOptions {
- /**
- * The address prefix
- */
- prefix: string
-
- /**
- * The the price of a single unit of gas. This is typically a fraction of the smallest fee token unit, such as 0.012utoken
- */
- gasPrice: string
-
- /**
- * The multiplier to apply to the estimated gas price. Used to make sure transactions do not run out of gas.
- *
- * @default 2.0
- */
- multiplier?: number
-}
-
-interface IBCGetBalanceOptions {
- /**
- * The denomination of the token
- */
- denom: string
-}
-
-interface IBCPreparePayOptions extends IBCGetBalanceOptions {}
-
-interface IBCSignTxOptions extends IBCConnectWalletOptions {
- /**
- * The private key to override the connected wallet
- */
- privateKey?: string
-}
-
-export default class IBC extends DefaultChainAsync {
- address: string = ""
- chainID: string
- declare provider: StargateClient
- declare wallet: SigningStargateClient
- declare signer: DirectSecp256k1Wallet | DirectSecp256k1HdWallet
-
- // IBC options
- gasPrice: string = ""
- multiplier: number = 2.0
-
- constructor(rpc_url: string) {
- super(rpc_url)
- this.name = "ibc"
-
- // INFO: We can't await here, so we call .setRPC in .create()
- // if (rpc_url) {
- // this.setRPC(rpc_url);
- // }
- }
-
- async setRPC(rpc_url: string) {
- this.provider = await StargateClient.connect(rpc_url)
- }
-
- static async create(rpc_url: string): Promise {
- const instance = new IBC(rpc_url)
-
- if (rpc_url) {
- // INFO: Set rpc url and ping it.
- await instance.setRPC(rpc_url)
- await instance.connect()
- }
-
- return instance
- }
-
- async connect() {
- try {
- const chain_id = await this.provider.getChainId()
- this.chainID = chain_id
-
- this.connected = Boolean(chain_id)
- } catch (error) {
- this.connected = false
- }
-
- return this.connected
- }
-
- async connectWallet(privateKey: string, options: IBCConnectWalletOptions) {
- required(options.prefix, "Address prefix not provided")
- required(options.gasPrice, "Gas price not provided")
-
- // INFO: Store the gasPrice for preparePays and other methods
- this.gasPrice = options.gasPrice
-
- // INFO: Check if privateKey is a mnemonic or a private key
- const isPrivateKey = privateKey.split(" ").length === 1
-
- // INFO: Create a signer using the appropriate wallet
- if (isPrivateKey) {
- // TODO: Test this block!
- const buffer = Buffer.from(privateKey, "hex")
- this.signer = await DirectSecp256k1Wallet.fromKey(
- buffer,
- options.prefix,
- )
- } else {
- this.signer = await DirectSecp256k1HdWallet.fromMnemonic(
- privateKey,
- {
- prefix: options.prefix,
- },
- )
- }
-
- // INFO: Store the address as .getAddress can't be async
- const wallet_accounts = await this.signer.getAccounts()
- const this_account = wallet_accounts.find(account =>
- account.address.startsWith(options.prefix),
- )
-
- if (this_account) {
- this.address = this_account.address
- } else {
- throw new Error(`No account found for prefix: ${options.prefix}`)
- }
-
- this.wallet = await SigningStargateClient.connectWithSigner(
- this.rpc_url,
- this.signer,
- )
- return this.wallet
- }
-
- getAddress() {
- return this.address
- }
-
- /**
- * Get the balance of the address
- * @param address The address
- * @returns The balance of the address in the specified denomination
- */
- async getBalance(address: string, options: IBCGetBalanceOptions) {
- required(this.provider, "Provider not connected")
-
- const coins = await this.provider.getBalance(address, options.denom)
- return coins.amount
- }
-
- getEmptyTransaction(): IBCTransaction {
- return {
- signerAddress: this.getAddress(),
- messages: [
- {
- typeUrl: "/cosmos.bank.v1beta1.MsgSend",
- value: {
- fromAddress: this.getAddress(),
- toAddress: "",
- amount: [{ denom: "", amount: "" }],
- },
- },
- ],
- // INFO: Fees are to be estimated when filling the tx
- fee: null,
- memo: "",
- }
- }
-
- async pay(receiver: string, amount: string, options: IBCPreparePayOptions) {
- // INFO: Call preparePays with a single payment
- const tx = await this.multiPay([{ address: receiver, amount }], options)
- return tx[0]
- }
-
- /**
- * Prepare multiple payments
- * @param payments An array of payments
- * @param options Specifies the denomination of the token
- * @returns An array of signed transactions
- */
- async multiPay(payments: IPayOptions[], options: IBCPreparePayOptions) {
- // INFO: Create an array of transactions
- const txs = payments.map(payment => {
- const tx = this.getEmptyTransaction()
-
- // INFO: Fill the tx
- tx.messages[0].value.toAddress = payment.address
- tx.messages[0].value.amount[0].amount = payment.amount as string
- tx.messages[0].value.amount[0].denom = options.denom
- return tx
- })
-
- // INFO: Estimate the fee for the first tx
- const fees = await this.estimateTxFee(txs[0])
-
- // INFO: Since all txs here are similar, set same fee for all
- txs.forEach(tx => {
- tx.fee = fees
- })
-
- // INFO: Sign and return the txs
- return await this.signTransactions(txs)
- }
-
- async signTransaction(tx: IBCTransaction, options?: IBCSignTxOptions) {
- // INFO: Call signTransactions with a single tx
- const signed_txs = await this.signTransactions([tx], options)
- return signed_txs[0]
- }
-
- /**
- * Estimate the fee for a transaction
- * @param tx The transaction
- * @returns The estimate fee for the transaction
- */
- private async estimateTxFee(tx: IBCTransaction) {
- const signerAddress = this.getAddress()
- const gasEstimate = await this.wallet.simulate(
- signerAddress,
- tx.messages,
- tx.memo,
- )
-
- const gasLimit = Math.round(gasEstimate * this.multiplier)
- return calculateFee(gasLimit, this.gasPrice)
- }
-
- async signTransactions(
- transactions: IBCTransaction[],
- options?: IBCSignTxOptions,
- ) {
- required(this.wallet, "Wallet not connected")
-
- if (options?.privateKey) {
- const { privateKey, ...connectOptions } = options
- await this.connectWallet(privateKey, connectOptions)
- }
-
- // NOTE: Sequence management happens here
- // INFO: Get account on network
- const address = this.getAddress()
- const account = await this.wallet.getAccount(address)
-
- if (!account) {
- throw new Error(`Account ${address} not found`)
- }
-
- // INFO: Store the current sequence
- let current_sequence = account.sequence
-
- const signed_txs = transactions.map(async tx => {
- const signerInfo = {
- sequence: current_sequence,
- accountNumber: account.accountNumber,
- chainId: this.chainID,
- }
-
- // INFO: Increment the sequence for next round
- current_sequence++
-
- // INFO: Sign the tx
- const signed_tx = await this.wallet.sign(
- tx.signerAddress,
- tx.messages,
- tx.fee,
- tx.memo,
- signerInfo,
- )
-
- // INFO: Convert raw tx to bytes array (Ready for broadcast)
- const tx_bytes = TxRaw.encode(signed_tx).finish()
- return tx_bytes
- })
-
- // INFO: Return the signed transactions
- return await Promise.all(signed_txs)
- }
-
- async sendTransaction(signed_tx: Uint8Array) {
- required(this.wallet, "Wallet not connected")
-
- const hash = await this.wallet.broadcastTxSync(signed_tx)
-
- return {
- hash,
- result: "success",
- }
- }
-
- async disconnect() {
- this.resetLocals()
- this.address = ""
- this.gasPrice = ""
- return !this.connected
- }
-
- // SECTION: Unimplemented methods
- async ibcSend() {
- // TODO: Implement IBC send
- // REFERENCE: https://github.com/cosmos/cosmjs/blob/33271bc51c/packages/stargate/src/signingstargateclient.ts#L246
- throw new Error("Method not implemented")
- }
- async info(...args: any): Promise {
- throw new Error("Method not implemented.")
- }
-
- async createWallet(password?: string) {
- throw new Error("Method not implemented.")
- }
-}
diff --git a/sdk/localsdk/multichain/index.ts b/sdk/localsdk/multichain/index.ts
index ef4799085..f648dc545 100644
--- a/sdk/localsdk/multichain/index.ts
+++ b/sdk/localsdk/multichain/index.ts
@@ -1,10 +1,2 @@
-// REVIEW Why was it here? // import XRPL from './xrpl';
-//export {default as BTC} from './btc';
-export { default as EVM } from "./evm"
-export { default as SOLANA } from "./solana"
-export { default as XLM } from "./xlm"
-export { default as MULTIVERSX } from "./multiversx"
-export { default as XRPL } from "./xrpl"
export { default as DEMOS } from "./demos"
-export { default as IBC } from "./ibc"
export { default as multichainCapabilities } from "./types/multichainCapabilities"
diff --git a/sdk/localsdk/multichain/multiversx.ts b/sdk/localsdk/multichain/multiversx.ts
deleted file mode 100644
index 92f75e974..000000000
--- a/sdk/localsdk/multichain/multiversx.ts
+++ /dev/null
@@ -1,193 +0,0 @@
-import required from "src/utilities/required"
-
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-import {
- Account,
- Address,
- GasEstimator,
- IPlainTransactionObject,
- TokenTransfer,
- Transaction,
- TransferTransactionsFactory,
-} from "@multiversx/sdk-core"
-import { ApiNetworkProvider } from "@multiversx/sdk-network-providers"
-import { INetworkProvider } from "@multiversx/sdk-network-providers/out/interface"
-import { Mnemonic, UserSigner, UserWallet } from "@multiversx/sdk-wallet"
-
-import DefaultChainAsync from "./types/defaultChainAsync"
-
-export default class MULTIVERSX extends DefaultChainAsync {
- declare provider: INetworkProvider
- declare wallet: UserSigner
-
- // TODO: Review the use of #private properties
- chainID: string
-
- constructor(rpcURL: string) {
- super(rpcURL)
- this.name = "multiversx"
- }
-
- async connect(rpc_url?: string) {
- // NOTE We might not need to pass the rpc_url to the provider as it's already set in the constructor
-
- if (rpc_url) {
- this.rpc_url = rpc_url
- }
-
- this.provider = new ApiNetworkProvider(this.rpc_url, {
- timeout: 10000,
- })
-
- const networkConfig = await this.provider.getNetworkConfig()
- // NOTE: Chain ID is needed in this.pay()
- this.chainID = networkConfig.ChainID
- this.connected = Boolean(this.chainID)
-
- return this.connected
- }
-
- static async create(rpc_url?: string) {
- const instance = new MULTIVERSX(rpc_url)
-
- if (!rpc_url) {
- return instance
- }
-
- await instance.connect()
- return instance
- }
-
- async disconnect() {
- this.resetLocals()
- this.chainID = null
- }
-
- createWallet(password: string, addressIndex: number = undefined) {
- required(password, "Password is required to encrypt the key file")
-
- const mnemonics = Mnemonic.generate()
-
- const words = mnemonics.getWords()
- const words_with_index = words.map((word, index) => index + ". " + word)
-
- const secretKey = mnemonics.deriveKey(addressIndex, password)
- const wallet = UserWallet.fromSecretKey({ secretKey, password })
-
- const jsonWallet = wallet.toJSON()
-
- // NOTE: .bech32 is the address property
- const walletAddress: string = jsonWallet.bech32
-
- // TODO Return downloadable mnemonics & json files
- return {
- mnemonics: words,
- address: walletAddress,
- mnemonics_txt: words_with_index.join(""),
- wallet_keyfile: JSON.stringify(jsonWallet, null, 2),
- }
- }
-
- // @ts-ignore
- connectWallet(privateKey: string, password: string) {
- // NOTE: privateKey is the keyFile in a JSON string format
- // NOTE: the password param is not yet defined in DefaultChainAsync
-
- required(privateKey, "KeyFile is required to connect to the wallet.")
- required(password, "Password is required to decrypt the key file.")
-
- const keyfile = JSON.parse(privateKey)
- this.wallet = UserSigner.fromWallet(keyfile, password)
-
- return this.wallet
- }
-
- async getBalance(address: string): Promise {
- required(address, "address is required to get the balance")
-
- const Iaddress = new Address(address)
- const account = await this.provider.getAccount(Iaddress)
-
- return account.balance.toString()
- }
-
- async pay(receiver: string, amount: string): Promise {
- required(this.provider, "Provider not connected")
-
- const senderAdress = this.wallet.getAddress()
-
- // INFO: Sync sender account which is needed to get a nonce
- const senderAccount = new Account(senderAdress)
- const senderOnNetwork = await this.provider.getAccount(senderAdress)
- senderAccount.update(senderOnNetwork)
-
- const receiverAdress = new Address(receiver)
-
- // INFO: Gas estimation
- const gas = new GasEstimator()
- const factory = new TransferTransactionsFactory(gas)
-
- const transfer = TokenTransfer.egldFromAmount(amount)
- const tx = factory.createEGLDTransfer({
- sender: senderAdress,
- receiver: receiverAdress,
- value: transfer,
- chainID: this.chainID,
- })
-
- tx.setNonce(senderAccount.getNonceThenIncrement())
-
- // INFO: tx is the unsigned transaction
- // INFO: Return it for signing and broadcast
- return tx
- }
-
- info(): Promise {
- throw new Error("Method not implemented.")
- }
-
- async signTransaction(transaction: Transaction): Promise {
- required(this.wallet, "Wallet not connected")
-
- const serializedTx = transaction.serializeForSigning()
- const signature = await this.wallet.sign(serializedTx)
- transaction.applySignature(signature)
-
- return transaction
- }
-
- async sendTransaction(raw_tx: Transaction | IPlainTransactionObject) {
- required(this.provider, "Provider not connected")
- let signed_tx: Transaction
-
- // INFO: raw_tx is a plain object when it comes from the frontend
- if (!(raw_tx instanceof Transaction)) {
- signed_tx = Transaction.fromPlainObject(raw_tx)
- } else {
- signed_tx = raw_tx
- }
-
- // INFO: The provider can also send a list of transactions
- const tx_hash = await this.provider.sendTransaction(
- signed_tx as Transaction,
- )
-
- return {
- result: "success",
- hash: tx_hash,
- }
- }
-
- async signTransactions(raw_tx: any[], options?: {}): Promise {
- throw new Error("Method not implemented.")
- }
-}
diff --git a/sdk/localsdk/multichain/multiversx/test.ts b/sdk/localsdk/multichain/multiversx/test.ts
deleted file mode 100644
index e91a6ddb8..000000000
--- a/sdk/localsdk/multichain/multiversx/test.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import fs from "node:fs/promises"
-import path from "path"
-import { fileURLToPath } from "url"
-
-import MULTIVERSX from "../multiversx"
-
-const __filename = fileURLToPath(import.meta.url)
-const __dirname = path.dirname(__filename)
-
-const TESTNET_URL = "https://testnet-api.multiversx.com"
-const VALID_TESTNET_ADDRESS =
- "erd1fsac7hpfzyhzs2ls894579kctfzp8n3hyp6gt5n0ccnd6hp9dpkqd6hg6w"
-
-async function readKeyfileFromPath(_path: string) {
- const fullpath = path.join(__dirname, _path)
-
- // INFO: Read the keyfile from the path
- const file = await fs.readFile(fullpath, {
- encoding: "utf-8",
- })
-
- return file.trim()
-}
-
-export default async function testMultiversx() {
- const WALLET_PASSWORD = "password"
-
- const multiversx = new MULTIVERSX(TESTNET_URL)
-
- // INFO: Connecting to the network
- console.log("starting connection")
- await multiversx.connect()
-
- // INFO: Generating a wallet
- const { wallet_keyfile, address } = multiversx.createWallet(WALLET_PASSWORD)
- console.log("[MULTIVERSX] GENERATED KEY FILE")
- console.log(wallet_keyfile)
-
- // INFO: Connecting to the wallet
- const VALID_KEYFILE = await readKeyfileFromPath("keyfile.json")
- const VALID_KEYFILE_PASSWORD = await readKeyfileFromPath(
- "keyfile_password.txt",
- )
-
- multiversx.connectWallet(VALID_KEYFILE, VALID_KEYFILE_PASSWORD)
-
- // INFO: Getting the balance
- const balance = await multiversx.getBalance(VALID_TESTNET_ADDRESS)
- console.log("Balance: " + balance)
-
- // INFO: EGLD Transfer
- const tx = await multiversx.pay(address, "1.5")
- console.log(tx)
-
- // INFO: Signing a transaction
- const signedTx = await multiversx.signTransaction(tx)
- console.log(signedTx)
-
- // INFO: Sending a transaction
- const txHash = await multiversx.sendTransaction(signedTx)
-
- console.log("SENT TX HASH")
- console.log(txHash)
- console.log("chain ID before disconnect: ", multiversx.chainID)
-
- await multiversx.disconnect()
- console.log("chaid ID after disconnect: " + multiversx.chainID)
-}
diff --git a/sdk/localsdk/multichain/solana.ts b/sdk/localsdk/multichain/solana.ts
deleted file mode 100644
index 4af73ff61..000000000
--- a/sdk/localsdk/multichain/solana.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import required from "src/utilities/required"
-
-import * as solanaWeb3 from "@solana/web3.js"
-
-import defaultChainAsync from "./types/defaultChainAsync"
-
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-// LINK https://docs.solana.com/developing/clients/javascript-api
-
-export default class SOLANA extends defaultChainAsync {
- private static instance: SOLANA
-
- wallet: solanaWeb3.Keypair = null
- provider: solanaWeb3.Connection = null
-
- constructor(rpc_url: string) {
- super(rpc_url)
- this.name = "solana"
- }
-
- async connect(rpc_url: string): Promise {
- this.provider = new solanaWeb3.Connection(rpc_url)
- // TODO Check connectivity
- return true
- }
-
- async disconnect(): Promise {
- this.provider = null
- // TODO If something is to do, do it here
- }
-
- createWallet(): any {}
-
- // ANCHOR Public methods
- connectWallet(privateKey: string) {
- this.wallet = solanaWeb3.Keypair.fromSecretKey(
- Buffer.from(privateKey, "hex"),
- ) // REVIEW is this ok?
- }
-
- async getBalance(address: string): Promise {
- // TODO
- return ""
- }
-
- async pay(to: string, amount: string): Promise {
- required(this.wallet, "Wallet not connected")
- // TODO
- return null
- }
-
- async info(): Promise {
- let info = ""
- // TODO
- return info
- }
-
- // INFO Returning an empty raw transaction skeleton
- async createRawTransaction(): Promise {
- let empty_tx = new solanaWeb3.Transaction()
- return empty_tx
- }
-
- // INFO Placeholder compatibility function that is here only for the interface
- async signTransaction(raw_transaction: any): Promise {
- required(this.wallet, "Wallet not connected")
- // LINK https://docs.shyft.to/tutorials/how-to-sign-transactions-on-solana
- // NOTE Due to the above, the transaction is signed and sent at the same time.
- return raw_transaction
- }
-
- // INFO Sending a transfer transaction on Solana network
- sendTransaction({ to, amount }) {
- required(this.wallet, "Wallet not connected")
- let tx = new solanaWeb3.Transaction()
- tx.add(
- solanaWeb3.SystemProgram.transfer({
- fromPubkey: this.wallet.publicKey,
- toPubkey: to,
- lamports: amount * solanaWeb3.LAMPORTS_PER_SOL,
- }),
- )
- let result = solanaWeb3.sendAndConfirmTransaction(this.provider, tx, [
- this.wallet,
- ])
- return result
- }
-
- // ANCHOR Static singleton methods
-
- static getInstance(): SOLANA | boolean {
- if (!SOLANA.instance) {
- return false
- }
- return SOLANA.instance
- }
-
- static createInstance(rpc_url: string): SOLANA {
- if (!SOLANA.instance) {
- SOLANA.instance = new SOLANA(rpc_url)
- }
- return SOLANA.instance
- }
-}
diff --git a/sdk/localsdk/multichain/types/transfers.ts b/sdk/localsdk/multichain/types/transfers.ts
index dda0dceba..49ef061a5 100644
--- a/sdk/localsdk/multichain/types/transfers.ts
+++ b/sdk/localsdk/multichain/types/transfers.ts
@@ -1,4 +1,4 @@
-import { MsgSendEncodeObject, StdFee } from '@cosmjs/stargate';
+import { MsgSendEncodeObject, StdFee } from "@cosmjs/stargate"
/**
* `preparePay` parameters
diff --git a/sdk/localsdk/multichain/xlm.ts b/sdk/localsdk/multichain/xlm.ts
deleted file mode 100644
index 1f49a9f89..000000000
--- a/sdk/localsdk/multichain/xlm.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-// LINK https://github.com/stellar/js-stellar-sdk/tree/master/docs/reference
-
-import required from "src/utilities/required"
-import * as StellarSdk from "stellar-sdk"
-
-import Server from "../../../src/libs/network/server"
-import defaultChainAsync from "./types/defaultChainAsync"
-
-// TODO Find a way to make things in the next link much more unified
-// LINK https://github.com/stellar/js-stellar-base/blob/master/docs/reference/building-transactions.md
-export default class XLM extends defaultChainAsync {
- constructor(rpcURL: string) {
- super(rpcURL)
- this.name = "xlm"
- }
-
- public async connect(rpcURL: string): Promise {
- console.log("stellar not yet implemented. check the code")
- process.exit(0)
- // this.provider = new StellarSdk(rpcURL) // 'https://horizon-testnet.stellar.org' // FIXME
- return true
- }
-
- public async disconnect(): Promise {
- throw new Error("Method not implemented.")
- }
-
- createWallet(): any {}
-
- // INFO Loading a keypair from a private key string
- connectWallet(privateKey: string) {
- this.wallet = StellarSdk.Keypair.fromSecret(privateKey)
- }
- getBalance(address: string): Promise {
- throw new Error("Method not implemented.")
- }
- pay(receiver: string, amount: string): Promise {
- throw new Error("Method not implemented.")
- }
- info(): Promise {
- throw new Error("Method not implemented.")
- }
-
- // REVIEW Signing a pre built transaction
- async signTransaction(raw_transaction: any): Promise {
- required(this.wallet, "Wallet not connected")
- let signed_tx = await raw_transaction.sign(this.wallet)
- return signed_tx
- }
-
- sendTransaction(transactions: any) {
- throw new Error("Method not implemented.")
- }
-}
diff --git a/sdk/localsdk/multichain/xrpl.ts b/sdk/localsdk/multichain/xrpl.ts
deleted file mode 100644
index 61905319e..000000000
--- a/sdk/localsdk/multichain/xrpl.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-import * as xrpl from "xrpl"
-
-// import WebSocket from "ws" // NOTE tsx compatibility
-import DefaultChainAsync from "./types/defaultChainAsync"
-
-// LINK https://js.xrpl.org/
-// TODO https://xrpl.org/monitor-incoming-payments-with-websocket.html
-
-export default class XRPL extends DefaultChainAsync {
- provider: xrpl.Client = null
- wallet: xrpl.Wallet = null
-
- constructor(rpc_url: string) {
- super(rpc_url) // overwrote -> (rpc_url)
- this.name = "xrpl"
- }
-
- // SECTION Initializations
-
- // INFO Connects to a XRP rpc server
- public async connect(rpc: string) {
- this.provider = new xrpl.Client(rpc, {
- connectionTimeout: 10000,
- })
-
- // INFO Connects to the provider with error handling
- let trial_index = 0
- let maxTrials = 3
-
- const providerConnect = async () => {
- console.log(`[XRPL] ${maxTrials - trial_index} retries left`)
-
- try {
- await this.provider.connect()
- console.log(
- `[XRPL] Connected to RPC on ${trial_index + 1}th trial`,
- )
-
- return true
- } catch (error) {
- console.log("[XRPL] Error connecting to RPC")
- console.log(error)
-
- trial_index++
- if (trial_index == maxTrials) {
- // INFO: Return false if we failed to connect
- console.log("[XRPL] Failed to connect to RPC")
- return false
- }
-
- // INFO: Retry for the Nth time
- console.log("[XRPL] Retrying ...")
- await providerConnect()
- }
-
- return false
- }
-
- // Listen for connection events
- this.provider.on("connected", () => {
- console.log("Successfully connected to XRPL.")
- this.connected = true
- })
-
- // Handle disconnection events
- this.provider.on("disconnected", async code => {
- // Handle the disconnection event (e.g., attempt to reconnect)
- console.log(
- `Disconnected from XRPL with code: ${code}, attempting to reconnect...`,
- )
- this.connected = false
-
- this.connected = await providerConnect()
- })
-
- // Handle errors
- this.provider.on("error", (errorCode, errorMessage, data) => {
- console.log(`XRPL Client Error: ${errorCode}, ${errorMessage}`)
- // Handle the error based on errorCode and errorMessage
- })
-
- // Finally, connect to the provider
- this.connected = await providerConnect()
- return this.connected
- }
-
- // INFO Manages a clean exit
- public async disconnect(): Promise {
- await this.provider.disconnect()
- this.connected = false
- return true
- }
-
- // INFO Connects to a wallet on XRPL
- async connectWallet(seed: string) {
- this.wallet = xrpl.Wallet.fromSeed(seed)
- }
-
- // INFO Creates a new wallet
- async createWallet() {
- this.wallet = xrpl.Wallet.generate()
- }
-
- // !SECTION Initializations
-
- // SECTION Reads
-
- // INFO Generic account info
- async accountInfo(address: string): Promise {
- return await this.provider.request({
- command: "account_info",
- account: address,
- ledger_index: "validated",
- })
- }
-
- // INFO Getting balance for an address (supports both XRP and other tokens)
- async getBalance(address: string, multi: boolean = true) {
- let response = null
- if (multi) {
- response = await this.provider.getBalances(address)
- } else {
- response = await this.provider.getXrpBalance(address)
- }
- return response
- }
-
- // !SECTION Reads
-
- // SECTION Writes
-
- // INFO Sending XRP to an address
- // ANCHOR MVP
- async pay(
- receiver: string,
- amount: string,
- send: boolean = true,
- ): Promise {
- // Preparing a payment tx
- const prepared = await this.provider.autofill({
- TransactionType: "Payment",
- Account: this.wallet.address,
- Amount: xrpl.xrpToDrops(amount),
- Destination: receiver,
- })
-
- // FIXME See below
- /*const max_ledger = prepared.LastLedgerSequence
- console.log("Prepared transaction instructions:", prepared)
- console.log("Transaction cost:", xrpl.dropsToXrp(prepared.Fee), "XRP")
- console.log("Transaction expires after ledger:", max_ledger) */
- if (send) {
- console.log("Sending transaction...")
- console.log(prepared)
- return await this.sendTransaction(prepared)
- } else {
- // Just signing the tx
- let signed = this.wallet.sign(prepared)
- return signed
- }
- }
-
- async info(): Promise {
- let info = ""
- // TODO Implement
- return info
- }
-
- async signTransaction(raw_tx: any): Promise {
- // Signing the tx
- let signed = this.wallet.sign(raw_tx)
- console.log("Hash: " + signed.hash)
- console.log("Blob: " + signed.tx_blob)
- return signed
- }
-
- async signTransactions(raw_tx: any[], options?: {}): Promise {
- throw new Error("Method not implemented.")
- }
-
- // INFO Generic sign, send and await (if not specified) a tx
- async sendTransaction(signed: any, wait: boolean = false) {
- // Sending the tx
- console.log("[xrpl] sendtransaction")
-
- if (wait) {
- const res = await this.provider.submitAndWait(signed.tx_blob)
-
- // NOTE: The return type here might need to change
- return {
- result: "success",
- hash: res.result.hash,
- }
- } else {
- const res = await this.provider.submit(signed.tx_blob)
-
- return {
- result: res.result.accepted ? "success" : "error",
- hash: res.result.tx_json.hash,
- extra: {
- accepted: res.result.accepted,
- result: res.result.engine_result,
- result_code: res.result.engine_result_code,
- result_message: res.result.engine_result_message,
- },
- }
- }
- }
-
- // !SECTION Writes
-}
diff --git a/src/features/InstantMessagingProtocol/instantMessagingProtocol.ts b/src/features/InstantMessagingProtocol/instantMessagingProtocol.ts
index 9506173bd..f5aaef229 100644
--- a/src/features/InstantMessagingProtocol/instantMessagingProtocol.ts
+++ b/src/features/InstantMessagingProtocol/instantMessagingProtocol.ts
@@ -1 +1,2 @@
import IMSession from "./types/IMSession"
+
diff --git a/src/features/experimental/fhe/FHE.ts b/src/features/fhe/FHE.ts
similarity index 100%
rename from src/features/experimental/fhe/FHE.ts
rename to src/features/fhe/FHE.ts
diff --git a/src/features/fhe/fhe_test.ts b/src/features/fhe/fhe_test.ts
new file mode 100644
index 000000000..085dbbb5d
--- /dev/null
+++ b/src/features/fhe/fhe_test.ts
@@ -0,0 +1,77 @@
+import { cipher } from "node-forge"
+
+import FHE from "./FHE"
+
+async function main() {
+
+ // Create a new instance of FHE
+ // NOTE The resulting instance will be used to perform operations on the encrypted data
+ // Only this specific instance will be able to decrypt the data it encrypted
+ const fhe = await FHE.getInstance()
+ await fhe.config.setParameters()
+ await fhe.config.createKeysAndEncoders()
+
+ console.log("[+] FHE instance created")
+ console.log("\n\n[ Math Operations ]")
+ // Create data to be encrypted
+ let plainData = 7
+ let addStep = 5
+ let multiplyStep = 3
+ // Encrypt the PlainText
+ var cipheredData = await fhe.encryption.encryptNumber(plainData)
+
+ console.log("\n[Addition]")
+ var cipheredAddStep = await fhe.encryption.encryptNumber(addStep)
+ // Add the CipherText to itself and store it in the destination parameter (itself)
+ var cipheredAdditionResult = await fhe.math.addNumbers(cipheredData, cipheredAddStep)
+ // Decrypt the CipherText
+ var decryptedAdditionResult = await fhe.encryption.decryptNumber(cipheredAdditionResult)
+ console.log("plainData: ", plainData, "\naddStep: ", addStep, "\ndecryptedAdditionResult: ", decryptedAdditionResult)
+
+ var decryptedData = await fhe.encryption.decryptNumber(cipheredData)
+
+ if (decryptedData !== decryptedAdditionResult) {
+ console.log("\n[ERROR] The decryptedData is not equal to decryptedAdditionResult")
+ process.exit(-1)
+ }
+ console.log("\n[OK] Now the cipheredData is equal to decryptedAdditionResult: ", decryptedData)
+ console.log("\n[Multiplication]")
+ var cipheredMultiplyStep = await fhe.encryption.encryptNumber(multiplyStep)
+ // Multiply the CipherText to itself and store it in the destination parameter (itself)
+ var cipheredMultiplicationResult = await fhe.math.multiplyNumbers(cipheredData, cipheredMultiplyStep)
+ // Decrypt the CipherText
+ var decryptedMultiplicationResult = await fhe.encryption.decryptNumber(cipheredMultiplicationResult)
+ console.log("plainData: ", plainData, "\nmultiplyStep: ", multiplyStep, "\ndecryptedMultiplyResult: ", decryptedMultiplicationResult)
+
+ decryptedData = await fhe.encryption.decryptNumber(cipheredData)
+ if (decryptedData !== decryptedMultiplicationResult) {
+ console.log("\n[ERROR] The decryptedData is not equal to decryptedMultiplicationResult")
+ process.exit(-1)
+ }
+ console.log("\n[OK] Now the cipheredData is equal to decryptedMultiplicationResult: ", decryptedData)
+
+ console.log("\n[Negate - Flipping the sign of the number]")
+ // Boolean operations
+ // Negate the CipherText and store it in the destination parameter (itself)
+ var cipheredNegateResult = await fhe.math.negate(cipheredData)
+ // Decrypt the CipherText
+ var decryptedNegateResult = await fhe.encryption.decryptNumber(cipheredNegateResult)
+ if (decryptedNegateResult !== -decryptedData) {
+ console.log("\n[ERROR] The decryptedNegateResult is not equal to -plainData")
+ process.exit(-1)
+ }
+ console.log("\ndecryptedNegateResult: ", decryptedNegateResult)
+
+ decryptedData = await fhe.encryption.decryptNumber(cipheredData)
+ if (decryptedData !== decryptedNegateResult) {
+ console.log("\n[ERROR] The decryptedData is not equal to -decryptedNegateResult")
+ process.exit(-1)
+ }
+
+ console.log("\n[OK] Now the cipheredData is equal to -decryptedNegateResult: ", decryptedData)
+
+
+}
+
+
+main()
\ No newline at end of file
diff --git a/src/features/multichain/XMDispatcher.ts b/src/features/multichain/XMDispatcher.ts
index c6c44ef44..363aa14d5 100644
--- a/src/features/multichain/XMDispatcher.ts
+++ b/src/features/multichain/XMDispatcher.ts
@@ -1,7 +1,6 @@
/* eslint-disable no-unused-vars */
import {
- DerivableNative,
- deriveMempoolOperation,
+ DerivableNative, deriveMempoolOperation,
} from "src/libs/utils/demostdlib/deriveMempoolOperation"
// INFO Entry point for multichain requests
import { json } from "stream/consumers"
@@ -14,25 +13,26 @@ export default class multichainDispatcher {
console.log("\n\n")
console.log("[XM Script full digest]")
console.log(data)
+ console.log("Stringed to:")
console.log(JSON.stringify(data))
console.log("\n\n")
console.log("[XMChain Digestion] Processing multichain operation")
- console.log(data.multichain_operation)
+ console.log(data.operations)
console.log("\n[XMChain Digestion] Having:")
- console.log(Object.keys(data.multichain_operation.operations).length)
+ console.log(Object.keys(data.operations).length)
console.log("operations")
console.log("\n===== ANALYSIS ===== \n")
console.log("\n===== FUNCTIONS ===== \n")
for (
let i = 0;
- i < Object.keys(data.multichain_operation.operations).length;
+ i < Object.keys(data.operations).length;
i++
) {
// Named function
console.log(
"[XMChain Digestion] Found: " +
- Object.keys(data.multichain_operation.operations)[i],
+ Object.keys(data.operations)[i],
)
}
console.log("\n===== END OF ANALYSIS ===== \n")
@@ -60,53 +60,13 @@ export default class multichainDispatcher {
console.log("[XM EXECUTE] Successfully executed")
console.log(results)
- // Inserting in mempool the results
- let derivedResults = await multichainDispatcher.toMempool(
- script,
- results,
- true,
- )
console.log("[XM EXECUTE] Derived Operation completed successfully")
//console.log(derivedOperation)
- let overallResult = {
- results: results,
- derivedOperation: derivedResults[0], // TODO We will want to return the demos tx hash too prolly
- }
-
console.log("[XM EXECUTE] Sending back the result")
- console.log(overallResult)
-
- return overallResult
- }
-
- static async toMempool(
- script: XMScript,
- results: any[],
- insert: boolean = true,
- ): Promise {
- // We should have a valid, attested request: lets handle it
- // NOTE If all the attestations are valid we can create the transaction, insert it and give back the result
- // Creating a tx from the completed request if is possible
- let jsonNote: DerivableNative = {
- from: "0x0", // FIXME Implement this
- to: "multichain", // FIXME Implement this more in details
- type: "xm",
- data: {
- script: script,
- results: results,
- },
- timestamp: Date.now(),
- fees: {
- networkFee: 0,
- rpcFee: 0,
- additionalFee: 0,
- }, // FIXME Implement this
- }
-
- //console.log(jsonNote)
+ console.log(results)
- return await deriveMempoolOperation(jsonNote, insert)
+ return results
}
-}
+}
\ No newline at end of file
diff --git a/src/features/multichain/routines/XMParser.ts b/src/features/multichain/routines/XMParser.ts
index 11b3ee33f..e0f193aad 100644
--- a/src/features/multichain/routines/XMParser.ts
+++ b/src/features/multichain/routines/XMParser.ts
@@ -1,6 +1,6 @@
// INFO In this module is offloaded the parsing of XM requests
import * as fs from "fs"
-import * as multichain from "sdk/localsdk/multichain"
+import * as multichain from "@kynesyslabs/demosdk/xm-localsdk"
import { chainIds } from "sdk/localsdk/multichain/configs/chainIds"
import { evmProviders } from "sdk/localsdk/multichain/configs/evmProviders"
@@ -39,7 +39,8 @@ export interface old_XMScript {
}
export interface XMScript {
- multichain_operation: { [key: string]: IOperation }
+ operations: { [key: string]: IOperation },
+ operations_order: string[]
}
class XMParser {
@@ -79,15 +80,15 @@ class XMParser {
// TODO Enforce order
for (
let id = 0;
- id < Object.keys(fullscript.multichain_operation.operations).length;
+ id < Object.keys(fullscript.operations).length;
id++
) {
try {
- name = Object.keys(fullscript.multichain_operation.operations)[
+ name = Object.keys(fullscript.operations)[
id
]
console.log("[" + name + "] ")
- operation = fullscript.multichain_operation.operations[name]
+ operation = fullscript.operations[name]
console.log("[XMParser]: full script operation")
console.log(fullscript)
console.log("[XMParser]: partial operation")
@@ -142,7 +143,7 @@ class XMParser {
const result = await handlePayOperation(operation, chainID)
// INFO: Adding chain info for debugging purposes
- result.chain = `${operation.chain}.${operation.subchain}`
+ result["chain"] = `${operation.chain}.${operation.subchain}`
return result
}
@@ -160,7 +161,7 @@ class XMParser {
// console.log(evmProviders)
let providerUrl =
evmProviders[operation.chain][operation.subchain] // REVIEW Error handling
- let evmInstance = await multichain.EVM.createInstance(
+ let evmInstance = multichain.EVM.createInstance(
chainID,
providerUrl,
) // REVIEW We should be connected
@@ -168,7 +169,7 @@ class XMParser {
`[XM Method] operation.chain: ${operation.chain}, operation.subchain: ${operation.subchain}`,
)
console.log(`[XM Method]: providerUrl: ${providerUrl}`)
- await evmInstance.connect(providerUrl)
+ await evmInstance.connect()
console.log("params: \n")
console.log(operation.task.params)
console.log("\n end params: \n")
diff --git a/src/features/multichain/routines/executors/pay.ts b/src/features/multichain/routines/executors/pay.ts
index 3e022db7c..7cb81b904 100644
--- a/src/features/multichain/routines/executors/pay.ts
+++ b/src/features/multichain/routines/executors/pay.ts
@@ -1,12 +1,11 @@
-import { multichain } from "sdk/localsdk"
+import * as multichain from "@kynesyslabs/demosdk/xm-localsdk"
+
import { chainProviders } from "sdk/localsdk/multichain/configs/chainProviders"
import { evmProviders } from "sdk/localsdk/multichain/configs/evmProviders"
import { TransactionResponse } from "sdk/localsdk/multichain/types/multichain"
import checkSignedPayloads from "src/utilities/checkSignedPayloads"
import { IOperation } from "../XMParser"
-import { IBC, MULTIVERSX } from "sdk/localsdk/multichain"
-import DefaultChainAsync from "sdk/localsdk/multichain/types/defaultChainAsync"
/**
* Executes a XM pay operation and returns
@@ -60,11 +59,11 @@ export default async function handlePayOperation(
break
case "egld":
- result = await genericJsonRpcPay(MULTIVERSX, rpc_url, operation)
+ result = await genericJsonRpcPay(multichain.MULTIVERSX, rpc_url, operation)
break
case "ibc":
- result = await genericJsonRpcPay(IBC, rpc_url, operation)
+ result = await genericJsonRpcPay(multichain.IBC, rpc_url, operation)
break
default:
@@ -87,16 +86,17 @@ export default async function handlePayOperation(
* @param operation The operation to be executed
*/
async function genericJsonRpcPay(
- sdk: typeof DefaultChainAsync,
+ sdk: typeof multichain.IBC | typeof multichain.MULTIVERSX,
rpc_url: string,
operation: IOperation,
) {
console.log([
`[XMScript Parser] Generic JSON RPC Pay on: ${operation.chain}.${operation.subchain}`,
])
- let instance: DefaultChainAsync
+ let instance: multichain.IBC | multichain.MULTIVERSX
try {
+ // @ts-expect-error
instance = await sdk.create(rpc_url)
} catch (error) {
return {
@@ -139,13 +139,9 @@ async function handleEVMPay(chainID: number, operation: IOperation) {
let evmInstance = multichain.EVM.getInstance(chainID)
if (!evmInstance) {
- evmInstance = multichain.EVM.createInstance(
- chainID,
- evmProviders[operation.chain][operation.subchain],
- )
- await evmInstance.connect(
- evmProviders[operation.chain][operation.subchain],
- )
+ const rpc_url = evmProviders[operation.chain][operation.subchain]
+ evmInstance = multichain.EVM.createInstance(chainID,rpc_url)
+ await evmInstance.connect()
}
return await multichain.EVM.getInstance(chainID).sendSignedTransaction(
@@ -170,7 +166,7 @@ async function handleXRPLPay(
"[XMScript Parser] Ripple Pay: trying to send the payload as a signed transaction...",
) // REVIEW Simulations?
let xrplInstance = new multichain.XRPL(rpc_url)
- const connected = await xrplInstance.connect(rpc_url)
+ const connected = await xrplInstance.connect()
console.log("CONNECT RETURNED: ", connected)
if (!connected) {
diff --git a/src/features/experimental/pgp/pgp.ts b/src/features/pgp/pgp.ts
similarity index 100%
rename from src/features/experimental/pgp/pgp.ts
rename to src/features/pgp/pgp.ts
diff --git a/src/features/web2/Web2Dispatcher.ts b/src/features/web2/Web2Dispatcher.ts
index f6846b454..05c47b84c 100644
--- a/src/features/web2/Web2Dispatcher.ts
+++ b/src/features/web2/Web2Dispatcher.ts
@@ -1,18 +1,17 @@
// INFO Entry file for handling web2 requests
import Web2API, { Web2APIClass } from "src/features/web2/routines/Web2Parser"
-import { IWeb2Payload, IWeb2Request } from "src/features/web2/types/Web2Types"
-import { Operation } from "src/libs/blockchain/routines/executeOperations"
import Cryptography from "src/libs/crypto/cryptography"
import Hashing from "src/libs/crypto/hashing"
import {
- DerivableNative,
- deriveMempoolOperation,
+ DerivableNative, deriveMempoolOperation,
} from "src/libs/utils/demostdlib/deriveMempoolOperation"
import required from "src/utilities/required"
import sharedState from "src/utilities/sharedState"
// NOTE Terminal kit for useful logging
import terminalkit from "terminal-kit"
+import { IWeb2Payload, IWeb2Request, Operation } from "@kynesyslabs/demosdk/types"
+
const term = terminalkit.terminal
// INFO Upon receiving a request from a socket, we
@@ -21,9 +20,9 @@ const term = terminalkit.terminal
// send back to the client or to the origin rpc the
// transaction that will b e granted as web2 result
export default async function handleWeb2(
- payload: IWeb2Payload,
+ payload: IWeb2Request,
senderSocket: any,
-): Promise<[boolean, string]> {
+): Promise<[boolean, string | IWeb2Request]> {
// Creating the workable interface
// TODO Remember that web2 could need to be signed and could need a fee
// NOTE From now on, Web2API will reply to instanceName with the same instance
@@ -34,7 +33,7 @@ export default async function handleWeb2(
//console.log(payload)
//process.exit(0)
- let request: IWeb2Request = payload.message
+ let request: IWeb2Request = payload
console.log(
"[REQUEST FOR WEB2] [+] Found and loaded payload.message as expected...",
)
@@ -60,6 +59,7 @@ export default async function handleWeb2(
let web2interface = Web2API(null, nameHash, senderSocket, payload)
// NOTE We want to wait for the request to be digested before proceeding (see above paragraph)
await web2interface.digestedPromise
+ console.log(web2interface.request.result)
// Now result is in web2request.request.result
console.log(
"[web2Dispatcher] Request digested and promise solved. Registering the instance...",
@@ -135,8 +135,6 @@ export default async function handleWeb2(
console.log(
"[web2Dispatcher] Attestations validated. Deriving a transaction + operation...",
)
- let derivedResult = await toMempool(instanceName)
- console.log("[web2Dispatcher] Transaction + operation derived.")
Web2API("remove", nameHash, senderSocket)
@@ -147,31 +145,5 @@ export default async function handleWeb2(
// console.log(JSON.stringify(web2interface.request))
// TODO Maybe we should also return derivedResult somehow
- return [true, JSON.stringify(web2interface.request)] // , derivedResult
-}
-
-// INFO Derive a valid DEMOS tx and GLS operation from a compatible request
-async function toMempool(
- instanceName: string,
- insert: boolean = true,
-): Promise<[string, Operation]> {
- // We should have a valid, attested request: lets handle it
- let derivedResults: [string, Operation]
- let web2Instance: Web2APIClass = Web2API(null, instanceName)
- let derivable: DerivableNative = {
- from: "web2module", // FIXME Implement this
- to: "web2", // FIXME Implement this more in details
- type: "web2",
- data: web2Instance.request,
- timestamp: Date.now(),
- fees: {
- networkFee: 0,
- rpcFee: 0,
- additionalFee: 0,
- }, // FIXME Implement this
- }
- // NOTE If all the attestations are valid we can create the transaction, insert it and give back the result
- // Deriving an operation and a tx from the web2 request
- derivedResults = await deriveMempoolOperation(derivable, insert)
- return derivedResults
-}
+ return [true, web2interface.request] // , derivedResult
+}
\ No newline at end of file
diff --git a/src/features/web2/routines/Web2Parser.ts b/src/features/web2/routines/Web2Parser.ts
index 89a739626..9614b763b 100644
--- a/src/features/web2/routines/Web2Parser.ts
+++ b/src/features/web2/routines/Web2Parser.ts
@@ -10,13 +10,9 @@ import sharedState from "src/utilities/sharedState"
import terminalkit from "terminal-kit"
import {
- IParam,
- IRawWeb2Request,
- IWeb2Attestation,
- IWeb2Payload,
- IWeb2Request,
- IWeb2Result,
-} from "../types/Web2Types"
+ IParam, IRawWeb2Request, IWeb2Attestation, IWeb2Payload, IWeb2Request, IWeb2Result,
+} from "@kynesyslabs/demosdk/types"
+
import post from "./operations/Web2Post"
import retrieve from "./operations/Web2Retrieve"
@@ -33,7 +29,7 @@ export default function Web2API(
command: string = null,
named: string = null,
sendSock: any = null,
- req: IWeb2Payload = null,
+ req: IWeb2Request = null,
): Web2APIClass {
if (command === "remove" && typeof sendSock === "string") {
const instanceNameToRemove = sendSock
@@ -58,7 +54,7 @@ export class Web2APIClass {
static getInstance(
named: string = null,
sendSock: any = null,
- req: IWeb2Payload = null,
+ req: IWeb2Request = null,
): Web2APIClass {
if (!named) {
named = String(Web2APIClass.progressive)
@@ -84,7 +80,6 @@ export class Web2APIClass {
}
// NOTE Storing the request here
- payload: IWeb2Payload = null
request: IWeb2Request = null
// NOTE Storing the sender's socket here
senderSocket: null
@@ -96,18 +91,18 @@ export class Web2APIClass {
// SECTION Control methods
// INFO Creating a named instance and bootstrapping it
- constructor(name: string, sendSock: any, payload: IWeb2Payload = null) {
+ constructor(name: string, sendSock: any, payload: IWeb2Request = null) {
this.name = name
this.senderSocket = sendSock
- if (!payload.message) {
- term.yellow.bold("[Web2API] No request attached. Is this right?")
+ console.log(payload)
+ if (!payload.raw) {
+ term.yellow.bold("[Web2API] No raw request attached. Is this right?")
//console.log(payload)
// TODO Specify this as a parameter that users can set
this.request.raw.minAttestations = 10
this.request.raw.stage.hop_number = 0
} else {
- this.payload = payload
- this.request = payload.message
+ this.request = payload
}
// REVIEW Should be ok anyway
// NOTE Not awaiting cause we need to let devs decide when to await with awaitQuorum
diff --git a/src/features/web2/routines/operations/Web2Post.ts b/src/features/web2/routines/operations/Web2Post.ts
index 12f0cebab..ac82abe7f 100644
--- a/src/features/web2/routines/operations/Web2Post.ts
+++ b/src/features/web2/routines/operations/Web2Post.ts
@@ -2,7 +2,7 @@ import axios from "axios"
import terminalkit from "terminal-kit"
// INFO This module is used to retrieve a resource from a raw request
-import { IParam, IRawWeb2Request, IWeb2Result } from "../../types/Web2Types"
+import { IParam, IRawWeb2Request, IWeb2Result } from "@kynesyslabs/demosdk/types"
const term = terminalkit.terminal
diff --git a/src/features/web2/routines/operations/Web2Retrieve.ts b/src/features/web2/routines/operations/Web2Retrieve.ts
index 7a41b9d0f..7269ad5d9 100644
--- a/src/features/web2/routines/operations/Web2Retrieve.ts
+++ b/src/features/web2/routines/operations/Web2Retrieve.ts
@@ -2,7 +2,7 @@ import axios from "axios"
import terminalkit from "terminal-kit"
// INFO This module is used to retrieve a resource from a raw request
-import { IParam, IRawWeb2Request, IWeb2Result } from "../../types/Web2Types"
+import { IParam, IRawWeb2Request, IWeb2Result } from "@kynesyslabs/demosdk/types"
const term = terminalkit.terminal
diff --git a/src/features/web2/routines/types/proxyManager.ts b/src/features/web2/routines/types/proxyManager.ts
index 0d234e5fa..c06a73420 100644
--- a/src/features/web2/routines/types/proxyManager.ts
+++ b/src/features/web2/routines/types/proxyManager.ts
@@ -1,12 +1,12 @@
// LINK https://stackoverflow.com/questions/46412934/forward-https-traffic-thru-nginx-without-ssl-certificate
// LINK https://github.com/http-party/node-http-proxy
+import fs from "fs"
// LINK https://github.com/http-party/node-http-proxy?tab=readme-ov-file#https---https
import httpProxy from "http-proxy"
-import fs from "fs"
import Cryptography from "src/libs/crypto/cryptography"
import Hashing from "src/libs/crypto/hashing"
-import sharedState from "src/utilities/sharedState"
import required from "src/utilities/required"
+import sharedState from "src/utilities/sharedState"
export interface IHTTPSCerts {
key: string
diff --git a/src/features/web2/types/Web2Types.ts b/src/features/web2/types/Web2Types.ts
index d3ab681a5..99aa0dcc1 100644
--- a/src/features/web2/types/Web2Types.ts
+++ b/src/features/web2/types/Web2Types.ts
@@ -1,68 +1,68 @@
-import forge from "node-forge"
+// import forge from "node-forge"
-// NOTE
-// In case of POST requests, the data is the only parameter thus 'name' is ignored
-// In case of GET requests, we can have multiple parameters, thus 'name' is used to identify them
-export interface IParam {
- name: string // Ignored in POST requests
- value: any
-}
+// // NOTE
+// // In case of POST requests, the data is the only parameter thus 'name' is ignored
+// // In case of GET requests, we can have multiple parameters, thus 'name' is used to identify them
+// export interface IParam {
+// name: string // Ignored in POST requests
+// value: any
+// }
-// INFO Properties of a typical request as the client would send it
-// NOTE This should be the thing we receive from the handler as a request
-// NOTE Basically is the comlink message
-export interface IWeb2Payload {
- type: "web2Request"
- message: IWeb2Request
- sender: any
- receiver: any
- timestamp: any
- data: any
- extra: any
-}
+// // INFO Properties of a typical request as the client would send it
+// // NOTE This should be the thing we receive from the handler as a request
+// // NOTE Basically is the comlink message
+// export interface IWeb2Payload {
+// type: "web2Request"
+// message: IWeb2Request
+// sender: any
+// receiver: any
+// timestamp: any
+// data: any
+// extra: any
+// }
-// INFO A web2 result interface
-export interface IWeb2Result {
- status: number
- statusText: string
- data: any
-}
+// // INFO A web2 result interface
+// export interface IWeb2Result {
+// status: number
+// statusText: string
+// data: any
+// }
-// INFO A complete web2 request
-export interface IWeb2Request {
- raw: IRawWeb2Request
- result: any
- attestations: {}
- hash: string
- signature?: forge.pki.ed25519.BinaryBuffer
-}
+// // INFO A complete web2 request
+// export interface IWeb2Request {
+// raw: IRawWeb2Request
+// result: any
+// attestations: {}
+// hash: string
+// signature?: forge.pki.ed25519.BinaryBuffer
+// }
-// INFO A request without any attestations or identity data
-export interface IRawWeb2Request {
- action: string
- parameters: IParam[]
- requestedParameters: [] | null
- method: "POST" | "GET" | "PUT" | "DELETE" | "PATCH"
- url: string
- headers: any
- minAttestations: number
- // Handling the various stages of an IWeb2Request
- stage: {
- // The one that will handle the response too
- origin: {
- identity: forge.pki.ed25519.BinaryBuffer
- connection_url: string
- }
- // Starting from 0, each attestation it is increased
- hop_number: number
- }
-}
+// // INFO A request without any attestations or identity data
+// export interface IRawWeb2Request {
+// action: string
+// parameters: IParam[]
+// requestedParameters: [] | null
+// method: "POST" | "GET" | "PUT" | "DELETE" | "PATCH"
+// url: string
+// headers: any
+// minAttestations: number
+// // Handling the various stages of an IWeb2Request
+// stage: {
+// // The one that will handle the response too
+// origin: {
+// identity: forge.pki.ed25519.BinaryBuffer
+// connection_url: string
+// }
+// // Starting from 0, each attestation it is increased
+// hop_number: number
+// }
+// }
-// ANCHOR Useful interfaces
-export interface IWeb2Attestation {
- hash: string
- timestamp: number
- identity: forge.pki.PublicKey
- signature: forge.pki.ed25519.BinaryBuffer
- valid: boolean
-}
+// // ANCHOR Useful interfaces
+// export interface IWeb2Attestation {
+// hash: string
+// timestamp: number
+// identity: forge.pki.PublicKey
+// signature: forge.pki.ed25519.BinaryBuffer
+// valid: boolean
+// }
diff --git a/src/features/experimental/zk/iZKP/test.ts b/src/features/zk/iZKP/test.ts
similarity index 100%
rename from src/features/experimental/zk/iZKP/test.ts
rename to src/features/zk/iZKP/test.ts
diff --git a/src/features/experimental/zk/iZKP/zk.ts b/src/features/zk/iZKP/zk.ts
similarity index 100%
rename from src/features/experimental/zk/iZKP/zk.ts
rename to src/features/zk/iZKP/zk.ts
diff --git a/src/features/experimental/zk/iZKP/zkPrimer.ts b/src/features/zk/iZKP/zkPrimer.ts
similarity index 100%
rename from src/features/experimental/zk/iZKP/zkPrimer.ts
rename to src/features/zk/iZKP/zkPrimer.ts
diff --git a/src/index.ts b/src/index.ts
index 1a3773913..3d05cb4be 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -12,7 +12,6 @@ KyneSys Labs: https://www.kynesys.xyz/
import "reflect-metadata"
-import * as bitcoin from "bitcoinjs-lib"
import * as dotenv from "dotenv"
import express from "express"
//import process from "node:process"
diff --git a/src/libs/blockchain/block.ts b/src/libs/blockchain/block.ts
index 478c2da08..42e59f7e4 100644
--- a/src/libs/blockchain/block.ts
+++ b/src/libs/blockchain/block.ts
@@ -11,7 +11,7 @@ KyneSys Labs: https://www.kynesys.xyz/
import { pki } from "node-forge"
-import BlockContent from "./types/blocks"
+import { BlockContent } from "@kynesyslabs/demosdk/types"
// NOTE Block class
export default class Block {
diff --git a/src/libs/blockchain/chain.ts b/src/libs/blockchain/chain.ts
index 70d3ce546..ebe4a3f5c 100644
--- a/src/libs/blockchain/chain.ts
+++ b/src/libs/blockchain/chain.ts
@@ -18,16 +18,15 @@ import { StatusProperties } from "src/model/entities/StatusProperties"
import { Transactions } from "src/model/entities/Transactions"
import { MoreThan } from "typeorm"
+import {
+ AddressInfo, Operation, StatusNative as StatusNativeType,
+ StatusProperties as StatusPropertiesType, TransactionContent,
+} from "@kynesyslabs/demosdk/types"
+
import Hashing from "../crypto/hashing"
import Block from "./block"
-import { Operation } from "./gls/gls"
import manageNative from "./routines/gls_routines/manageNative"
import Transaction from "./transaction"
-import AddressInfo from "./types/addressInfo"
-import RawTransaction from "./types/rawTransaction"
-import StatusNativeType from "./types/statusNative"
-import StatusPropertiesType from "./types/statusProperties"
-import { TransactionContent } from "./types/transactions"
export default class Chain {
private static instance: Chain
diff --git a/src/libs/blockchain/gls/gls.ts b/src/libs/blockchain/gls/gls.ts
index a02b0fd98..ebdc6dc39 100644
--- a/src/libs/blockchain/gls/gls.ts
+++ b/src/libs/blockchain/gls/gls.ts
@@ -52,35 +52,13 @@ import { Validators } from "src/model/entities/Validators"
import terminalkit from "terminal-kit"
import { LessThanOrEqual } from "typeorm"
+import { Operation, OperationRegistrySlot, OperationResult } from "@kynesyslabs/demosdk/types"
+
import Chain from "../chain"
import executeOperations, { Actor } from "../routines/executeOperations"
-import { TxFee } from "../types/transactions"
const term = terminalkit.terminal
-export interface OperationResult {
- success: boolean
- message: string
-}
-
-export interface Operation {
- operator: string
- actor: string
- params: {} // Documented in the chain itself
- hash: string
- nonce: number
- timestamp: number
- status: boolean | "pending"
- fees: TxFee
-}
-
-// WIP Making 'operations' registry more stable through db writing or file writing
-interface OperationRegistrySlot {
- operation: Operation
- status: boolean | "pending"
- result: OperationResult
- timestamp: number
-}
export class OperationsRegistry {
path: string = "data/operations.json"
diff --git a/src/libs/blockchain/gls/types/StateChange.ts b/src/libs/blockchain/gls/types/StateChange.ts
deleted file mode 100644
index 677ba26bb..000000000
--- a/src/libs/blockchain/gls/types/StateChange.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-import forge from "node-forge"
-
-interface TokenTransfer {
- address: string
- amount: number
-}
-
-interface NFTTransfer {
- address: string
- tokenId: string
- amount: number
-}
-
-export default interface StateChange {
- // Structure for state change
- sender: forge.pki.ed25519.BinaryBuffer
- receiver: forge.pki.ed25519.BinaryBuffer
- nativeAmount: number
- tx_hash: string
- token: TokenTransfer
- nft: NFTTransfer
-}
diff --git a/src/libs/blockchain/mempool.ts b/src/libs/blockchain/mempool.ts
index 398d08228..0b8eaf38f 100644
--- a/src/libs/blockchain/mempool.ts
+++ b/src/libs/blockchain/mempool.ts
@@ -21,6 +21,7 @@ import PeerManager from "../peer/PeerManager"
import Block from "./block"
// INFO Singleton Mempool class
import Transaction from "./transaction"
+import { ISignature } from "@kynesyslabs/demosdk/types"
export interface MempoolData {
number: number
@@ -91,7 +92,7 @@ export default class Mempool {
}
// INFO Writing a transaction to the mempool
- /* NOTE
+ /* NOTE
Here we should already have cryptographically valid data: adding the transaction to the mempool is the way
to flag it for verification and execution at consensus.
*/
@@ -99,7 +100,15 @@ export default class Mempool {
transaction: Transaction,
): Promise {
let mempool = await this.getMempool()
- console.log("adding transaction, found this mempool:")
+ console.log("adding transaction with hash " + transaction.hash + " to the mempool")
+
+ // FIXME Debug to remove
+ let is_coherent = Transaction.isCoherent(transaction)
+ if (!is_coherent) {
+ console.error("Transaction in mempool is not coherent")
+ process.exit(1)
+ }
+
//console.log(mempool)
mempool.transactions.push(transaction) // REVIEW What if it is empty?
@@ -211,7 +220,11 @@ export default class Mempool {
"[MEMPOOL VERIFICATION] Verifying the hash of the transaction: " +
tx_hash,
)
+ console.log(JSON.stringify(tx.content))
let calculated_hash = Hashing.sha256(JSON.stringify(tx.content))
+ console.log(
+ "[MEMPOOL VERIFICATION] Calculated hash: " + calculated_hash,
+ )
if (calculated_hash != tx_hash) {
console.log(
"[X] [MEMPOOL VERIFICATION] The hash of the transaction is invalid",
@@ -223,11 +236,20 @@ export default class Mempool {
)
// NOTE Verifying the signature against the verified hash using from as public key
console.log("[MEMPOOL VERIFICATION] Verifying the signature")
- let { signature } = tx
- console.log(
- "[MEMPOOL VERIFICATION] Signature: " +
- signature.data.toString("hex"),
- )
+
+ let signature = tx.signature // TODO Sometimes there is a nested type / data structure (see below)
+ // REVIEW Ugly patch for the above TODO
+ try {
+ let signature_data = signature.data as unknown as ISignature
+ if (!signature_data.data || !signature_data.type) {
+ throw new Error("[*] Signature fix failed successfully!")
+ }
+ console.log("[+] Signature fixed successfully!")
+ signature = signature_data
+ } catch (error) {
+ console.log("[+] [MEMPOOL VERIFICATION] Signature did not need to be fixed")
+ }
+
console.log(
"[MEMPOOL VERIFICATION] Signature: " +
signature.data.toString("hex"),
diff --git a/src/libs/blockchain/routines/calculateCurrentGas.ts b/src/libs/blockchain/routines/calculateCurrentGas.ts
index 1bb8290b2..a5a42b140 100644
--- a/src/libs/blockchain/routines/calculateCurrentGas.ts
+++ b/src/libs/blockchain/routines/calculateCurrentGas.ts
@@ -8,12 +8,46 @@ import Transaction from "../transaction"
// INFO Calculating transaction fees based on the size of the transaction and the status of the chain
async function calculateComposedGas(): Promise {
let lastblock_basegas: number = await GLS.getGLSLastBlockBaseGas()
- // TODO Add something to check congestion
- let composed_gas = lastblock_basegas + sharedState.getInstance().rpcFee
+ // Congestion check
+ let factor = await adaptGasToCongestion()
+ let adapted_gas = lastblock_basegas * factor
+ // Adding the fee for the rpc
+ // TODO Set limits for the fee
+ let composed_gas = adapted_gas + sharedState.getInstance().rpcFee
// TODO Add dApp fees
return composed_gas
}
+// REVIEW This function is used to adapt the gas to congestion. It increases the gas if needed
+async function adaptGasToCongestion(): Promise {
+ // TODO Get last block and previous last block timestamps
+ let lastBlockNumber = await Chain.getLastBlockNumber()
+ // Support for genesis block
+ if (lastBlockNumber == 0) {
+ return 0
+ }
+ let previousLastBlockNumber = lastBlockNumber - 1
+ // Getting blocks
+ let lastBlock = await Chain.getBlockByNumber(lastBlockNumber)
+ let previousLastBlock = await Chain.getBlockByNumber(
+ previousLastBlockNumber,
+ )
+ // Getting timestamps
+ let lastBlockTimestamp = lastBlock.content.timestamp
+ let previousLastBlockTimestamp = previousLastBlock.content.timestamp
+ // Calculating the difference between the two timestamps
+ let difference = lastBlockTimestamp - previousLastBlockTimestamp
+ // Get the block time from the chain status (in seconds, so we multiply by 1000)
+ let block_time = sharedState.getInstance().block_time * 1000
+ // Calculating the factor
+ let factor: number = 1
+ if (difference > block_time) {
+ let drift = difference - block_time
+ factor = 1 + (1.5 * drift / block_time) // REVIEW Is this correct?
+ }
+ return factor
+}
+
// REVIEW Why is this just a nested call
export default async function calculateCurrentGas(payload: any): Promise {
let payload_size = sizeOf(payload)
diff --git a/src/libs/blockchain/routines/executeTransaction.ts b/src/libs/blockchain/routines/executeNativeTransaction.ts
similarity index 95%
rename from src/libs/blockchain/routines/executeTransaction.ts
rename to src/libs/blockchain/routines/executeNativeTransaction.ts
index d8fb7bc68..ee1131474 100644
--- a/src/libs/blockchain/routines/executeTransaction.ts
+++ b/src/libs/blockchain/routines/executeNativeTransaction.ts
@@ -14,8 +14,9 @@ KyneSys Labs: https://www.kynesys.xyz/
consensus has confirmed the transaction in the block.
*/
-import GLS, { Operation } from "../gls/gls"
+import GLS from "../gls/gls"
import Transaction from "../transaction"
+import { Operation } from "./executeOperations"
/* NOTE
@@ -29,7 +30,7 @@ Each block, the nodes execute the Operation objects ordering them by their times
*/
// INFO Given a transaction, use GLS to see if it is executable and return a result
-export default async function executeTransaction(
+export default async function executeNativeTransaction(
transaction: Transaction,
): Promise<[boolean, string, Operation[]?]> {
let success: boolean = true
diff --git a/src/libs/blockchain/routines/executeOperations.ts b/src/libs/blockchain/routines/executeOperations.ts
index b2267918d..af12800f3 100644
--- a/src/libs/blockchain/routines/executeOperations.ts
+++ b/src/libs/blockchain/routines/executeOperations.ts
@@ -16,26 +16,27 @@ KyneSys Labs: https://www.kynesys.xyz/
executeSequence is called for each address to execute the operations contained.
*/
+import { Operation, OperationResult } from "@kynesyslabs/demosdk/types"
+
import Block from "../block"
-import { TxFee } from "../types/transactions"
import subOperations from "./subOperations"
-export interface OperationResult {
- success: boolean
- message: string
-}
-
-export interface Operation {
- // TODO Add parameters as a property
- operator: string
- actor: string
- params: any
- hash: string
- nonce: number
- timestamp: number
- status: boolean | "pending"
- fees: TxFee
-}
+// export interface OperationResult {
+// success: boolean
+// message: string
+// }
+
+// export interface Operation {
+// // TODO Add parameters as a property
+// operator: string
+// actor: string
+// params: any
+// hash: string
+// nonce: number
+// timestamp: number
+// status: boolean | "pending"
+// fees: TxFee
+// }
// NOTE The Actor object is designed to represent a single operator and the status of its operations
export interface Actor {
diff --git a/src/libs/blockchain/routines/gls_routines/assignWeb2.ts b/src/libs/blockchain/routines/gls_routines/assignWeb2.ts
index e151c89d8..6626246ce 100644
--- a/src/libs/blockchain/routines/gls_routines/assignWeb2.ts
+++ b/src/libs/blockchain/routines/gls_routines/assignWeb2.ts
@@ -1,9 +1,11 @@
+import { Operation, OperationResult } from "@kynesyslabs/demosdk/types"
+
import GLS from "../../gls/gls"
-import { Operation, OperationResult } from "../executeOperations"
export async function assignWeb2(
operation: Operation,
): Promise {
+ // @ts-expect-error
let { address, web2_hash } = operation.params
return await GLS.addToGLSWeb2(address, web2_hash)
}
diff --git a/src/libs/blockchain/routines/gls_routines/assignXM.ts b/src/libs/blockchain/routines/gls_routines/assignXM.ts
index 395932f9a..6a1b608dd 100644
--- a/src/libs/blockchain/routines/gls_routines/assignXM.ts
+++ b/src/libs/blockchain/routines/gls_routines/assignXM.ts
@@ -1,7 +1,9 @@
+import { Operation, OperationResult } from "@kynesyslabs/demosdk/types"
+
import GLS from "../../gls/gls"
-import { Operation, OperationResult } from "../executeOperations"
export async function assignXM(operation: Operation): Promise {
+ // @ts-expect-error
let { address, xm_hash } = operation.params
return await GLS.addToGLSXM(address, xm_hash)
}
diff --git a/src/libs/blockchain/routines/gls_routines/manageNative.ts b/src/libs/blockchain/routines/gls_routines/manageNative.ts
index aee84d99c..61c7a53fa 100644
--- a/src/libs/blockchain/routines/gls_routines/manageNative.ts
+++ b/src/libs/blockchain/routines/gls_routines/manageNative.ts
@@ -1,11 +1,11 @@
import Datasource from "src/model/datasource"
import { StatusNative } from "src/model/entities/StatusNative"
-import Block from "../../block"
-import Chain from "../../chain"
-import GLS from "../../gls/gls"
-import Genesis from "../../types/genesisTypes"
-import { Operation, OperationResult } from "../executeOperations"
+// import Block from "../../block"
+// import Chain from "../../chain"
+// import GLS from "../../gls/gls"
+// import Genesis from "../../types/genesisTypes"
+// import { OperationResult } from "../executeOperations"
// TODO Implement other properties of the GLS object to be fetched and set from the database
diff --git a/src/libs/blockchain/routines/subOperations.ts b/src/libs/blockchain/routines/subOperations.ts
index d5aab9407..7c4622d7f 100644
--- a/src/libs/blockchain/routines/subOperations.ts
+++ b/src/libs/blockchain/routines/subOperations.ts
@@ -1,11 +1,12 @@
import Datasource from "src/model/datasource"
import { Transactions } from "src/model/entities/Transactions"
+import { Operation, OperationResult } from "@kynesyslabs/demosdk/types"
+
import Block from "../block"
import Chain from "../chain"
import GLS from "../gls/gls"
import Genesis from "../types/genesisTypes"
-import { Operation, OperationResult } from "./executeOperations"
// NOTE Due to the modularity of the code, many routines will be stored in their own modules
// TODO Move everything there if possible
import glsRoutines from "./gls_routines"
diff --git a/src/libs/blockchain/routines/validateTransaction.ts b/src/libs/blockchain/routines/validateTransaction.ts
index 843f9bd7b..d83dd937b 100644
--- a/src/libs/blockchain/routines/validateTransaction.ts
+++ b/src/libs/blockchain/routines/validateTransaction.ts
@@ -9,100 +9,177 @@ KyneSys Labs: https://www.kynesys.xyz/
*/
-import { cryptography } from "src/libs/crypto"
+import { pki } from "node-forge"
+import Chain from "src/libs/blockchain/chain"
+import GLS from "src/libs/blockchain/gls/gls"
+import calculateCurrentGas from "src/libs/blockchain/routines/calculateCurrentGas"
+import executeNativeTransaction from "src/libs/blockchain/routines/executeNativeTransaction"
+import Transaction from "src/libs/blockchain/transaction"
+import Cryptography from "src/libs/crypto/cryptography"
+import Hashing from "src/libs/crypto/hashing"
+import sharedState from "src/utilities/sharedState"
import terminalkit from "terminal-kit"
-import GLS, { Operation } from "../gls/gls"
-import Transaction from "../transaction"
-import calculateCurrentGas from "./calculateCurrentGas"
-import executeTransaction from "./executeTransaction"
+import { Operation, ValidityData } from "@kynesyslabs/demosdk/types"
const term = terminalkit.terminal
-// INFO Cryptographically validate a transaction, calculate gas and see if the execution is valid
+// INFO Cryptographically validate a transaction and calculate gas
// REVIEW is it overkill to write an interface for the return value?
-export default async function validateTransaction(
- type: string,
- request: any, // Must contain a tx property being a Transaction object
-): Promise<[boolean, any]> {
- term.yellow("Validating transaction...\n")
-
+export async function confirmTransaction(
+ tx: Transaction, // Must contain a tx property being a Transaction object
+): Promise {
+ term.yellow("[Native Tx Validation] Validating transaction...\n")
+ // Getting the current block number
+ let reference_block = await Chain.getLastBlockNumber()
// Loading identity
- const id_ed25519 = await cryptography.load("./.demos_identity")
- let publicKey = Buffer.from(id_ed25519.publicKey.toString("hex"))
- let privateKey = Buffer.from(id_ed25519.privateKey.toString("hex"))
- // Ingesting a transaction so that we have all the methods we need
- let tx = new Transaction()
- tx.content = request.tx.content
- tx.signature = request.tx.signature
- // As usual converting buffers to nodejs buffers
- if (
- typeof tx.signature === "object" &&
- request.tx.signature.type === "Buffer"
- ) {
- tx.signature = Buffer.from(request.tx.signature) as any
- console.log("Normalized signature")
- }
+ const id_ed25519 = await Cryptography.load("./.demos_identity")
+ let publicKey = id_ed25519.publicKey
+ let privateKey = id_ed25519.privateKey
+ // REVIEW This should work just fine
console.log("Signature: ")
console.log(tx.signature)
- tx.hash = request.tx.hash
- tx.content.transaction_fee = request.tx.content.transaction_fee
- console.log("[TX RECEIVED] Examining:\n")
+ console.log("[Tx Validation] Examining it\n")
console.log(tx)
- // NOTE Charge the gas for the transaction
- let from = tx.content.from.toString("hex")
+ let validityData: ValidityData = {
+ data: {
+ valid: false,
+ reference_block: reference_block,
+ message: "",
+ gas_operation: null,
+ transaction: tx,
+ },
+ signature: null,
+ rpc_public_key: publicKey as pki.ed25519.BinaryBuffer,
+ }
+
+ /* NOTE Charge the gas for the transaction
+ This includes a check to see if the transaction gas can be paid
+ by the sender prior to the transaction execution part.
+ This way, we can avoid committing computations that will be reverted.
+ */
+ let from: string
+ try {
+ from = tx.content.from.toString("hex")
+ console.log(
+ "[Native Tx Validation] Calculating gas for: " + from + "\n",
+ )
+ } catch (e) {
+ term.red.bold(
+ "[Native Tx Validation] [FROM ERROR] No 'from' field found in the transaction\n",
+ )
+ validityData.data.message =
+ "[Native Tx Validation] [FROM ERROR] No 'from' field found in the transaction\n"
+ // Hash the validation data
+ let hash = Hashing.sha256(JSON.stringify(validityData.data))
+ // Sign the hash
+ validityData.signature = Cryptography.sign(hash, privateKey)
+ return validityData
+ }
let fromBalance = 0
try {
fromBalance = await GLS.getGLSNativeBalance(from)
} catch (e) {
term.red.bold(
- "[NATIVE TX] [BALANCE ERROR] No balance found for this address: " +
+ "[Native Tx Validation] [BALANCE ERROR] No balance found for this address: " +
from +
"\n",
)
- return [
- false,
- "[NATIVE TX] [BALANCE ERROR] No balance found for this address: " +
- from +
- "\n",
- ]
+ validityData.data.message =
+ "[Native Tx Validation] [BALANCE ERROR] No balance found for this address: " +
+ from +
+ "\n"
+ // Hash the validation data
+ let hash = Hashing.sha256(JSON.stringify(validityData.data))
+ // Sign the hash
+ validityData.signature = Cryptography.sign(hash, privateKey)
+ return validityData
}
// TODO Work on this method
- let gasAmount = await calculateCurrentGas(tx)
- if (fromBalance < gasAmount) {
- return [
- false,
- "[NATIVE TX] [BALANCE ERROR] Insufficient balance for gas; required: " +
- gasAmount +
+ let compositeFeeAmount = await calculateCurrentGas(tx)
+ // FIXME Overriding for testing
+ if (fromBalance < compositeFeeAmount && sharedState.getInstance().PROD) {
+ term.red.bold(
+ "[Native Tx Validation] [BALANCE ERROR] Insufficient balance for gas; required: " +
+ compositeFeeAmount + "; available: " + fromBalance + "\n" +
"\n",
- ]
+ )
+ validityData.data.message =
+ "[Native Tx Validation] [BALANCE ERROR] Insufficient balance for gas; required: " +
+ compositeFeeAmount + "; available: " + fromBalance + "\n" +
+ "\n"
+ // Hash the validation data
+ let hash = Hashing.sha256(JSON.stringify(validityData.data))
+ // Sign the hash
+ validityData.signature = Cryptography.sign(hash, privateKey)
+ return validityData
}
+
+ // TODO Move gas operation creator to a separate module
// NOTE Deducting the gas from the account and assigning the operation to be executed
// as child of this transaction
let gas_operation: Operation = {
operator: "pay_gas",
actor: from,
- params: { amount: gasAmount.toString() },
+ params: { amount: compositeFeeAmount.toString() },
hash: tx.hash,
nonce: tx.content.nonce,
timestamp: tx.content.timestamp,
status: "pending",
- fees: tx.content.transaction_fee,
+ fees: {
+ network_fee: 0,
+ rpc_fee: 0,
+ additional_fee: 0,
+ }, // This is the gas operation so it doesn't have additional fees
}
- console.log("[TX RECEIVED] Gas Operation derived\n")
+ console.log("[Native Tx Validation] Gas Operation derived\n")
//console.log(gas_operation)
+
// Verify tx validity
- let verified = Transaction.confirmTx(tx, privateKey, publicKey) // REVIEW Are the buffers ok?
+ let verified = Transaction.confirmTx(tx, privateKey as pki.ed25519.BinaryBuffer, publicKey as pki.ed25519.BinaryBuffer) // REVIEW Are the buffers ok?
if (!verified) {
- return [false, "Transaction not verified: " + tx.hash]
+ term.red.bold(
+ "[Native Tx Validation] [SIGNATURE ERROR] Transaction signature not verified\n",
+ )
+ validityData.data.message =
+ "[Native Tx Validation] [SIGNATURE ERROR] Transaction signature not verified\n"
+ // Hash the validation data
+ let hash = Hashing.sha256(JSON.stringify(validityData.data))
+ // Sign the hash
+ validityData.signature = Cryptography.sign(hash, privateKey)
+ return validityData
}
+ console.log("[Native Tx Validation] Transaction validity verified, compiling ValidityData\n")
+
+ // Now that we verified the transaction, we can return its validity data
+ // TODO Add the relevant info
+ validityData.data.valid = true
+ validityData.data.message =
+ "Transaction verified and ready to be executed\n"
+ validityData.data.gas_operation = gas_operation
+ // Hash the validation data
+ let hash = Hashing.sha256(JSON.stringify(validityData.data))
+ // Sign the hash
+ validityData.signature = Cryptography.sign(hash, privateKey)
+
+ console.log("[Native Tx Validation] Transaction validity data compiled\n")
+ return validityData
+}
+
+// TODO a verified transaction should be signed by the same rpc that verified it and should be only valid for the current consensus round
+export async function broadcastVerifiedNativeTransaction(
+ validityData: ValidityData,
+): Promise<[boolean, string, Operation[]?]> {
// REVIEW Execute or Revert the transaction
// NOTE executeTransaction returns an array of [success, message, operations]
// The operations are the Operation objects that are executed in the GLS after the consensus
// has confirmed the transaction in the block.
- let execution = await executeTransaction(tx)
+
+ let execution = await executeNativeTransaction(
+ validityData.data.transaction,
+ )
if (!execution[0]) {
return [false, "Execution failed: " + execution[1]]
}
@@ -111,7 +188,8 @@ export default async function validateTransaction(
// NOTE Now we can save the gas operation as the tx is set to be executed
// and the gas will be deducted anyway
- GLS.getInstance().operations.push(gas_operation)
+ console.log("[TX RECEIVED] Gas Operation added to the GLS\n")
+ GLS.getInstance().operations.push(validityData.data.gas_operation)
// Finally, we add all the derived operations to the GLS
for (let i = 0; i < execution[2].length; i++) {
@@ -120,5 +198,5 @@ export default async function validateTransaction(
GLS.getInstance().operations.push(execution[2][i])
console.log("[TX RECEIVED] Operation added to the GLS\n")
}
- return [true, tx]
+ return execution
}
diff --git a/src/libs/blockchain/transaction.ts b/src/libs/blockchain/transaction.ts
index c84f00090..a2f3e7fec 100644
--- a/src/libs/blockchain/transaction.ts
+++ b/src/libs/blockchain/transaction.ts
@@ -18,14 +18,16 @@ NOTE: The fee is locked by the node and released when the block itself is confir
*/
-import { pki } from "node-forge"
+import forge from "node-forge"
+
+import {
+ ISignature, RawTransaction, Transaction as ITransaction, TransactionContent,
+} from "@kynesyslabs/demosdk/types"
import Cryptography from "../crypto/cryptography"
import Hashing from "../crypto/hashing"
import { compressData, decompressData } from "../utils/demostdlib"
import Confirmation from "./types/confirmation"
-import RawTransaction from "./types/rawTransaction"
-import { TransactionContent } from "./types/transactions"
interface TransactionResponse {
status: string
@@ -34,14 +36,9 @@ interface TransactionResponse {
data: {}
}
-interface Signature {
- type: string
- data: pki.ed25519.BinaryBuffer
-}
-
-export default class Transaction {
+export default class Transaction implements ITransaction {
content: TransactionContent
- signature: Signature
+ signature: ISignature
hash: string
status: string
blockNumber: number
@@ -69,7 +66,7 @@ export default class Transaction {
// INFO Given a transaction, sign it with the private key of the sender
public static sign(
tx: Transaction,
- privateKey: pki.ed25519.BinaryBuffer,
+ privateKey: forge.pki.ed25519.BinaryBuffer,
): any[] {
// Check sanity of the structure of the tx object
if (!tx.content) {
@@ -119,9 +116,12 @@ export default class Transaction {
// INFO Compile a verification for a transaction and spit out the resulting tx
static confirmTx(
tx: Transaction,
- publicKey: pki.ed25519.BinaryBuffer,
- privateKey: pki.ed25519.BinaryBuffer,
+ publicKey: forge.pki.ed25519.BinaryBuffer,
+ privateKey: forge.pki.ed25519.BinaryBuffer,
) {
+ console.log(publicKey)
+ console.log(privateKey)
+ console.log(tx.signature)
let confirmed =
this.sanityCheck(tx) && this.isCoherent(tx) && this.structured(tx)
if (confirmed) {
@@ -140,19 +140,25 @@ export default class Transaction {
// INFO Checks the integrity of a transaction
public static sanityCheck(tx: Transaction) {
+ console.log("[sanityCheck] Checking the sanity of the tx with hash: " + tx.hash)
+ //let tx_content_hash = Hashing.sha256(JSON.stringify(tx.content))
let _result = Cryptography.verify(
- JSON.stringify(tx.content),
- tx.signature,
+ tx.hash,
+ tx.signature.data,
tx.content.from,
)
+ console.log("[sanityCheck] Sanity: " + _result)
return _result
}
// INFO Checking if the tx is coherent to the current state of the blockchain (and the txs pending before it)
public static isCoherent(tx: Transaction) {
let _result = true
+ console.log("[isCoherent] Checking the coherence of the tx with hash: " + tx.hash)
let _derived_hash = Hashing.sha256(JSON.stringify(tx.content))
- _result = _derived_hash !== tx.hash
+ console.log("[isCoherent] Derived hash: " + _derived_hash)
+ _result = (_derived_hash == tx.hash)
+ console.log("[isCoherent] Coherence: " + _result)
return _result
}
diff --git a/src/libs/blockchain/types/addressInfo.ts b/src/libs/blockchain/types/addressInfo.ts
deleted file mode 100644
index f7db74a48..000000000
--- a/src/libs/blockchain/types/addressInfo.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { StatusNative } from "src/model/entities/StatusNative"
-import { StatusProperties } from "src/model/entities/StatusProperties"
-
-export default interface AddressInfo {
- native: StatusNative | null
- properties: StatusProperties | null
-}
diff --git a/src/libs/blockchain/types/blocks.ts b/src/libs/blockchain/types/blocks.ts
deleted file mode 100644
index 193f9578b..000000000
--- a/src/libs/blockchain/types/blocks.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-import Transactions from "../transaction"
-
-export default interface BlockContent {
- ordered_transactions: string[]
- per_address_transactions: Map
- web2data: {} // TODO Add Web2 class
- previousHash: string
- timestamp: number
-}
diff --git a/src/libs/blockchain/types/confirmation.ts b/src/libs/blockchain/types/confirmation.ts
index fa1d7d8a1..4a8117d64 100644
--- a/src/libs/blockchain/types/confirmation.ts
+++ b/src/libs/blockchain/types/confirmation.ts
@@ -17,4 +17,12 @@ export default class Confirmation {
tx_hash_validated: string
}
signature: forge.pki.ed25519.BinaryBuffer
+
+ constructor() {
+ this.data = {
+ validator: null,
+ tx_hash_validated: null,
+ }
+ this.signature = null
+ }
}
diff --git a/src/libs/blockchain/types/genesisTypes.ts b/src/libs/blockchain/types/genesisTypes.ts
index bcb0b048a..d45a68771 100644
--- a/src/libs/blockchain/types/genesisTypes.ts
+++ b/src/libs/blockchain/types/genesisTypes.ts
@@ -1,5 +1,7 @@
import { Blocks } from "src/model/entities/Blocks"
+import { GenesisArtifact } from "@kynesyslabs/demosdk/types"
+
// INFO Defining the structure of a valid Genesis block
import Chain from "../chain"
@@ -9,48 +11,6 @@ import Chain from "../chain"
*
*/
-// SECTION Primitives
-
-export interface GenesisImmutableProperties {
- id: number
- name: string
- currency: string
-}
-
-export interface GenesisMutableProperties {
- minBlocksForValidationOnlineStatus: number
-}
-
-export interface GenesisArtifact {
- properties: GenesisImmutableProperties
- mutables: GenesisMutableProperties
- balances: [[address: string, amount: string]]
- timestamp: number
- previous_genesis_hash: string
- previous_block_hash: string
- signature: string
- hash: string
- number: number
-}
-
-// !SECTION Primitives
-
-// SECTION Components
-
-export interface StandardGenesis {
- properties: GenesisImmutableProperties
- mutables: GenesisMutableProperties
- balances: [[address: string, amount: string]]
- timestamp: number
-}
-
-export interface forkGenesis extends StandardGenesis {
- previous_genesis_hash: string
- previous_block_hash: string
-}
-
-// !SECTION Components
-
// INFO The Genesis class with its methods
export default class Genesis {
genesisBlock: Blocks // The genesis block
diff --git a/src/libs/blockchain/types/rawTransaction.ts b/src/libs/blockchain/types/rawTransaction.ts
deleted file mode 100644
index 2b14606b4..000000000
--- a/src/libs/blockchain/types/rawTransaction.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-export default interface RawTransaction {
- blockNumber: number
- signature: string
- status: string
- hash: string
- content: NonNullable
- type: string
- from: any
- to: any
- amount: number
- nonce: number
- timestamp: number
- networkFee: number
- rpcFee: number
- additionalFee: number
-}
diff --git a/src/libs/blockchain/types/statusNative.ts b/src/libs/blockchain/types/statusNative.ts
deleted file mode 100644
index 77774e6bd..000000000
--- a/src/libs/blockchain/types/statusNative.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export default interface statusNative {
- address: string
- balance: number
- nonce: number
- tx_list: string
-}
diff --git a/src/libs/blockchain/types/statusProperties.ts b/src/libs/blockchain/types/statusProperties.ts
deleted file mode 100644
index 0669183da..000000000
--- a/src/libs/blockchain/types/statusProperties.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export default interface statusNative {
- address: string
- tokens: string
- nfts: string
- xm: string
- web2: string
- other: string
-}
diff --git a/src/libs/blockchain/types/transactions.ts b/src/libs/blockchain/types/transactions.ts
deleted file mode 100644
index 97a845c99..000000000
--- a/src/libs/blockchain/types/transactions.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-import forge, { pki } from "node-forge"
-
-export interface TxFee {
- network_fee: number
- rpc_fee: number
- additional_fee: number
-}
-
-export interface fromSignature {
- type: string
- data: pki.ed25519.BinaryBuffer
-}
-
-export interface toSignature {
- type: string
- data: pki.ed25519.BinaryBuffer
-}
-
-export interface TransactionContent {
- type: string
- from: forge.pki.ed25519.BinaryBuffer | forge.pki.PublicKey | fromSignature
- to: forge.pki.ed25519.BinaryBuffer | forge.pki.PrivateKey | toSignature
- amount: number
- data: [string, string] // type as string and content in hex string
- nonce: number // Increments every time a transaction is sent from the same account
- timestamp: number // Is the registered unix timestamp when the transaction was sent the first time
- transaction_fee: TxFee // Is the signed message where the sender locks X tokens until the tx is confirmed
-}
diff --git a/src/libs/communications/comlink.ts b/src/libs/communications/comlink.ts
index afa8937f5..90e3cf17d 100644
--- a/src/libs/communications/comlink.ts
+++ b/src/libs/communications/comlink.ts
@@ -172,11 +172,14 @@ export default class ComLink {
// INFO Generic comlink validation function
async validateComlink() {
var _currentMessage = this.chain.current.currentMessage
+ console.log(_currentMessage)
console.log("[COMLINK VALIDATION 2] Stringifying...")
// Check if the current message hash matches the message
let stringifiedMessage = JSON.stringify(_currentMessage.bundle.content)
+ console.log(_currentMessage.bundle.hash)
console.log("[COMLINK VALIDATION 2] Hashing...")
let _derivedMessageHash = Hashing.sha256(stringifiedMessage)
+ console.log(_derivedMessageHash)
if (!(_derivedMessageHash === _currentMessage.bundle.hash)) {
//console.log(_currentMessage)
//console.log(stringifiedMessage)
diff --git a/src/libs/communications/comlinkUtils.ts b/src/libs/communications/comlinkUtils.ts
index d82abd77b..13079fc8f 100644
--- a/src/libs/communications/comlinkUtils.ts
+++ b/src/libs/communications/comlinkUtils.ts
@@ -9,11 +9,14 @@ KyneSys Labs: https://www.kynesys.xyz/
*/
+import { Socket } from "socket.io-client"
import sharedState from "src/utilities/sharedState"
import sizeOf from "src/utilities/sizeOf"
import { json } from "stream/consumers"
import terminalkit from "terminal-kit"
+import { DefaultEventsMap } from "@socket.io/component-emitter"
+
import ComLink from "./comlink"
const term = terminalkit.terminal
@@ -21,9 +24,9 @@ const term = terminalkit.terminal
export default class ComLinkUtils {
// INFO common comlink digestor
static async parseComlink(
- request,
- peerSocket,
- ): Promise<[ComLink, any] | boolean> {
+ request: ComLink,
+ peerSocket: Socket,
+ ): Promise {
// We need to check if the message request is valid (is a ComLink object)
term.yellow("[COMLINKUTILS] Received comlink\n")
// GIving the request the comlink methods
@@ -53,7 +56,7 @@ export default class ComLinkUtils {
"The request has a current message that is a: " +
typeof _comlink_request.chain.current.currentMessage,
)
- let type_of_call
+ let type_of_call: string
try {
type_of_call =
_comlink_request.chain.current.currentMessage.bundle.content
@@ -64,7 +67,7 @@ export default class ComLinkUtils {
status: "error",
message: e,
})
- return false
+ return null
}
if (!(type_of_call === "nodeCall")) {
let valid: any[]
@@ -79,7 +82,7 @@ export default class ComLinkUtils {
status: "error",
message: valid[1],
})
- return false
+ return null
}
} else {
term.green("[COMLINK] nodeCall received (no auth required)\n")
@@ -92,17 +95,16 @@ export default class ComLinkUtils {
muid: null,
message: "No muid specified",
})
- return false
+ return null
}
console.log("[COMLINK PARSING] MUID: " + request.muid)
// Taking the message part
- let content
- if (!(typeof request.chain.current.currentMessage === "object")) {
+ /*if (!(typeof request.chain.current.currentMessage === "object")) {
content = JSON.parse(request.chain.current.currentMessage).bundle
.content
- } else {
- content = request.chain.current.currentMessage.bundle.content
- }
+ } else { */
+ let content = request.chain.current.currentMessage.bundle.content
+ //}
if (!content) {
console.log(
"[COMLINK PARSING] Eww, no content specified. Erroring back.",
@@ -115,18 +117,18 @@ export default class ComLinkUtils {
}
console.log("[COMLINK PARSING] Content parsed")
//console.log(content)
- if (!content.message) {
+ if (!content.message && !content.data) {
console.log(
- "[COMLINK PARSING] No message specified. Erroring back.",
+ "[COMLINK PARSING] No message or data specified. Erroring back.",
//console.log(content),
)
peerSocket.emit("error", {
muid: request.muid,
message: "Eww...no message specified",
})
- return false
+ return null
}
console.log("[COMLINK PARSING] Message parsed")
- return [_comlink_request, content]
+ return _comlink_request
}
}
diff --git a/src/libs/communications/transmission.ts b/src/libs/communications/transmission.ts
index c08e20824..bf27d0c33 100644
--- a/src/libs/communications/transmission.ts
+++ b/src/libs/communications/transmission.ts
@@ -11,11 +11,12 @@ KyneSys Labs: https://www.kynesys.xyz/
import forge, { pki } from "node-forge"
+import { Bundle } from "@kynesyslabs/demosdk/types"
+
import Cryptography from "../crypto/cryptography"
// INFO This module exposes methods designed to have an unified way of communicate in DEMOS
import Hashing from "../crypto/hashing"
import { Peer } from "../peer"
-import { Bundle } from "./types/transmit"
export default class Transmission {
bundle: Bundle
diff --git a/src/libs/communications/types/transmit.ts b/src/libs/communications/types/transmit.ts
deleted file mode 100644
index 408ab7856..000000000
--- a/src/libs/communications/types/transmit.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-import forge, { pki } from "node-forge"
-
-export interface BundleContent {
- type: string
- message: string
- sender: any // TODO improve interface
- receiver: any // TODO improve interface
- timestamp: number
- data: Buffer
- extra: Buffer
-}
-
-export interface Bundle {
- content: BundleContent
- hash: string
- signature: any // TODO improve interface
-}
diff --git a/src/libs/crypto/cryptography.ts b/src/libs/crypto/cryptography.ts
index 33244f843..9a22d03b7 100644
--- a/src/libs/crypto/cryptography.ts
+++ b/src/libs/crypto/cryptography.ts
@@ -180,7 +180,11 @@ export default class Cryptography {
publicKey = Buffer.from(publicKey) // REVIEW Does not work in bun
}
- console.log("[*] Verifying the signature...")
+ console.log("[*] Verifying the signature of: " + signed + "\n")
+ console.log("[*] Using the signature: ")
+ console.log(signature)
+ console.log("[*] And the public key: ")
+ console.log(publicKey)
return forge.pki.ed25519.verify({
message: signed,
encoding: "utf8",
diff --git a/src/libs/network/routines/determineGasForOperation.ts b/src/libs/network/routines/determineGasForOperation.ts
index 05ebd3494..e6f0222a9 100644
--- a/src/libs/network/routines/determineGasForOperation.ts
+++ b/src/libs/network/routines/determineGasForOperation.ts
@@ -7,7 +7,7 @@ export default async function determineGasForOperation(
// Calculating byte size of the operation
let byte_size = demostdlib.payloadSize(operation)
// Getting the base gas from the chain status (GLS)
- let base_gas = await calculateCurrentGas()
+ let base_gas = await calculateCurrentGas(operation)
// INFO The gas required for an operation is the base gas multiplied by the byte size
let operation_gas = base_gas * byte_size
diff --git a/src/libs/network/routines/manageMessages.ts b/src/libs/network/routines/manageMessages.ts
new file mode 100644
index 000000000..dc726e884
--- /dev/null
+++ b/src/libs/network/routines/manageMessages.ts
@@ -0,0 +1,76 @@
+import { pki } from "node-forge"
+import { Socket } from "socket.io-client"
+// INFO This module manages gasless calls (such as rpc calls, consensus, etc.)
+import ComLink from "src/libs/communications/comlink"
+import { proofConsensusHandler } from "src/libs/consensus/routines/proofOfConsensus"
+// NOTE Terminal kit for useful logging
+import terminalkit from "terminal-kit"
+
+import { BundleContent } from "@kynesyslabs/demosdk/types"
+
+import ServerHandlers from "../serverHandlers"
+
+const term = terminalkit.terminal
+
+export default async function manageMessages(
+ content: BundleContent,
+ original_comlink: ComLink,
+ original_request: any,
+ id_ed25519: pki.KeyPair,
+ receiver: Socket,
+) {
+ let extra = null
+ let require_reply = false
+ let response = null
+
+ switch (content.type) {
+ case "proofOfConsensus":
+ ({ extra, require_reply, response } =
+ await proofConsensusHandler(content))
+
+ break
+ case "consensus":
+ console.log("[SERVER LISTENER HANDLER]: received consensus request")
+ console.log(
+ original_comlink.chain.current.currentMessage.bundle.content
+ .sender,
+ )
+ ;({ extra, require_reply, response } =
+ await ServerHandlers.handleConsensusRequest(
+ original_request,
+ content,
+ original_comlink.chain.current.currentMessage.bundle.content
+ .sender,
+ ))
+ break
+
+ case "messages":
+ ({ extra, require_reply, response } =
+ await ServerHandlers.handleMessage(content))
+ break
+
+ case "storage":
+ ({ extra, require_reply, response } =
+ await ServerHandlers.handleStorage())
+ break
+
+ case "mempool":
+ ({ extra, require_reply, response } =
+ await ServerHandlers.handleMempool(content))
+ break
+
+ case "nodeCall":
+ ({ extra, require_reply, response } =
+ await ServerHandlers.handleNodeAPI(
+ content,
+ receiver,
+ id_ed25519,
+ ))
+ break
+
+ default:
+ term.red(`[COMLINK INVALID] No known type: ${content.type}\n`)
+ break
+ }
+ return { extra, require_reply, response }
+}
diff --git a/src/libs/network/routines/nodecalls/getPeerlist.ts b/src/libs/network/routines/nodecalls/getPeerlist.ts
index 878f3ceb3..1c57f63e1 100644
--- a/src/libs/network/routines/nodecalls/getPeerlist.ts
+++ b/src/libs/network/routines/nodecalls/getPeerlist.ts
@@ -1,6 +1,7 @@
-import PeerManager from "../../../peer/PeerManager"
import { Peer } from "src/libs/peer"
+import PeerManager from "../../../peer/PeerManager"
+
export default async function getPeerlist(): Promise {
console.log("[SERVER] Received getPeerlist")
// Getting our current peerlist
diff --git a/src/libs/network/securityModule.ts b/src/libs/network/securityModule.ts
index 7dc017e30..0c97ab346 100644
--- a/src/libs/network/securityModule.ts
+++ b/src/libs/network/securityModule.ts
@@ -1,22 +1,5 @@
// TODO Implement this
-
-export interface ISecurityReport {
- state: boolean
- code: string
- message: string
-}
-
-interface SIResponseRegistry {
- prune_interval: number
-}
-
-interface SIComlink {
- rate_limit_size: number // How many comlinks can be sent in an interval? // TODO Make it configurable
- rate_limit_time: number // How many milliseconds is an interval? // TODO Make it configurable
- rate_limit_bin: number // The amount of comlinks sent in the last interval // TODO Make it configurable
- rate_limit_timestamp: number // The timestamp of the last interval
- checkRateLimits: Function
-}
+import { ISecurityReport } from "@kynesyslabs/demosdk/types"
export const modules = {
// SECTION Modules
diff --git a/src/libs/network/server.ts b/src/libs/network/server.ts
index 9d9643748..dcdac9291 100644
--- a/src/libs/network/server.ts
+++ b/src/libs/network/server.ts
@@ -10,11 +10,10 @@ KyneSys Labs: https://www.kynesys.xyz/
*/
import { Server as ServerType } from "socket.io"
+import ServerListeners from "src/libs/network/serverListeners"
+import { Peer } from "src/libs/peer"
import terminalkit from "terminal-kit"
-import { Peer } from "../peer"
-import ServerListeners from "./serverListeners"
-
const term = terminalkit.terminal
export default class Server {
diff --git a/src/libs/network/serverHandlers.ts b/src/libs/network/serverHandlers.ts
index f9d6cf50e..b97e3146a 100644
--- a/src/libs/network/serverHandlers.ts
+++ b/src/libs/network/serverHandlers.ts
@@ -15,28 +15,37 @@ import multichainDispatcher from "src/features/multichain/XMDispatcher"
import handleWeb2 from "src/features/web2/Web2Dispatcher"
import Chain from "src/libs/blockchain/chain"
import Mempool from "src/libs/blockchain/mempool"
+import {
+ broadcastVerifiedNativeTransaction, confirmTransaction,
+} from "src/libs/blockchain/routines/validateTransaction"
+import Transaction from "src/libs/blockchain/transaction"
+import deriveBlock from "src/libs/consensus/routines/deriveBlock"
+import Cryptography from "src/libs/crypto/cryptography"
+import Hashing from "src/libs/crypto/hashing"
+import eggs from "src/libs/network/routines/eggs"
+import getBlockByHash from "src/libs/network/routines/nodecalls/getBlockByHash"
+import getBlockByNumber from "src/libs/network/routines/nodecalls/getBlockByNumber"
+import getBlockHeaderByHash from "src/libs/network/routines/nodecalls/getBlockHeaderByHash"
+import getBlockHeaderByNumber from "src/libs/network/routines/nodecalls/getBlockHeaderByNumber"
+import getPeerlist from "src/libs/network/routines/nodecalls/getPeerlist"
+import getPreviousHashFromBlockHash from "src/libs/network/routines/nodecalls/getPreviousHashFromBlockHash"
+import getPreviousHashFromBlockNumber from "src/libs/network/routines/nodecalls/getPreviousHashFromBlockNumber"
+import { normalizeWebBuffers } from "src/libs/network/routines/normalizeWebBuffers"
+import Sessions from "src/libs/network/routines/sessionManager"
+import { BrowserRequest } from "src/libs/network/serverListeners"
import { Peer } from "src/libs/peer"
import { Blocks } from "src/model/entities/Blocks"
import sharedState from "src/utilities/sharedState"
// NOTE Terminal kit for useful logging
import terminalkit from "terminal-kit"
+import {
+ AddressInfo, ExecutionResult, IWeb2Payload, IWeb2Request, ValidityData,
+ XMScript,
+} from "@kynesyslabs/demosdk/types"
+
import GLS from "../blockchain/gls/gls"
-import validateTransaction from "../blockchain/routines/validateTransaction"
-import Transaction from "../blockchain/transaction"
-import AddressInfo from "../blockchain/types/addressInfo"
-import deriveBlock from "../consensus/routines/deriveBlock"
-import eggs from "./routines/eggs"
-import getPreviousHashFromBlockNumber from "./routines/nodecalls/getPreviousHashFromBlockNumber"
-import { normalizeWebBuffers } from "./routines/normalizeWebBuffers"
-import Sessions from "./routines/sessionManager"
-import { BrowserRequest } from "./serverListeners"
-import getPeerlist from "./routines/nodecalls/getPeerlist"
-import getPreviousHashFromBlockHash from "./routines/nodecalls/getPreviousHashFromBlockHash"
-import getBlockHeaderByHash from "./routines/nodecalls/getBlockHeaderByHash"
-import getBlockHeaderByNumber from "./routines/nodecalls/getBlockHeaderByNumber"
-import getBlockByNumber from "./routines/nodecalls/getBlockByNumber"
-import getBlockByHash from "./routines/nodecalls/getBlockByHash"
+import { NativePayload, StringifiedPayload, Web2Payload, XMPayload } from "node_modules/@kynesyslabs/demosdk/build/types/blockchain/Transaction"
let term = terminalkit.terminal
@@ -85,62 +94,183 @@ export default class ServerHandlers {
// !SECTION Login On Chain
// ANCHOR Comlinks
- static async handleTransaction(content: any): Promise {
- term.yellow("[handleTransactions] Handling a native DEMOS tx...\n")
- let require_reply = true // REVIEW Sure?
- let extra: string, response: boolean
+ static async handleValidateTransaction(
+ tx: Transaction,
+ ): Promise {
+ term.yellow("[handleTransactions] Handling a DEMOS tx...\n")
let fname = "[handleTransactions] "
term.yellow(fname + "Handling transaction...")
// Verify and execute the transaction
- let validatedTx: any[]
+ let validationData: ValidityData
try {
/* NOTE This workflow goeas as:
- * The tx is validated, an operation is created and pushed in the GLS
- * An operation for the gas is also pushed in the GLS
- * The tx is pushed in the mempool if applicable
+ * The transaction is validated
+ * A gas operation is created and is sent back alongside the validation data
+ * TODO Add signatures to validation data
+ * The validation data can be used by the client to effectively execute the tx
*/
//console.log(fname + "Validating transaction...")
- validatedTx = await validateTransaction(
- content.type,
- content.message,
- )
+ validationData = await confirmTransaction(tx)
//console.log(fname + "Fetching result...")
} catch (e) {
term.red.bold("[TX VALIDATION ERROR] 💀 : ")
term.red(e)
- validatedTx = [false, JSON.stringify(e)]
+ validationData = {
+ data: {
+ valid: false,
+ reference_block: null,
+ message:
+ "An error occurred while validating the transaction",
+ gas_operation: null,
+ transaction: null,
+ },
+ signature: null,
+ rpc_public_key: null,
+ }
+ // Signing and hashing the validation data
+ let hashedValidationData = Hashing.sha256(
+ JSON.stringify(validationData.data),
+ )
+ validationData.signature = Cryptography.sign(
+ hashedValidationData,
+ sharedState.getInstance().identity.ed25519.privateKey,
+ )
+ }
+
+ term.bold.white(fname + "Transaction handled.")
+ return validationData
+ }
+
+ // NOTE This method is used to handle the execution of a transaction
+ // TODO Better typing for content (must contain validity data, hashing and signature as shown below)
+ // TODO Either put this into a module or do something to make it more modular
+ static async handleExecuteTransaction(
+ validatedData: ValidityData,
+ senderSocket: any,
+ ): Promise {
+
+ let fname = "[handleExecuteTransaction] "
+ let result: ExecutionResult = {
+ success: true,
+ response: null,
+ extra: null,
+ require_reply: false,
}
+ // NOTE Content should contain validity data and our signature to proceed
+ // Integrity checks
+ let ourKey = sharedState.getInstance().identity.ed25519.publicKey
+ let hexOurKey = ourKey.toString("hex")
+ let dataKey = validatedData.rpc_public_key
+ let hexDataKey = Buffer.from(dataKey as Buffer).toString("hex")
+ let dataSignature = validatedData.signature
+ let queriedTx = validatedData.data.transaction
+ console.log("[SERVER] Received transaction for execution: " + queriedTx.hash)
+
+ // We need to have issued the validity data
+ if (hexDataKey !== hexOurKey) {
+ term.red.bold(fname + "Invalid validityData signature key (not us) 💀 : ")
+
+ result.success = false
+ result.response = false
+ result.extra = "Invalid signature key"
+ return result
- // Returning an appropriate response
- if (!validatedTx[0]) {
+ }
+ // Also the signature must be valid
+ let hashedData = Hashing.sha256(JSON.stringify(validatedData.data))
+ let signatureValid = Cryptography.verify(
+ hashedData,
+ dataSignature,
+ dataKey,
+ )
+ if (!signatureValid) {
+ term.red.bold(fname + "Invalid validityData signature 💀 : ")
+ result.success = false
+ result.response = false
+ result.extra = "Invalid signature"
+ return result
+ }
+ // Finally, the block number reference must be valid
+ let blockNumber = validatedData.data.reference_block
+ let lastBlockNumber = await Chain.getLastBlockNumber()
+ if (blockNumber != lastBlockNumber) {
+ term.red.bold(fname + "Invalid validityData block reference 💀 : ")
+ result.success = false
+ result.response = false
+ result.extra = "Invalid block reference"
+ return result
+ }
+ // REVIEW Is this useful at this point?
+ if (!validatedData.data.valid) {
// An invalid transaction won't even be added to the mempool
- term.yellow.bold(fname + "Invalid transaction 💀 : ")
- console.log(validatedTx[1])
- extra = "InvalidTransaction 💀: " + validatedTx[1]
- response = false
- } else {
- /* NOTE
+ term.yellow.bold(fname + "Invalid validityData 💀 : ")
+ console.log(validatedData.data.message)
+ result.success = false
+ result.response = false
+ result.extra = validatedData.data.message
+ return result
+ }
+
+ /* NOTE
We just processed the cryptographic validity of the transaction.
- We have no idea of its state validity and thus won't modify the GLS, but
- it can go into the mempool to be further processed if its cryptographically valid.
+ We will now try to execute it obtaining valid Operations.
*/
- term.green.bold(fname + "Valid transaction! ")
- //console.log(validatedTx[1])
- console.log(fname + "Adding transaction to mempool...")
- // Adding the valid tx to the mempool
- Mempool.addTransaction(validatedTx[1]) // Works by writing the registry
- extra = validatedTx[1].hash
- response = true
- //process.exit(0) /* TODO Eliminate this debug line */
+ term.green.bold(fname + "Valid validityData! \n")
+ // REVIEW Switch case for different types of transactions
+ let tx = validatedData.data.transaction
+ // Using a payload variable to be able to check types immediately
+ let payload: XMPayload | Web2Payload | NativePayload | StringifiedPayload
+ switch (tx.content.type) {
+ case "crosschainOperation":
+ case "multichainOperation":
+ payload = tx.content.data as XMPayload
+ console.log(
+ "[Included XM Chainscript]")
+ console.log(payload[1])
+ // TODO Better types on answers
+ var xm_result = await ServerHandlers.handleXMChainOperation(
+ payload[1] as XMScript,
+ )
+ // TODO Add result.success handling
+ result.response = xm_result
+ break
+ case "web2Request":
+ // TODO Better types on answers
+ payload = tx.content.data as Web2Payload
+ var web2_result = await ServerHandlers.handleWeb2Request(
+ payload[1] as IWeb2Request,
+ senderSocket,
+ )
+ // TODO Add result.success handling
+ result.response = web2_result
+ break
+ case "native":
+ // REVIEW This still works with the new tx system?
+ var native_result = await broadcastVerifiedNativeTransaction(validatedData)
+ // NOTE We add the Transaction to the mempool as it looks valid
+ if (native_result[0]) {
+ result.success = true
+ }
+ // REVIEW Check if this is ok with types
+ result.response = native_result
+ }
+ // Only if the transaction is valid we add it to the mempool
+ if (result.success) {
+ // REVIEW We add the transaction to the mempool
+ Mempool.addTransaction(queriedTx) // FIXME queriedTx hash mismatch with the expected hash? WHY
+ /* TODO for the above FIXME
+ * queriedTx should be identical to above but here is not coherent anymore
+ */
+ // TODO Check if Operation(s) are added to the GLS too
}
- // TODO Broadcast the tx to the other peers
+ // TODO Broadcast the tx to the other peers (or maybe not, consensus should take care of it)
// Response is then sent back automatically as a reply (with our validation)
- term.bold.white(fname + "Transaction handled.")
- return { extra, require_reply, response }
+ // Returning the state of the transaction including operations
+ return result
}
// INFO Handling XM Transaction
- static async handleXMChainOperation(xmscript: any): Promise {
+ static async handleXMChainOperation(xmscript: XMScript): Promise {
/* NOTE This workflow goeas as:
* The XM Operation is validated, executed and verified
* when applicable.
@@ -162,7 +292,7 @@ export default class ServerHandlers {
// INFO This method is used to allow signed data exchanges between peers and clients
static async handleXMChainSignedPayload(content: any): Promise {
- // TODO Probably to take it out
+ // TODO Probably to take out
}
static async handleXMChainStatus(): Promise {
@@ -178,8 +308,7 @@ export default class ServerHandlers {
// NOTE Theoretically, content should be IWeb2Request compliant
// LINK "../../features/web2/types/Web2Request";
static async handleWeb2Request(
- request: any,
- content: any,
+ content: IWeb2Request,
senderSocket: any,
): Promise {
/* NOTE This workflow goeas as:
@@ -193,9 +322,9 @@ export default class ServerHandlers {
console.log("[SERVER] Received web2Request")
//console.log(JSON.stringify(request))
- let extra: any,
+ let extra: string,
require_reply = false
- let response: unknown
+ let response: IWeb2Request
// We get our connection string
// const currentPeerString = Identity.getInstance().getConnectionString()
// NOTE Switched to the new class
@@ -208,10 +337,10 @@ export default class ServerHandlers {
// Managing the results
if (fullResponse[0]) {
- response = fullResponse[1]
+ response = fullResponse[1] as IWeb2Request
} else {
- response = "error"
- extra = fullResponse[1]
+ response = null
+ extra = fullResponse[1] as string
}
return { extra, require_reply, response }
}
@@ -338,11 +467,12 @@ export default class ServerHandlers {
//console.log(typeof data)
//console.log(JSON.stringify(content))
switch (content.message) {
- case "crosschain_operation":
+ // NOTE The following commented block of code is vestigial
+ /*case "crosschain_operation":
case "multichain_operation":
term.yellow.bold("[SERVER] Received crosschain_operation\n")
response = await ServerHandlers.handleXMChainOperation(content)
- break // REVIEW Here or in comlinks?
+ break // REVIEW Here or in comlinks? */
case "getPeerlist":
response = await getPeerlist()
break
diff --git a/src/libs/network/serverListeners.ts b/src/libs/network/serverListeners.ts
index 0c21c5534..db51282c1 100644
--- a/src/libs/network/serverListeners.ts
+++ b/src/libs/network/serverListeners.ts
@@ -1,27 +1,19 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
+import Transaction from "src/libs/blockchain/transaction"
import { comlinkUtils } from "src/libs/communications"
+import ComLink from "src/libs/communications/comlink"
import { cryptography } from "src/libs/crypto"
-import { demostdlib } from "../utils"
+import manageMessages from "src/libs/network/routines/manageMessages"
+import { ISession } from "src/libs/network/routines/sessionManager"
+import * as Security from "src/libs/network/securityModule"
/* eslint-disable no-extra-semi */
import ServerHandlers from "src/libs/network/serverHandlers"
import { Peer } from "src/libs/peer"
+import { demostdlib } from "src/libs/utils"
import sharedState from "src/utilities/sharedState"
// NOTE Terminal kit for useful logging
import terminalkit from "terminal-kit"
-import { proofConsensusHandler } from "../consensus/routines/proofOfConsensus"
-import { ISession } from "./routines/sessionManager"
-import * as Security from "./securityModule"
+import { BundleContent, ISecurityReport, ValidityData } from "@kynesyslabs/demosdk/types"
let term = terminalkit.terminal
@@ -75,169 +67,151 @@ export default class ServerListeners {
})
}
- // NOTE ComLinks are managed "centrally" here so apply securityModule stuff here
+ // REVIEW ComLinks are managed "centrally" here so apply securityModule stuff here
+ /* NOTE ComLink and Transactions
+ Once a comlink is received, we need to parse it and check if it is a transaction or a message.
+ Basically, a transaction needs gas calculation and validation, then it is sent back to the client that can
+ either execute it or discard it.
+ A message is just a message, so it is handled by its type.
+ */
async comlinkListener() {
this.peer.socket.on("comlink", async request => {
- term.yellow("[SERVER] Received comlink\n")
- const id_ed25519 = sharedState.getInstance().identity.ed25519
- const receiver = this.peer.socket
- let parsed_comlink: any // TODO Better typing
- // TODO This can be put into securityModule for consistency
- try {
- // Parsing comlink
- parsed_comlink = await comlinkUtils.parseComlink(
- request,
- this.peer.socket,
- )
- if (!parsed_comlink) {
- return // TODO Better error handling
- }
- } catch (error) {
- term.red(error)
- console.log("Returning")
- return // TODO Better error handling
- }
- let _comlink_request = parsed_comlink[0]
- console.log("[serverListeners] ComLink request received and parsed correctly")
- //console.log(_comlink_request)
- let content = parsed_comlink[1]
- console.log("[serverListeners] Received comlink content")
-
- let extra: any, require_reply: any, response: any
-
- //let content_data = content.data
- //console.log("[DATA INCLUDED IN THE COMLINK]")
- //console.log(content_data)
-
- // NOTE And here we have the real deal
- console.log("[serverListeners] content.type: " + content.type)
- switch (content.type) {
- // TODO We need to calculate the gas cost for operations that require it
- case "proofOfConsensus":
- ;({ extra, require_reply, response } =
- await proofConsensusHandler(content))
- break
-
- case "tx":
- term.yellow.bold("[SERVER] Received tx\n")
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleTransaction(content))
- break
-
- case "crosschain_operation":
- case "multichain_operation":
- console.log(
- "[Included XM Chainscript]" +
- JSON.stringify(content.message) +
- "\n\n",
- )
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleXMChainOperation(
- content.message,
- ))
- break
-
- case "web2Request":
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleWeb2Request(
- request,
- content,
- this.peer.socket,
- ))
- break
-
- case "consensus":
- console.log(
- "[SERVER LISTENER HANDLER]: received consensus request",
- )
- console.log(
- parsed_comlink[0].chain.current.currentMessage.bundle
- .content.sender,
- )
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleConsensusRequest(
- request,
- content,
- parsed_comlink[0].chain.current.currentMessage
- .bundle.content.sender,
- ))
- break
-
- case "messages":
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleMessage(content))
- break
-
- case "storage":
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleStorage())
- break
-
- case "mempool":
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleMempool(content))
- break
-
- case "nodeCall":
- ;({ extra, require_reply, response } =
- await ServerHandlers.handleNodeAPI(
- content,
- receiver,
- id_ed25519,
- ))
- break
-
- default:
- term.red(
- `[COMLINK INVALID] No known type: ${content.type}\n`,
- )
- break
- }
- //console.log("content.message: " + content.message)
- //console.log("content.message.action: " + content.message.action)
+ await this.manageComLink(request)
+ })
+ // TODO See in communications.js and find the best way to validate, check and digest the request
+ }
- // ANCHOR Reply logic
- // NOTE unless specified, we now send back the updated comlink as a response
- await demostdlib.reply(
- _comlink_request,
- response,
- require_reply,
- extra,
+ // This method is used to check the comlink before processing it
+ async preflightComLinkChecks(request: any): Promise {
+ term.yellow("[SERVER] Received comlink\n")
+ console.log(request)
+ const id_ed25519 = sharedState.getInstance().identity.ed25519
+ const receiver = this.peer.socket
+ let _comlink_request: ComLink
+ // TODO This can be put into securityModule for consistency
+ try {
+ // Parsing comlink
+ _comlink_request = await comlinkUtils.parseComlink(
+ request,
+ this.peer.socket,
)
+ if (!_comlink_request) {
+ return // TODO Better error handling
+ }
+ } catch (error) {
+ term.red(error)
+ console.log("Returning")
+ return // TODO Better error handling
+ }
+ // We can now extract the comlink and the content to be used in the handlers
+ console.log(
+ "[serverListeners] ComLink request received and parsed correctly",
+ )
+
+ let content: BundleContent =
+ _comlink_request.chain.current.currentMessage.bundle.content
+ return { _comlink_request, content, id_ed25519, receiver }
+ }
- // TODO & REVIEW Call security module for send limiting messages
- let secDisabled = false
- if (!secDisabled) {
- let ts = new Date().getTime()
- let securityInterceptor: Security.ISecurityReport =
- await Security.modules.communications.comlink.checkRateLimits(
- ts,
+ // Here, we manage the comlink and its content
+ async manageComLink(request: any) {
+ // Security and sanity checks
+ let { _comlink_request, content, id_ed25519, receiver } =
+ await this.preflightComLinkChecks(request)
+ //console.log(_comlink_request)
+ // NOTE Now we have a valid ComLink and we can work with it
+ console.log("[serverListeners] Received comlink content")
+
+ let extra: any, require_reply: any, response: any
+
+ console.log("[serverListeners] content.type: " + content.type)
+ console.log("[serverListeners] content.extra: " + content.extra)
+
+ // REVIEW We use the 'extra' field to see if it is a confirmTx request (prior to execution)
+ // or an broadcastTx request (to execute the transaction after gas cost is calculated).
+ // Transactions are either gas consuming or not, so we need to check if the transaction
+ // needs to be validated,executed or treated as a message.
+ switch (content.extra) {
+ // ANCHOR Gas consuming transactions
+ // Validating a tx means that we calculate gas and check if the transaction is valid
+ // Then we send the validation data to the client that can use it to execute the tx
+ case "confirmTx":
+ term.yellow.bold("[SERVER] Received confirmTx\n")
+ var validityData =
+ await ServerHandlers.handleValidateTransaction(
+ content.data as Transaction,
)
- if (!securityInterceptor.state) {
- switch (securityInterceptor.code) {
- case "429":
- break
-
- default:
- term.red.bold(
- "[COMLINK] [SECURITY INTERCEPTOR] Unknown error: " +
- securityInterceptor.code.toString(),
- )
- term.red.bold(
- "[COMLINK] [SECURITY INTERCEPTOR] Reported:",
- )
- console.log(securityInterceptor.message)
- break
- }
+ response = validityData
+ extra = ""
+ require_reply = false // REVIEW Should we require a reply here?
+
+ // console.log(response)
+
+ break
+ // Executing a tx means that we execute the transaction and send back the result
+ // to the client. We first need to check if the tx is actually valid.
+ case "broadcastTx":
+ term.yellow.bold("[SERVER] Received broadcastTx\n")
+ // REVIEW This method needs to actually verify if the transaction is valid
+ var result = await ServerHandlers.handleExecuteTransaction(
+ content.data as ValidityData,
+ this.peer.socket,
+ )
+ // Destructuring the result to get the extra, require_reply and response
+ ;({ extra, require_reply, response } = result)
+ break
+ // ANCHOR Messages
+ // All the rest of the comlink types do not require extra validation or gas calculation
+ // They are treated as messages and are handled by their types themselves
+ // For readability, we call an external function to manage the messages
+ default:
+ ;({ extra, require_reply, response } = await manageMessages(
+ content,
+ _comlink_request,
+ request,
+ id_ed25519,
+ receiver,
+ ))
+ break
+ }
+ //console.log("content.message: " + content.message)
+ //console.log("content.message.action: " + content.message.action)
+
+ // ANCHOR Reply logic
+ // NOTE unless specified, we now send back the updated comlink as a response
+ await demostdlib.reply(_comlink_request, response, require_reply, extra)
+
+ // TODO & REVIEW Call security module for send limiting messages
+ let secDisabled = false
+ if (!secDisabled) {
+ let ts = new Date().getTime()
+ let securityInterceptor: ISecurityReport =
+ await Security.modules.communications.comlink.checkRateLimits(
+ ts,
+ )
+ if (!securityInterceptor.state) {
+ switch (securityInterceptor.code) {
+ case "429":
+ break
+
+ default:
+ term.red.bold(
+ "[COMLINK] [SECURITY INTERCEPTOR] Unknown error: " +
+ securityInterceptor.code.toString(),
+ )
+ term.red.bold(
+ "[COMLINK] [SECURITY INTERCEPTOR] Reported:",
+ )
+ console.log(securityInterceptor.message)
+ break
}
}
+ }
- // Sending back the response
- console.log("[SERVER] Sending back comlink")
- //console.log(JSON.stringify(_comlink_request))
- receiver.emit("comlink_reply", _comlink_request) // reply is managed in the common listeners
- })
- // TODO See in communications.js and find the best way to validate, check and digest the request
+ // Sending back the response
+ console.log("[SERVER] Sending back comlink")
+ //console.log(JSON.stringify(_comlink_request))
+ receiver.emit("comlink_reply", _comlink_request) // reply is managed in the common listeners
}
// INFO Register or update a peer identity and connection string
diff --git a/src/libs/peer/Peer.ts b/src/libs/peer/Peer.ts
index 05f233c5a..32b184c75 100644
--- a/src/libs/peer/Peer.ts
+++ b/src/libs/peer/Peer.ts
@@ -9,7 +9,7 @@ KyneSys Labs: https://www.kynesys.xyz/
*/
-import type { IPeerConfig } from "./types/Peer"
+import type { IPeerConfig } from "@kynesyslabs/demosdk/types"
import forge from "node-forge"
import { Socket } from "socket.io-client"
diff --git a/src/libs/peer/types/Peer.ts b/src/libs/peer/types/Peer.ts
deleted file mode 100644
index 3c33ef812..000000000
--- a/src/libs/peer/types/Peer.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/* LICENSE
-
-© 2023 by KyneSys Labs, licensed under CC BY-NC-ND 4.0
-
-Full license text: https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode
-Human readable license: https://creativecommons.org/licenses/by-nc-nd/4.0/
-
-KyneSys Labs: https://www.kynesys.xyz/
-
-*/
-
-import { Socket } from "socket.io-client"
-
-export interface IPeerConfig {
- connectionString?: string
- socket?: Socket
- identity?: string
-}
diff --git a/src/utilities/selfPeer.ts b/src/utilities/selfPeer.ts
new file mode 100644
index 000000000..98b6aace1
--- /dev/null
+++ b/src/utilities/selfPeer.ts
@@ -0,0 +1,16 @@
+import * as fs from "fs"
+
+// NOTE This method is mainly used by index.ts when we generate a new identity and we have no valid peers
+// (aka talking to ourselves)
+export default async function selfPeer() {
+ let public_key_file = "publickey"
+ let public_key = fs.readFileSync(public_key_file, "utf8")
+ let basic_peer_script = `
+ [
+ "http://127.0.0.1>53550>` + public_key + `"
+ ]
+ `
+ let basic_peer_script_file = "demos_peers"
+ fs.rmSync(basic_peer_script_file)
+ fs.writeFileSync(basic_peer_script_file, basic_peer_script)
+}
diff --git a/src/utilities/sharedState.ts b/src/utilities/sharedState.ts
index 297af173d..1e30c255f 100644
--- a/src/utilities/sharedState.ts
+++ b/src/utilities/sharedState.ts
@@ -13,6 +13,8 @@ dotenv.config({ path: "../../.commons" })
export default class sharedState {
private static instance: sharedState
+ block_time: number = 10 // TODO Get it from the genesis (or see Consensus module)
+
currentTimestamp: number = 0
lastTimestamp: number = 0
diff --git a/tests/chains/_template.test.ts b/tests/chains/_template.test.ts
deleted file mode 100644
index fbc8cd735..000000000
--- a/tests/chains/_template.test.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-// INFO: Duplicate and rename this file to add a new XM test
-// import { chainProviders } from "sdk/localsdk/multichain/configs/chainProviders"
-// import { CHAIN } from "sdk/localsdk/multichain"
-
-describe(" CHAIN TESTS", () => {
- // TODO: Set correct instance type
- let instance: any
-
- beforeAll(async () => {
- // INFO: Connect the RPC and Wallet here
- // instance = await CHAIN.create(chainProviders.ibc.testnet);
- await instance.connect()
- await instance.connectWallet("")
-
- expect(instance.connected).toBe(true)
- })
-
- afterAll(async () => {
- // INFO: Disconnect from the RPC here
- // NOTE: Not needed for non web socket RPCs
- await instance.disconnect()
- })
-
- test("preparePay returns a signed tx", async () => {
- // TODO: Test code here
- })
- test("A tx is signed with the ledger nonce", async () => {
- // TODO: Test code here
- })
-
- test("Transactions are signed with increasing nonces", async () => {
- // TODO: Test code here
- })
- test("Transactions are signed in order of appearance", async () => {
- // TODO: Test code here
- })
-})
diff --git a/tests/chains/ibc.test.ts b/tests/chains/ibc.test.ts
deleted file mode 100644
index 1e6ee2cbd..000000000
--- a/tests/chains/ibc.test.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { defaultRegistryTypes, GasPrice } from "@cosmjs/stargate"
-import { decodeTxRaw, Registry } from "@cosmjs/proto-signing"
-
-import ibcProviders from "sdk/localsdk/multichain/configs/ibcProviders"
-import { IBC } from "sdk/localsdk/multichain"
-import { getSampleTranfers, verifyNumberOrder } from "../utils"
-import { wallets } from "../utils/wallets"
-
-describe("IBC CHAIN TESTS", () => {
- let instance: IBC
- const chain_prefix = "cosmos"
- const token_denom = "uatom"
- const payment_options = { denom: token_denom }
-
- beforeAll(async () => {
- instance = await IBC.create(ibcProviders.cosmos.testnet)
- await instance.connectWallet(wallets.ibc.wallet, {
- prefix: chain_prefix,
- gasPrice: "0.012uatom",
- })
-
- expect(instance.connected).toBe(true)
- })
-
- test("preparePay returns a signed tx", async () => {
- const address = instance.getAddress()
- const tx_bytes = await instance.pay(
- address,
- "1",
- payment_options,
- )
-
- // INFO: Decode the bytes to get the raw tx
- // LINK: https://cosmos.github.io/cosmjs/latest/proto-signing/modules.html#decodeTxRaw
- // Ctrl + click decodeTxRaw to see the decoded raw Tx interface
- const raw_tx = decodeTxRaw(tx_bytes)
- expect(raw_tx.signatures.length == 1).toBe(true)
- })
-
- test("A tx is signed with the ledger nonce", async () => {
- const address = instance.getAddress()
-
- // INFO: Get the current ledger sequence
- const ledger_sequence = (await instance.provider.getAccount(address))
- ?.sequence
-
- // INFO: Sign and decode the tx
- const tx_bytes = await instance.pay(
- address,
- "1",
- payment_options,
- )
- const raw_tx = decodeTxRaw(tx_bytes)
-
- // INFO: Compare the sequences
- const tx_sequence = Number(raw_tx.authInfo.signerInfos[0].sequence)
- expect(tx_sequence).toEqual(ledger_sequence)
- })
-
- test("Transactions are signed with increasing nonces", async () => {
- const address = instance.getAddress()
- const payments = getSampleTranfers(address)
- const signed_txs = await instance.multiPay(payments, payment_options)
-
- // INFO: Get a list of objects containing the sequences
- const signer_infos = signed_txs.map(tx_bytes => {
- const tx = decodeTxRaw(tx_bytes)
- return tx.authInfo.signerInfos[0]
- })
-
- const is_sorted = verifyNumberOrder(signer_infos, "sequence")
- expect(is_sorted).toBe(true)
- })
-
- test("Transactions are signed in order of appearance", async () => {
- const address = instance.getAddress()
- const payments = getSampleTranfers(address)
- const signed_txs = await instance.multiPay(payments, payment_options)
-
- const amounts = signed_txs.map(tx_bytes => {
- const tx = decodeTxRaw(tx_bytes)
-
- // INFO: Decode the message to get the amount
- // LINK: https://cosmos.github.io/cosmjs/latest/proto-signing/classes/Registry.html
- const registry = new Registry(defaultRegistryTypes)
- const message = registry.decode(tx.body.messages[0])
- return message["amount"][0]
- })
-
- const is_sorted = verifyNumberOrder(amounts, "amount")
- expect(is_sorted).toBe(true)
- })
-})
diff --git a/tests/chains/index.ts b/tests/chains/index.ts
deleted file mode 100644
index 815cbd053..000000000
--- a/tests/chains/index.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-describe("GENERIC CHAIN TESTS", () => {
- test("Hi", () => {
- expect(1).toBe(1)
- })
-
- test.todo("Chain has a valid name")
- test.todo("Chain connects to the RPC")
- test.todo("On connect failure, .connected is false")
- test.todo("On disconnect, provider is reset")
-})
\ No newline at end of file
diff --git a/tests/utils/index.ts b/tests/utils/index.ts
deleted file mode 100644
index 330750bff..000000000
--- a/tests/utils/index.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { IPayOptions } from "sdk/localsdk/multichain/types/transfers";
-
-/**
- * Verify that keys in a list of items appear in ascending order
- * @param items The list of items
- * @param key The key to compare
- * @returns True if the list is sorted, false otherwise
- */
-export function verifyNumberOrder(items: any[], key: string) {
- // INFO: Verify that each number is greater than the previous one
- return items.every((num, i) => {
- const current = Number(num[key]);
- const prev = Number(items[i - 1]?.[key]);
- return i === 0 || current > prev;
- });
-}
-
-/**
- * Generate a list of transaction params for testing
- * @param address The address to send the transactions to
- * @returns A list of transaction params ready to be passed to preparePays
- */
-export function getSampleTranfers(address: string, length: number = 10): IPayOptions[] {
- return Array.from({ length }, (_, i) => {
- return {
- address,
- // INFO: Amount is passed to preparePays as a string
- amount: `${i + 1}`
- };
- });
-}
diff --git a/tests/utils/wallets.ts b/tests/utils/wallets.ts
deleted file mode 100644
index f06349df0..000000000
--- a/tests/utils/wallets.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-// INFO: These are testnet wallets for each chain
-export const wallets = {
- egld: {
- wallet: JSON.stringify({
- version: 4,
- id: 'c98cefdb-5ea0-404b-96b5-54391fe7cd68',
- kind: 'mnemonic',
- crypto: {
- ciphertext:
- '54067052dd60c0fc270329c5e3facfd0d16a5fe618a0ade72eb5797ca529b7b8808439d7d595b1c052e9684681efcb846e373b7f79fa2b6364618bffbc4afe50f20a510f00f7971e05516353ba225fcfe0a5d04d1995fc9e02ab242d60df838acfe59b5140d89adb00f88c121ad1a3cac3809d06bd025fad30fb3035374e8a80b20fb72d777b7b59182c75203f73b49265d8558b003814ea68dced49113d406216',
- cipherparams: { iv: '01710d9d92c8b45f2e02079ff3e2b58d' },
- cipher: 'aes-128-ctr',
- kdf: 'scrypt',
- kdfparams: {
- dklen: 32,
- salt: '10f68326bdd2755058dda807f9b3347e01b037ae65b439f0b0df1744fe4ff9d2',
- n: 4096,
- r: 8,
- p: 1
- },
- mac: 'dd63b26356692e206f25b7a034babe5a00705bdc7e3acaa2993733f930052489'
- }
- }),
- password: 'e9r#PNK7pB#?f39A'
- },
- xrpl: {
- wallet: 'sEdToEm3WLYXRmhvs62pd1BuLfxF9WG'
- },
- evm: {
- // INFO: Sepolia testnet wallet 👇
- wallet: 'e0a00e307c21850cde41b18bae307a492c471b463b60ce5b631fdb80503b23f7'
- },
- ibc: {
- // INFO: Cosmos chain Id: "theta-testnet-001"
- wallet: 'stumble august fancy affair device feed cruise brown dream section fit lift'
- }
-};
-
-export const addresses = {
- // Alt account
- // INFO: XRPL doesn't accept transfers to own account
- xrpl: 'rE57JVcMmoNq6yNbBbiJrCY9sMr4HWiqwf'
-};
diff --git a/tsconfig.json b/tsconfig.json
index 78bc63c72..cd1fef0c5 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,29 +1,31 @@
{
- "compilerOptions": {
- "target": "ESNext",
- "module": "ESNext",
- "esModuleInterop": true,
- "moduleResolution": "node",
- "declaration": true,
- "removeComments": true,
- "emitDecoratorMetadata": true,
- "experimentalDecorators": true,
- "allowSyntheticDefaultImports": true,
- "sourceMap": true,
- "sourceRoot": "/",
- "inlineSources": true,
- "outDir": "./dist",
- "baseUrl": "./",
- "types": ["jest", "node"],
- "incremental": true,
- "strictNullChecks": false,
- "noImplicitAny": false,
- "strictBindCallApply": false,
-
- /* Linting */
- "skipLibCheck": true,
- "strict": true,
- "noFallthroughCasesInSwitch": true,
- "forceConsistentCasingInFileNames": true
- }
-}
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "esModuleInterop": true,
+ "moduleResolution": "Bundler",
+ "declaration": true,
+ "removeComments": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "allowSyntheticDefaultImports": true,
+ "sourceMap": true,
+ "sourceRoot": "/",
+ "inlineSources": true,
+ "outDir": "./dist",
+ "baseUrl": "./",
+ "types": [
+ "jest",
+ "node"
+ ],
+ "incremental": true,
+ "strictNullChecks": false,
+ "noImplicitAny": false,
+ "strictBindCallApply": false,
+ /* Linting */
+ "skipLibCheck": true,
+ "strict": true,
+ "noFallthroughCasesInSwitch": true,
+ "forceConsistentCasingInFileNames": true
+ }
+}
\ No newline at end of file