Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add sdk node example #139

Merged
merged 6 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]
### Added
- [\#139](https://github.com/Manta-Network/sdk/pull/139) Add sdk node example
- [\#133](https://github.com/Manta-Network/sdk/pull/133) Restore pruning and add UTXO consolidation && add Api `estimateTransferPostsCount` && add Api `consolidateTransferSend`
- [\#131](https://github.com/Manta-Network/sdk/pull/131) Add synced ledger count api
- [\#128](https://github.com/Manta-Network/sdk/pull/128) Add total ledger count
Expand Down
3 changes: 1 addition & 2 deletions manta-js/examples/sdk-example/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
/node_modules
.DS_Store
index.js
.DS_Store
3 changes: 3 additions & 0 deletions manta-js/examples/sdk-node-example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/db
/node_modules
.DS_Store
1 change: 1 addition & 0 deletions manta-js/examples/sdk-node-example/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
9 changes: 9 additions & 0 deletions manta-js/examples/sdk-node-example/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"printWidth": 80,
"singleQuote": true,
"trailingComma": "all",
"proseWrap": "never",
"semi": false,
"overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
"importOrderSeparation": true
}
9 changes: 9 additions & 0 deletions manta-js/examples/sdk-node-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Manta SDK Node Example

## How to run this example


``` shell
yarn
yarn start # Will rebuild the sdk and run node code
```
19 changes: 19 additions & 0 deletions manta-js/examples/sdk-node-example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "sdk-node-example",
"version": "1.0.0",
"main": "index.js",
"private": true,
"scripts": {
"start_node": "node ./src/index.js",
"start": "yarn --cwd ../../package && yarn --cwd ../../package build-node && yarn add file:../../package && yarn start_node"
},
"dependencies": {
"bn.js": "^5.2.0",
"buffer": "^6.0.3",
"classic-level": "^1.3.0",
"manta-extension-sdk": "file:../../package"
},
"engines": {
"node": ">=18"
}
}
199 changes: 199 additions & 0 deletions manta-js/examples/sdk-node-example/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
const BN = require('bn.js')

const { Keyring } = require('@polkadot/keyring')
const { cryptoWaitReady } = require('@polkadot/util-crypto')
const { ClassicLevel } = require('classic-level')

const { BaseWallet, MantaPayWallet } = require('manta-extension-sdk/node')

const { saveStorageState, getStorageState, getDbPath } = require('./utils')

const loggingEnabled = true
const currentNetwork = 'Calamari'
const endPoint = ['wss://calamari.systems']
const maxTransactionCount = 4

let storageStateDb = null

const getPair = (publicAccountSeedPhrase) => {
const keyring = new Keyring({ type: 'sr25519' })
const pair = keyring.createFromUri(publicAccountSeedPhrase)
return pair
}

const sendTransaction = async (pair, transaction) => {
for (let i = 0; i < transaction.txs.length; i += 1) {
await transaction.txs[i].signAndSend(pair, { nonce: -1 })
}
}

const getBaseWallet = async () => {
const baseWallet = await BaseWallet.init({
apiEndpoint: endPoint,
loggingEnabled,
provingFilePath:
'https://media.githubusercontent.com/media/Manta-Network/manta-rs/main/manta-parameters/data/pay/proving',
parametersFilePath:
'https://raw.githubusercontent.com/Manta-Network/manta-rs/main/manta-parameters/data/pay/parameters',
async saveStorageStateToLocal(palletName, network, data) {
const result = await saveStorageState(storageStateDb, data)
return result
},
async getStorageStateFromLocal(palletName, network) {
const result = await getStorageState(storageStateDb)
return result
},
})
return baseWallet
}

const getMantaPayWallet = async (baseWallet, zkAccountSeedPhrase) => {
const mantaPayWallet = MantaPayWallet.init(currentNetwork, baseWallet)

const dbPath = getDbPath(
mantaPayWallet.palletName,
currentNetwork,
getPair(zkAccountSeedPhrase).address,
)
// must be called before `mantaPayWallet.initialSigner`
storageStateDb = new ClassicLevel(dbPath, { valueEncoding: 'json' })

await mantaPayWallet.initialSigner()
await mantaPayWallet.loadUserSeedPhrase(zkAccountSeedPhrase)
const zkAddress = await mantaPayWallet.getZkAddress()
console.log(`zkAddress: ${zkAddress}`)
return mantaPayWallet
}

const initialWallet = async (
baseWallet,
zkAccountSeedPhrase,
publicAccountSeedPhrase,
) => {
const mantaPayWallet = await getMantaPayWallet(
baseWallet,
zkAccountSeedPhrase,
)

const publicPair = getPair(publicAccountSeedPhrase)

return {
mantaPayWallet,
async toPrivateSend(assetId, amount) {
const transaction = await mantaPayWallet.toPrivateBuild(
new BN(assetId),
new BN(amount),
)
await sendTransaction(publicPair, transaction)
console.log(`toPrivateSend done, assetId: ${assetId}, amount: ${amount}`)
},
async privateTransferSend(assetId, amount, toZkAddress) {
const assetIdBn = new BN(assetId)
const amountBn = new BN(amount)
const estimateTransactionCount =
await mantaPayWallet.estimateTransferPostsCount(
'privateToPrivate',
assetIdBn,
amountBn,
toZkAddress,
)
if (estimateTransactionCount > maxTransactionCount) {
console.error(
`privateTransferSend error, estimateTransactionCount larger than ${maxTransactionCount}, (${estimateTransactionCount}), please consolidate assets first`,
)
return
}
const transaction = await mantaPayWallet.privateTransferBuild(
assetIdBn,
amountBn,
toZkAddress,
)
await sendTransaction(publicPair, transaction)
console.log(
`privateTransferSend done, assetId: ${assetId}, amount: ${amount}, toZkAddress: ${toZkAddress}`,
)
},
async toPublicSend(assetId, amount, toPublicAccount) {
const assetIdBn = new BN(assetId)
const amountBn = new BN(amount)
const formatToPublicAddress = toPublicAccount || publicPair.address
const estimateTransactionCount =
await mantaPayWallet.estimateTransferPostsCount(
'privateToPublic',
assetIdBn,
amountBn,
formatToPublicAddress,
)
if (estimateTransactionCount > maxTransactionCount) {
console.error(
`toPublicSend error, estimateTransactionCount larger than ${maxTransactionCount}, (${estimateTransactionCount}), please consolidate assets first`,
)
return
}
const transaction = await mantaPayWallet.toPublicBuild(
assetIdBn,
amountBn,
formatToPublicAddress,
)
await sendTransaction(publicPair, transaction)
console.log(
`toPublicSend done, assetId: ${assetId}, amount: ${amount}, toPublicAccount: ${formatToPublicAddress}`,
)
},
}
}

const start = async () => {
await cryptoWaitReady()
const baseWallet = await getBaseWallet()
await baseWallet.isApiReady()

const zkAccountSeedPhrase =
'present comic balcony bargain rare brass wage fly unit concert illegal simple'
const publicAccountSeedPhrase = zkAccountSeedPhrase

const actions = await initialWallet(
baseWallet,
zkAccountSeedPhrase,
publicAccountSeedPhrase,
)

await actions.mantaPayWallet.initialWalletSync()
const balance = await actions.mantaPayWallet.getZkBalance('1')
console.log(`KMA Balance: ${balance.toString()}`)

// test toPrivate transfer
console.log('Test 1/3: toPrivate')
await actions.toPrivateSend('1', String(1 * 10 ** 12))
console.log('Test 1/3: toPrivate done')

await new Promise((resolve) => {
setTimeout(resolve, 48 * 1000)
})
await actions.mantaPayWallet.walletSync()

// test toPublic transfer
console.log('Test 2/3: toPublic')
await actions.toPublicSend('1', String(1 * 10 ** 12))
console.log('Test 2/3: toPublic done')

await new Promise((resolve) => {
setTimeout(resolve, 48 * 1000)
})
await actions.mantaPayWallet.walletSync()

// test private transfer
console.log('Test 3/3: privateTransfer')
await actions.privateTransferSend(
'1',
String(1 * 10 ** 12),
'2aE8dmGPpw74p8eco7y58Aj1THWhEL4YrYp9xULMQDDy',
)
console.log('Test 3/3: privateTransfer done')

console.log('All test done')

process.exit(0);
}

start()
97 changes: 97 additions & 0 deletions manta-js/examples/sdk-node-example/src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const path = require('path')

const getDbPath = (palletName, network, address) => {
return path.resolve(__dirname, `../db/${palletName}_${network}_${address}`)
}

const overrideToJSON = () => {
let beforeBigIntToJSON = BigInt.prototype.toJSON
let beforeUint8ArrayToJSON = Uint8Array.prototype.toJSON
let beforeMapToJSON = Map.prototype.toJSON

BigInt.prototype.toJSON = function () {
return {
___type___: 'BigInt',
value: this.toString(),
}
}

Uint8Array.prototype.toJSON = function () {
return {
___type___: 'Uint8Array',
value: Array.from(this),
}
}

Map.prototype.toJSON = function () {
return {
___type___: 'Map',
value: JSON.stringify(Array.from(this.entries())),
}
}

return () => {
BigInt.prototype.toJSON = beforeBigIntToJSON
Uint8Array.prototype.toJSON = beforeUint8ArrayToJSON
Map.prototype.toJSON = beforeMapToJSON
}
}

const formatStateToJson = (state) => {
const revert = overrideToJSON()
const result = JSON.stringify(state, (key, value) => {
return value === undefined ? '___undefined___' : value
})
revert()
return result
}
const revertJsonToState = (json) => {
const formatJSON = JSON.parse(json)
const walk = (value) => {
if (value instanceof Array) {
return value.map(walk)
} else if (value instanceof Object && Object.keys(value).length > 0) {
if (value.___type___) {
if (value.___type___ === 'BigInt') {
return BigInt(value.value)
} else if (value.___type___ === 'Uint8Array') {
return Uint8Array.from(value.value)
} else if (value.___type___ === 'Map') {
const json = JSON.parse(value.value)
return new Map(json.map(walk))
}
} else {
Object.keys(value).forEach((key) => {
value[key] = walk(value[key])
})
return value
}
} else if (typeof value === 'string' && value === '___undefined___') {
return undefined
} else {
return value
}
}
const result = walk(formatJSON)
return result
}

const saveStorageState = async (db, data) => {
await db.put('value', formatStateToJson(data))
return true
}

const getStorageState = async (db) => {
try {
const result = await db.get('value')
return result ? revertJsonToState(result) : null
} catch (ex) {
return null
}
}

module.exports = {
getDbPath,
saveStorageState,
getStorageState,
}
Loading