UNPKG

myria-core-sdk

Version:

Latest version SDK

245 lines 21.8 kB
// import { ethers } from "ethers"; import { MyriaClient } from ".."; import { CommonAPI, RegisterAPI, UserAPI } from "../core/apis"; import { CommonModule, SIGN_MESSAGE } from "./CommonModule"; import { ContractFactory } from "../core/ContractFactory"; import { getDefaultOptions } from "../core/ContractHelpers"; import { bnTohex32, hexToBn } from '../core/helpers'; import { ethers } from "ethers"; import { DEFAULT_QUANTUM } from "../utils"; const { ec, keyDerivation, sign } = require('@starkware-industries/starkware-crypto-utils'); export class UserManager { constructor(client) { this.userAPI = new UserAPI(client.env); this.registrationAPI = new RegisterAPI(client.env); this.client = new MyriaClient(client); this.commonAPI = new CommonAPI(client.env); this.commonModule = new CommonModule(client); this.tokensAndRampingContract = this.getTokensAndRampingContract(this.client); } getTokensAndRampingContract(client) { const contractFactory = new ContractFactory(client); return contractFactory.getTokensAndRampingContract(); } async patchRegisterUserOnchain(ethAddress, transactionHash) { if (!ethAddress) { throw new Error('Eth Address is required'); } if (!transactionHash) { throw new Error('Transaction Hash is required'); } let patchUserRegisteredOnchain; try { patchUserRegisteredOnchain = await this.userAPI.patchRegisterUserOnchain(ethAddress, transactionHash); if (patchUserRegisteredOnchain.status !== 'success') { throw new Error('Register user on-chain to our system for synchronize on-chain status'); } } catch (ex) { console.log('Error -> ', ex); throw new Error('Error -> ' + JSON.stringify(ex)); } return patchUserRegisteredOnchain; } async registerUserOnChain(ethAddress, options) { const walletSign = await this.client.web3.eth.personal.sign(SIGN_MESSAGE, ethAddress, ''); const privateKeyFromSignature = keyDerivation.getPrivateKeyFromEthSignature(walletSign); const starkPublicKeyFromPrivateKey = keyDerivation.privateToStarkKey(privateKeyFromSignature); const starkPublicYToHex = bnTohex32(starkPublicKeyFromPrivateKey); const hashedMSG = ethers.utils.keccak256(ethers.utils.solidityPack(['string', 'address', 'uint256'], [ 'UserRegistration:', ethAddress, ethers.BigNumber.from('0x' + starkPublicYToHex) ])); const msgHashToBN = hexToBn(hashedMSG); const ecOrder = hexToBn('800000000000010FFFFFFFFFFFFFFFFB781126DCAE7B2321E66A241ADC64D2F'); const msgHashData2 = bnTohex32(msgHashToBN.mod(ecOrder)); const keyPair = ec.keyFromPrivate(privateKeyFromSignature, 'hex'); const starkSign = sign(keyPair, msgHashData2); const rHex = bnTohex32(starkSign === null || starkSign === void 0 ? void 0 : starkSign.r); const sHex = bnTohex32(starkSign === null || starkSign === void 0 ? void 0 : starkSign.s); const pubKey = ec.keyFromPublic(keyPair.getPublic(true, 'hex'), 'hex'); const pubKeyY = pubKey.pub.getY(); const starkPubkeyYHex = bnTohex32(pubKeyY); const abiCoder = new ethers.utils.AbiCoder(); const rBN = hexToBn(rHex).toString(); const sBN = hexToBn(sHex).toString(); const pubKeyBN = hexToBn(starkPubkeyYHex).toString(); let starkSignature = abiCoder.encode(['uint256', 'uint256', 'uint256'], [rBN, sBN, pubKeyBN]); starkSignature = starkSignature.substring(2, starkSignature.length); const starkKey = '0x' + starkPublicKeyFromPrivateKey; const optionsData = getDefaultOptions(options); try { const tx = await this.tokensAndRampingContract.registerEthAddress(ethAddress, starkKey, starkSignature, optionsData); return tx; } catch (err) { throw new Error(err); } console.log('ethAddress ->', ethAddress); console.log('options ->', options); throw new Error("The on-chain registered is not ready for testing"); } async registerUser(payload) { let res; const starkSignature = await this.commonModule.generateStarkSignatureForRegisterUser(payload); if (!starkSignature) { throw new Error("Message signing failed!"); } const requestPayload = { ethAddress: payload.ethAddress, starkKey: payload.starkKey, signature: starkSignature }; const registerUserResponse = await this.userAPI.registerUser(requestPayload); if ((registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.status) === "success") { res = registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.data; } else { throw new Error("Registration failed!"); } return res; } async getUserByWalletAddress(ethAddress) { if (!ethAddress) { throw new Error("Eth address is required!"); } let res; try { const registerUserResponse = await this.userAPI.getUserByWalletAddress(ethAddress); if ((registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.status) === 'success' && (registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.data)) { res = registerUserResponse === null || registerUserResponse === void 0 ? void 0 : registerUserResponse.data; } else { throw new Error('Get User failure - check BE server or validation request for calling'); } } catch (err) { throw new Error(err); } return res; } async getBalanceETH(starkKey) { if (!starkKey) { throw new Error("Stark Key is required!"); } let res; try { const balanceResponse = await this.userAPI.getBalanceETH(starkKey); if ((balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.status) === "success" && (balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data)) { res = balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data; } else { throw new Error("Error"); } } catch (err) { throw new Error(err); } return res; } async getBalanceERC20(starkKey, assetId) { if (!starkKey) { throw new Error("Stark Key is required!"); } let res; try { const balanceResponse = await this.userAPI.getBalanceERC20(starkKey, assetId); if ((balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.status) === "success" && (balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data)) { res = balanceResponse === null || balanceResponse === void 0 ? void 0 : balanceResponse.data; } else { throw new Error("Error"); } } catch (err) { throw new Error(err); } return res; } async registerMintableERC721Token(params) { let res; try { const registeredTokenResponse = await this.commonAPI.registerMintableERC721Token(params); if (registeredTokenResponse.status === 'success') { res = registeredTokenResponse.data; } else { throw new Error('There is an internal server error, please try again'); } } catch (ex) { throw new Error(ex); } return res; } async registerERC20Token(params) { const registerTokenERC20Request = { ...params, quantum: DEFAULT_QUANTUM }; let res; try { const registeredTokenResponse = await this.commonAPI.registerERC20Token(registerTokenERC20Request); if (registeredTokenResponse.status === 'success') { res = registeredTokenResponse.data; } else { throw new Error('There is an internal server error, please try again'); } } catch (ex) { throw new Error(ex); } return res; } async getRegisteredTokens(starkKey) { let res; try { const registeredTokenResponse = await this.registrationAPI.getRegisteredTokenByStarkKey(starkKey); if (registeredTokenResponse.status === 'success') { res = registeredTokenResponse.data; } else { throw new Error('There is an internal server error, please try again'); } } catch (ex) { throw new Error(ex); } return res; } /** * @summary Function config notification email * @param {string} ethAddress ETH address of user config * @param {SettingNotificationParam[]} notificationConfigParam Array option trigger notification email * @returns {SettingNotificationResponse} Status list of notification after trigger * @throws {string} Exception: Eth Address is required! * @throws {string} Exception: Notification option params is required or Invalid! * @throws {string} Exception: Change notification email failed * @throws {string} Exception: Network Error */ async configNotificationSetting(ethAddress, notificationConfigParam) { if (!ethAddress) { throw new Error("Eth Address is required!"); } if (!notificationConfigParam || (notificationConfigParam && notificationConfigParam.length === 0)) { throw new Error("Notification option params is required or Invalid!"); } let res; try { const configEmailNotificationRes = await this.userAPI.configEmailNotification(ethAddress, notificationConfigParam); if ((configEmailNotificationRes === null || configEmailNotificationRes === void 0 ? void 0 : configEmailNotificationRes.status) === "success" && (configEmailNotificationRes === null || configEmailNotificationRes === void 0 ? void 0 : configEmailNotificationRes.data)) { res = configEmailNotificationRes === null || configEmailNotificationRes === void 0 ? void 0 : configEmailNotificationRes.data; } else { throw new Error("Error"); } } catch (err) { throw new Error(err); } return res; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVXNlck1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9Vc2VyTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxtQ0FBbUM7QUFDbkMsT0FBTyxFQUFnQixXQUFXLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFL0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRS9ELE9BQU8sRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRTFELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzVELE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDckQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUVoQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRTNDLE1BQU0sRUFBRSxFQUFFLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFBO0FBRTNGLE1BQU0sT0FBTyxXQUFXO0lBUXRCLFlBQVksTUFBb0I7UUFDOUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0QyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksU0FBUyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMzQyxJQUFJ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