@ylide/everscale
Version:
Ylide Protocol SDK implementation for EverScale blockchain
260 lines • 13.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.randomHex = exports.venomWalletFactory = exports.everscaleWalletFactory = exports.EverscaleWalletController = void 0;
const everscale_inpage_provider_1 = require("everscale-inpage-provider");
const sdk_1 = require("@ylide/sdk");
const smart_buffer_1 = __importDefault(require("@ylide/smart-buffer"));
const contracts_1 = require("../contracts");
const misc_1 = require("../misc");
const contractUtils_1 = require("../contracts/contractUtils");
class EverscaleWalletController extends sdk_1.AbstractWalletController {
options;
ever;
mailerContract;
broadcasterContract;
registryContract;
lastCurrentAccount = null;
// on(event: WalletEvent.ACCOUNT_CHANGED, fn: (newAccount: IGenericAccount) => void, context?: any): this;
// on(event: WalletEvent.BLOCKCHAIN_CHANGED, fn: (newBlockchain: string) => void, context?: any): this;
// on(event: WalletEvent.LOGIN, fn: (newAccount: IGenericAccount) => void, context?: any): this;
// on(event: WalletEvent.LOGOUT, fn: () => void, context?: any): this;
constructor(options = {}) {
super(options);
this.options = options;
if (typeof options.type === 'undefined') {
throw new Error('You must provide network type for EverscaleWalletController');
}
this.onSwitchAccountRequest = options?.onSwitchAccountRequest || null;
this.ever = new everscale_inpage_provider_1.ProviderRpcClient({
fallback: async () => (options.type === 'everwallet' ? window.__ever : window.__venom),
forceUseFallback: true,
});
this.broadcasterContract = new contracts_1.MailerContract(this.ever, options.broadcasterContractAddress ||
(options.dev
? misc_1.DEV_BROADCASTER_ADDRESS
: options.type === 'venomwallet'
? misc_1.BROADCASTER_VENOM_ADDRESS
: misc_1.BROADCASTER_EVERSCALE_ADDRESS));
this.mailerContract = new contracts_1.MailerContract(this.ever, options.mailerContractAddress ||
(options.dev
? misc_1.DEV_MAILER_ADDRESS
: options.type === 'venomwallet'
? misc_1.MAILER_VENOM_ADDRESS
: misc_1.MAILER_EVERSCALE_ADDRESS));
this.registryContract = new contracts_1.RegistryContract(this.ever, options.registryContractAddress ||
(options.dev
? misc_1.DEV_REGISTRY_ADDRESS
: options.type === 'venomwallet'
? misc_1.REGISTRY_VENOM_ADDRESS
: misc_1.REGISTRY_EVERSCALE_ADDRESS));
}
isMultipleAccountsSupported() {
return false;
}
async init() {
await this.getAuthenticatedAccount();
const logoutSubscription = await this.ever.subscribe('loggedOut');
logoutSubscription.on('data', () => this.emit(sdk_1.WalletEvent.LOGOUT));
const networkSubscription = await this.ever.subscribe('networkChanged');
networkSubscription.on('data', data => {
// tslint:disable-next-line
console.log('networkSubscription data: ', data);
});
const permissionsSubscription = await this.ever.subscribe('permissionsChanged');
permissionsSubscription.on('data', data => {
const oldAccount = this.lastCurrentAccount;
if (data.permissions.accountInteraction) {
this.lastCurrentAccount = {
blockchain: this.options.type === 'everwallet' ? 'everscale' : 'venom',
address: data.permissions.accountInteraction.address.toString(),
publicKey: sdk_1.PublicKey.fromHexString(sdk_1.PublicKeyType.EVERSCALE_NATIVE, data.permissions.accountInteraction.publicKey),
};
if (oldAccount) {
this.emit(sdk_1.WalletEvent.ACCOUNT_CHANGED, this.lastCurrentAccount);
}
else {
this.emit(sdk_1.WalletEvent.LOGIN, this.lastCurrentAccount);
}
}
else {
if (oldAccount) {
this.emit(sdk_1.WalletEvent.LOGOUT);
}
}
});
}
async ensureAccount(needAccount) {
let me = await this.getAuthenticatedAccount();
if (!me || me.address !== needAccount.address) {
await this.switchAccountRequest(me, needAccount);
me = await this.getAuthenticatedAccount();
}
if (!me || me.address !== needAccount.address) {
throw new sdk_1.YlideError(sdk_1.YlideErrorType.ACCOUNT_UNREACHABLE, { currentAccount: me, needAccount });
}
}
addressToUint256(address) {
return (0, sdk_1.hexToUint256)(address.split(':')[1].toLowerCase());
}
async requestYlidePrivateKey(me) {
throw new Error('Method not available.');
}
async signMagicString(account, magicString) {
await this.ensureAccount(account);
const me = await this.getAuthenticatedAccount();
if (!me) {
throw new Error(`Can't derive without auth`);
}
const result = await this.ever.signData({
publicKey: me.publicKey.toHex(),
data: smart_buffer_1.default.ofUTF8String(magicString).toBase64String(),
});
// @ts-ignore
return (0, sdk_1.sha256)(smart_buffer_1.default.ofHexString(result.signatureHex || result.signature_hex).bytes);
}
// account block
async getAuthenticatedAccount() {
await this.ever.ensureInitialized();
const providerState = await this.ever.getProviderState();
if (providerState.permissions.accountInteraction) {
this.lastCurrentAccount = {
blockchain: this.options.type === 'everwallet' ? 'everscale' : 'venom',
address: providerState.permissions.accountInteraction.address.toString(),
publicKey: sdk_1.PublicKey.fromHexString(sdk_1.PublicKeyType.EVERSCALE_NATIVE, providerState.permissions.accountInteraction.publicKey),
};
return this.lastCurrentAccount;
}
else {
this.lastCurrentAccount = null;
return null;
}
}
async getCurrentBlockchain() {
return this.options.type === 'everwallet' ? 'everscale' : 'venom';
}
async attachPublicKey(account, publicKey) {
await this.ensureAccount(account);
// key version = 2
// registrar = 2 - everscale
await this.registryContract.attachPublicKey(account.address, publicKey);
}
async requestAuthentication() {
const acc = await this.getAuthenticatedAccount();
if (acc) {
await this.disconnectAccount(acc);
}
const { accountInteraction } = await this.ever.requestPermissions({
permissions: ['basic', 'accountInteraction'],
});
if (accountInteraction) {
return {
blockchain: this.options.type === 'everwallet' ? 'everscale' : 'venom',
address: accountInteraction.address.toString(),
publicKey: sdk_1.PublicKey.fromHexString(sdk_1.PublicKeyType.EVERSCALE_NATIVE, accountInteraction.publicKey),
};
}
else {
throw new Error('Not authenticated');
}
}
async disconnectAccount(account) {
await this.ensureAccount(account);
await this.ever.disconnect();
}
async publishMessage(me, contentData, recipients) {
await this.ensureAccount(me);
const uniqueId = Math.floor(Math.random() * 4 * 10 ** 9);
const chunks = sdk_1.MessageChunks.splitMessageChunks(contentData);
if (chunks.length === 1 && recipients.length === 1) {
const transaction = await this.mailerContract.sendSmallMail(me.address, uniqueId, recipients[0].address, recipients[0].messageKey.toBytes(), chunks[0]);
const om = transaction.childTransaction.outMessages;
const contentMsg = om.length ? om[0] : null;
if (!contentMsg || !contentMsg.body) {
throw new Error('Content event was not found');
}
const decodedEvent = (0, contractUtils_1.decodeContentMessageBody)(contentMsg.body);
return decodedEvent.msgId;
}
else if (chunks.length === 1 && recipients.length < Math.ceil((15.5 * 1024 - chunks[0].byteLength) / 70)) {
const transaction = await this.mailerContract.sendBulkMail(me.address, uniqueId, recipients.map(r => r.address), recipients.map(r => r.messageKey.toBytes()), chunks[0]);
const om = transaction.childTransaction.outMessages;
const contentMsg = om.length ? om[0] : null;
if (!contentMsg || !contentMsg.body) {
throw new Error('Content event was not found');
}
const decodedEvent = (0, contractUtils_1.decodeContentMessageBody)(contentMsg.body);
return decodedEvent.msgId;
}
else {
const initTime = Math.floor(Date.now() / 1000);
const msgId = await this.mailerContract.buildHash(me.publicKey.bytes, uniqueId, initTime);
for (let i = 0; i < chunks.length; i++) {
await this.mailerContract.sendMultipartMailPart(me.address, uniqueId, initTime, chunks.length, i, chunks[i]);
}
for (let i = 0; i < recipients.length; i += 210) {
const recs = recipients.slice(i, i + 210);
await this.mailerContract.addRecipients(me.address, uniqueId, initTime, recs.map(r => r.address), recs.map(r => r.messageKey.toBytes()));
}
return msgId;
}
}
async broadcastMessage(me, contentData) {
await this.ensureAccount(me);
const uniqueId = Math.floor(Math.random() * 4 * 10 ** 9);
const chunks = sdk_1.MessageChunks.splitMessageChunks(contentData);
if (chunks.length === 1) {
const transaction = await this.broadcasterContract.broadcastMail(me.address, uniqueId, chunks[0]);
const om = transaction.childTransaction.outMessages;
const contentMsg = om.length ? om[0] : null;
if (!contentMsg || !contentMsg.body) {
throw new Error('Content event was not found');
}
const decodedEvent = (0, contractUtils_1.decodeContentMessageBody)(contentMsg.body);
return decodedEvent.msgId;
}
else {
const initTime = Math.floor(Date.now() / 1000);
const msgId = await this.broadcasterContract.buildHash(me.publicKey.bytes, uniqueId, initTime);
for (let i = 0; i < chunks.length; i++) {
await this.broadcasterContract.sendMultipartMailPart(me.address, uniqueId, initTime, chunks.length, i, chunks[i]);
}
await this.broadcasterContract.broadcastMailHeader(me.address, uniqueId, initTime);
return msgId;
}
}
async decryptMessageKey(recipientAccount, senderPublicKey, encryptedKey) {
if (senderPublicKey.type !== sdk_1.PublicKeyType.EVERSCALE_NATIVE) {
throw new Error('EverWallet can only decrypt native encryption of EverWallet');
}
const { encData, nonce } = (0, sdk_1.unpackSymmetricalyEncryptedData)(encryptedKey);
const decryptionResultBase64 = await this.ever.decryptData({
algorithm: 'ChaCha20Poly1305',
sourcePublicKey: senderPublicKey.toHex(),
recipientPublicKey: recipientAccount.publicKey.toHex(),
data: new smart_buffer_1.default(encData).toBase64String(),
nonce: new smart_buffer_1.default(nonce).toBase64String(),
});
return smart_buffer_1.default.ofBase64String(decryptionResultBase64).bytes;
}
}
exports.EverscaleWalletController = EverscaleWalletController;
exports.everscaleWalletFactory = {
create: async (options) => new EverscaleWalletController(Object.assign({ type: 'everwallet' }, options || {})),
isWalletAvailable: () => new everscale_inpage_provider_1.ProviderRpcClient({ fallback: async () => window.__ever, forceUseFallback: true }).hasProvider(),
blockchainGroup: 'everscale',
wallet: 'everwallet',
};
exports.venomWalletFactory = {
create: async (options) => new EverscaleWalletController(Object.assign({ type: 'venomwallet' }, options || {})),
isWalletAvailable: () => new everscale_inpage_provider_1.ProviderRpcClient({ fallback: async () => window.__venom, forceUseFallback: true }).hasProvider(),
blockchainGroup: 'venom',
wallet: 'venomwallet',
};
function randomHex(length = 64) {
return [...Array(length)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');
}
exports.randomHex = randomHex;
//# sourceMappingURL=EverscaleWalletController.js.map