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

[WIP] Feature/account abstraction #170

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
117 changes: 117 additions & 0 deletions src/chains/account-abstraction/conversations/initialize-account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { AccountAbstractionManager, isValidSuiAddress } from '@avernikoz/rinbot-sui-sdk';
import goHome from '../../../inline-keyboards/goHome';
import confirmWithCloseKeyboard from '../../../inline-keyboards/mixed/confirm-with-close';
import { retryAndGoHomeButtonsData } from '../../../inline-keyboards/retryConversationButtonsFactory';
import { BotContext, MyConversation } from '../../../types';
import { CallbackQueryData } from '../../../types/callback-queries-data';
import { ConversationId } from '../../conversations.config';
import { getTransactionFromMethod, signAndExecuteTransaction } from '../../conversations.utils';
import { TransactionResultStatus } from '../../sui.functions';
import { getSuiVisionTransactionLink } from '../../utils';

export async function initializeAccount(conversation: MyConversation, ctx: BotContext) {
const retryButton = retryAndGoHomeButtonsData[ConversationId.InitializeAccount];

await ctx.reply(
'Please, enter the address to which your account will be able to withdraw funds.\n\n' +
'<b>Example</b>: <code>0x0aca2a52083bd23b09cf8efe2c9b84903d04a46dba6c6f78b4ef06f8bbec1082</code>',
{ parse_mode: 'HTML' },
);

let userFinishedAddressesAddition = false;
let addressToWithdraw: string | undefined;

do {
const addressContext = await conversation.waitFor('message:text');
const address = addressContext.msg.text;

const addressIsValid = isValidSuiAddress(address);

if (!addressIsValid) {
await ctx.reply('Entered address is not valid. Please, specify a valid one.');

continue;
}

await ctx.reply(`You are about to save <code>${address}</code> as the <b>withdraw address</b>.`, {
reply_markup: confirmWithCloseKeyboard,
parse_mode: 'HTML',
});

const confirmContext = await conversation.waitFor('callback_query:data');
const confirmCallbackQueryData = confirmContext.callbackQuery.data;

if (
confirmCallbackQueryData === CallbackQueryData.Cancel ||
confirmCallbackQueryData !== CallbackQueryData.Confirm
) {
await confirmContext.answerCallbackQuery();
await ctx.reply('Please, enter another <b>withdraw address</b>.', { parse_mode: 'HTML' });

continue;
}

addressToWithdraw = address;
userFinishedAddressesAddition = true;

await confirmContext.answerCallbackQuery();
break;
} while (!userFinishedAddressesAddition);

if (addressToWithdraw === undefined) {
await ctx.reply('Cannot process entered <b>withdraw address</b>. Please, try again or contact support.', {
reply_markup: retryButton,
parse_mode: 'HTML',
});

return;
}

const transaction = await getTransactionFromMethod({
conversation,
ctx,
method: AccountAbstractionManager.getCreateNewAccountTransaction,
// TODO: Make sure `owner` is `addressToWithdraw`
params: { owner: addressToWithdraw },
});

if (transaction === undefined) {
await ctx.reply('Failed to create transaction for account creation. Please, try again or contact support.', {
reply_markup: retryButton,
});

return;
}

// TODO: Who should be the `signerPrivateKey`?
const result = await signAndExecuteTransaction({ conversation, ctx, transaction, signerPrivateKey: '' });

if (result.result === TransactionResultStatus.Success && result.digest !== undefined) {
// TODO: Where to fetch created account from?
conversation.session.account = 'some_account';

await ctx.reply(
`Your account is <a href="${getSuiVisionTransactionLink(result.digest)}">successfully created</a>!`,
{ reply_markup: goHome, parse_mode: 'HTML', link_preview_options: { is_disabled: true } },
);

return;
}

if (result.result === TransactionResultStatus.Failure && result.digest !== undefined) {
await ctx.reply(`<a href="${getSuiVisionTransactionLink(result.digest)}">Failed</a> to create account.`, {
reply_markup: retryButton,
parse_mode: 'HTML',
link_preview_options: { is_disabled: true },
});

return;
}

await ctx.reply(`<b>Failed</b> to create account.`, {
reply_markup: retryButton,
parse_mode: 'HTML',
});

return;
}
1 change: 1 addition & 0 deletions src/chains/conversations.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export enum ConversationId {
ImportNewWallet = 'importNewWallet',
CheckCurrentWalletForRefund = 'checkCurrentWalletForRefund',
CheckProvidedAddressForRefund = 'checkProvidedAddressForRefund',
InitializeAccount = 'initializeAccount',
}
1 change: 1 addition & 0 deletions src/chains/conversations.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export async function getTransactionForStructuredResult<T extends (params: Param
return transaction;
}

// TODO: Modify method to work with account
export async function signAndExecuteTransaction({
conversation,
ctx,
Expand Down
1 change: 1 addition & 0 deletions src/chains/fees/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DEFAULT_FEE_PERCENTAGE, RINCEL_TO_FEES_MAP } from './config';

export async function getUserRincelBalance(ctx: BotContext) {
const walletManager = await getWalletManager();
// TODO: Replace all `getAllCoinAssets` calls with account assets fetching
const allAssets = await walletManager.getAllCoinAssets(ctx.session.publicKey);
const foundRincel = findCoinInAssets(allAssets, RINCEL_COIN_TYPE);
const rincelBalance = foundRincel?.balance ?? '0';
Expand Down
61 changes: 22 additions & 39 deletions src/chains/sui.functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
clmmMainnet,
getLpCoinDecimals,
getSuiProvider,
isValidSuiAddress,
isValidTokenAddress,
isValidTokenAmount,
transactionFromSerializedTransaction,
Expand Down Expand Up @@ -169,6 +168,8 @@ export const getRouteManager = async () => {
};

export async function withdraw(conversation: MyConversation, ctx: BotContext): Promise<void> {
const retryButton = retryAndGoHomeButtonsData[ConversationId.Withdraw];

const {
welcomeBonus: { isUserAgreeWithBonus, isUserClaimedBonus, amount: welcomeBonusAmount },
refund: { claimedBoostedRefund, boostedRefundAmount },
Expand Down Expand Up @@ -201,46 +202,11 @@ export async function withdraw(conversation: MyConversation, ctx: BotContext): P
);
}

await ctx.reply(`Please, type the address to which you would like to send your SUI.`, {
reply_markup: closeConversation,
});
const retryButton = retryAndGoHomeButtonsData[ConversationId.Withdraw];

const messageData = await conversation.waitUntil(async (ctx) => {
if (ctx.callbackQuery?.data === 'close-conversation') {
return false;
}

const destinationSuiAddress = ctx.msg?.text;

if (destinationSuiAddress === undefined) {
return false;
}

const addressIsValid = isValidSuiAddress(destinationSuiAddress);

if (!addressIsValid) {
await ctx.reply(`Destination wallet address is not correct.\n\nPlease, try again.`, {
reply_markup: closeConversation,
});

return false;
}

return true;
});
const destinationSuiAddress = messageData.msg?.text;

// ts check
if (destinationSuiAddress === undefined) {
await ctx.reply(`Destination wallet address is not correct.\n\nCannot continue.`, {
reply_markup: closeConversation,
});
return;
}
// TODO: Get info about account and print to user the owner's public key, to which will funds be withdrawn

let { availableAmount, totalGasFee } = await conversation.external(async () => {
const walletManager = await getWalletManager();
// TODO: Get available withdraw SUI amount for account
return await walletManager.getAvailableWithdrawSuiAmount(ctx.session.publicKey);
});

Expand Down Expand Up @@ -314,9 +280,11 @@ export async function withdraw(conversation: MyConversation, ctx: BotContext): P
await ctx.reply('Initiating withdrawal...');
let tx;

// TODO: Use method from utils to create transaction
try {
const txBlock = await WalletManagerSingleton.getWithdrawSuiTransaction({
amount: inputAmount,
// TODO: Replace `destinationSuiAddress` with account owner's address
address: destinationSuiAddress,
});
txBlock.setGasBudget(Number(totalGasFee));
Expand All @@ -339,6 +307,7 @@ export async function withdraw(conversation: MyConversation, ctx: BotContext): P

await ctx.reply('Sending withdraw transaction...');

// TODO: use method from utils to sign & execute transaction
try {
const res = await provider.signAndExecuteTransactionBlock({
transactionBlock: tx,
Expand Down Expand Up @@ -376,12 +345,14 @@ export async function withdraw(conversation: MyConversation, ctx: BotContext): P

export async function availableBalance(ctx: BotContext): Promise<string> {
const walletManager = await getWalletManager();
// TODO: Fetch account's available SUI balance
const availableBalance = await walletManager.getAvailableSuiBalance(ctx.session.publicKey);
return availableBalance;
}

export async function balance(ctx: BotContext): Promise<string> {
const walletManager = await getWalletManager();
// TODO: Fetch account's SUI balance
const balance = await walletManager.getSuiBalance(ctx.session.publicKey);
return balance;
}
Expand Down Expand Up @@ -638,7 +609,7 @@ export async function home(ctx: BotContext) {

const welcomeText =
`<b>Welcome to RINbot on Sui Network!</b>\n\n` +
`Your wallet address (click to copy): <code>${ctx.session.publicKey}</code>\n\n` +
`Your account address (click to copy): <code>${ctx.session.account}</code>\n\n` +
`${positionOverview}Your SUI balance: ${balanceSUIdStr}\n` +
`Your available SUI balance: ${avlBalanceSUIdStr}\n\n${totalBalanceStr}`;
await ctx.reply(welcomeText, {
Expand Down Expand Up @@ -1259,9 +1230,12 @@ export async function createAftermathPool(conversation: MyConversation, ctx: Bot

// Create LP coin
await ctx.reply('Creating LP coin...');

// TODO: Use method from utils to create transaction
const createLpCoinTransaction = await conversation.external({
task: async () => {
try {
// TODO: Use adapted for account method to create LP coin
const createLpCoinTransaction = await AftermathSingleton.getCreateLpCoinTransaction({
publicKey: ctx.session.publicKey,
lpCoinDecimals,
Expand Down Expand Up @@ -1313,6 +1287,7 @@ export async function createAftermathPool(conversation: MyConversation, ctx: Bot
return;
}

// TODO: use method from utils to sign & execute transaction
const resultOfCreateLpCoin: {
createLpCoinResult?: SuiTransactionBlockResponse;
digest?: string;
Expand Down Expand Up @@ -1390,9 +1365,12 @@ export async function createAftermathPool(conversation: MyConversation, ctx: Bot

// Create pool
await ctx.reply('Creating the pool...');

// TODO: Use method from utils to create transaction
const createPoolTransaction = await conversation.external({
task: async () => {
try {
// TODO: Use adapted for account method to create pool
const createPoolTransaction = await AftermathSingleton.getCreatePoolTransaction({
publicKey: ctx.session.publicKey,
createLpCoinTransactionResult: createLpCoinResult,
Expand Down Expand Up @@ -1448,6 +1426,7 @@ export async function createAftermathPool(conversation: MyConversation, ctx: Bot
return;
}

// TODO: use method from utils to sign & execute transaction
const resultOfCreatePool: {
createPoolResult?: SuiTransactionBlockResponse;
digest?: string;
Expand Down Expand Up @@ -1868,9 +1847,12 @@ export async function createCoin(conversation: MyConversation, ctx: BotContext):
// console.debug('fixedSupply:', fixedSupply);

await ctx.reply('Creating the coin transaction...');

// TODO: Use method from utils to create transaction
const createCoinTransaction = await conversation.external({
task: async () => {
try {
// TODO: Use adapted for account method to create coin
const createCoinTx = await CoinManagerSingleton.getCreateCoinTransaction({
name: coinName,
symbol: coinSymbol,
Expand Down Expand Up @@ -1929,6 +1911,7 @@ export async function createCoin(conversation: MyConversation, ctx: BotContext):
return;
}

// TODO: use method from utils to sign & execute transaction
const resultOfCreateCoin: {
createCoinResult?: SuiTransactionBlockResponse;
digest?: string;
Expand Down
2 changes: 2 additions & 0 deletions src/chains/trading/buy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export async function buy(conversation: MyConversation, ctx: BotContext) {
const availableBalance = await conversation.external(async () => {
const walletManager = await getWalletManager();
// TODO: Maybe we should add try/catch here as well
// TODO: Get available SUI balance of account instead of public key
const balance = await walletManager.getAvailableSuiBalance(conversation.session.publicKey);
return balance;
});
Expand Down Expand Up @@ -225,6 +226,7 @@ export const instantBuy = async (conversation: MyConversation, ctx: BotContext)
const transaction = await getTransactionFromMethod({
conversation,
ctx,
// TODO: Use adapted method for account usage & modify corresponding params
method: routerManager.getBestRouteTransaction.bind(routerManager) as typeof routerManager.getBestRouteTransaction,
params: {
tokenFrom: LONG_SUI_COIN_TYPE,
Expand Down
2 changes: 2 additions & 0 deletions src/chains/trading/sell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export async function sell(conversation: MyConversation, ctx: BotContext): Promi
const availableBalance = await conversation.external(async () => {
const walletManager = await getWalletManager();
// TODO: Maybe we should add try/catch here as well
// TODO: Get available SUI balance of account instead of public key
const balance = await walletManager.getAvailableSuiBalance(conversation.session.publicKey);

return balance;
Expand Down Expand Up @@ -299,6 +300,7 @@ export async function sell(conversation: MyConversation, ctx: BotContext): Promi
const transaction = await getTransactionFromMethod({
conversation,
ctx,
// TODO: Use adapted method for account usage & modify corresponding params
method: routerManager.getBestRouteTransaction.bind(routerManager) as typeof routerManager.getBestRouteTransaction,
params: {
tokenFrom: validCoinToSell.type,
Expand Down
4 changes: 4 additions & 0 deletions src/chains/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,7 @@ export async function coinCannotBeSoldDueToDelay({

return false;
}

export function accountIsNotInitialized(ctx: BotContext) {
return ctx.session.account === null;
}
1 change: 1 addition & 0 deletions src/chains/wallet/conversations/export-private-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { BotContext, MyConversation } from '../../../types';
import { ConversationId } from '../../conversations.config';
import { getPrivateKeyString, userIsNotEligibleToExportPrivateKey } from '../utils';

// TODO: Remove this feature for accounts
export async function exportPrivateKey(conversation: MyConversation, ctx: BotContext): Promise<void> {
if (await userIsNotEligibleToExportPrivateKey(ctx)) {
return;
Expand Down
Loading