Skip to content

Commit

Permalink
wallet-ext: use request_add_delegation_mul_coin for staking (MystenLa…
Browse files Browse the repository at this point in the history
…bs#7631)

* also increases the default gas budget for stake to account for merging
too many coins

(It no longer requires a Pay tx before doing the actual staking)


https://user-images.githubusercontent.com/10210143/214341083-1d7c3aca-bf21-4bc6-bfba-a3b4f78ea590.mov



closes APPS-400
  • Loading branch information
pchrysochoidis authored Jan 25, 2023
1 parent abb34e8 commit e0f24f9
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 21 deletions.
6 changes: 6 additions & 0 deletions apps/wallet/src/ui/app/redux/slices/account/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,9 @@ export function createAccountNftByIdSelector(nftId: ObjectId) {
allNfts.find((nft) => getObjectId(nft.reference) === nftId) || null
);
}

export function createCoinsForTypeSelector(coinTypeArg: string) {
return createSelector(accountCoinsSelector, (allCoins) =>
allCoins.filter((aCoin) => Coin.getCoinTypeArg(aCoin) === coinTypeArg)
);
}
48 changes: 41 additions & 7 deletions apps/wallet/src/ui/app/redux/slices/sui-objects/Coin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const COIN_TYPE = '0x2::coin::Coin';
const COIN_TYPE_ARG_REGEX = /^0x2::coin::Coin<(.+)>$/;

export const DEFAULT_GAS_BUDGET_FOR_PAY = 150;
export const DEFAULT_GAS_BUDGET_FOR_STAKE = 10000;
export const DEFAULT_GAS_BUDGET_FOR_STAKE = 15000;
export const GAS_TYPE_ARG = '0x2::sui::SUI';
export const GAS_SYMBOL = 'SUI';
export const DEFAULT_NFT_TRANSFER_GAS_FEE = 450;
Expand Down Expand Up @@ -81,26 +81,60 @@ export class Coin {
*
* @param signer A signer with connection to fullnode
* @param coins A list of Coins owned by the signer with the same generic type(e.g., 0x2::Sui::Sui)
* @param gasCoins A list of Sui coins owned by the signer
* @param amount The amount to be staked
* @param validator The sui address of the chosen validator
*/
public static async stakeCoin(
signer: SignerWithProvider,
coins: SuiMoveObject[],
gasCoins: SuiMoveObject[],
amount: bigint,
validator: SuiAddress
): Promise<SuiExecuteTransactionResponse> {
const coin = await Coin.requestSuiCoinWithExactAmount(
signer,
coins,
amount
// sort to get the smallest one for gas
const sortedGasCoins = CoinAPI.sortByBalance(gasCoins);
const gasCoin = CoinAPI.selectCoinWithBalanceGreaterThanOrEqual(
sortedGasCoins,
BigInt(DEFAULT_GAS_BUDGET_FOR_STAKE)
);
if (!gasCoin) {
throw new Error(
'Insufficient funds, not enough funds to cover for gas fee.'
);
}
if (!coins.length) {
throw new Error('Insufficient funds, no coins found.');
}
const isSui = CoinAPI.getCoinTypeArg(coins[0]) === SUI_TYPE_ARG;
const stakeCoins =
CoinAPI.selectCoinSetWithCombinedBalanceGreaterThanOrEqual(
coins,
amount,
isSui ? [CoinAPI.getID(gasCoin)] : undefined
).map(CoinAPI.getID);
if (!stakeCoins.length) {
if (stakeCoins.length === 1 && isSui) {
throw new Error(
'Not enough coin objects, at least 2 coin objects are required.'
);
} else {
throw new Error(
'Insufficient funds, try reducing the stake amount.'
);
}
}
const txn = {
packageObjectId: '0x2',
module: 'sui_system',
function: 'request_add_delegation',
function: 'request_add_delegation_mul_coin',
typeArguments: [],
arguments: [SUI_SYSTEM_STATE_OBJECT_ID, coin, validator],
arguments: [
SUI_SYSTEM_STATE_OBJECT_ID,
stakeCoins,
[String(amount)],
validator,
],
gasBudget: DEFAULT_GAS_BUDGET_FOR_STAKE,
};
return await signer.executeMoveCall(txn);
Expand Down
27 changes: 13 additions & 14 deletions apps/wallet/src/ui/app/staking/stake/StakingCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
SUI_TYPE_ARG,
normalizeSuiAddress,
type SuiAddress,
type SuiMoveObject,
} from '@mysten/sui.js';
import { useQueryClient, useMutation } from '@tanstack/react-query';
import { Formik } from 'formik';
Expand Down Expand Up @@ -38,7 +37,7 @@ import {
import {
accountAggregateBalancesSelector,
accountItemizedBalancesSelector,
ownedObjects,
createCoinsForTypeSelector,
} from '_redux/slices/account';
import {
Coin,
Expand Down Expand Up @@ -162,7 +161,16 @@ function StakingCard() {

const navigate = useNavigate();
const signer = useSigner();
const allCoins = useAppSelector(ownedObjects);
const allCoinsForStakeSelector = useMemo(
() => createCoinsForTypeSelector(coinType),
[coinType]
);
const allCoinsForStake = useAppSelector(allCoinsForStakeSelector);
const allSuiCoinsSelector = useMemo(
() => createCoinsForTypeSelector(SUI_TYPE_ARG),
[]
);
const allSuiCoins = useAppSelector(allSuiCoinsSelector);
const stakeToken = useMutation({
mutationFn: async ({
tokenTypeArg,
Expand All @@ -176,19 +184,10 @@ function StakingCard() {
if (!validatorAddress || !amount || !tokenTypeArg) {
throw new Error('Failed, missing required field');
}

const coinType = Coin.getCoinTypeFromArg(tokenTypeArg);
const coins: SuiMoveObject[] = allCoins
.filter(
(anObj) =>
anObj.data.dataType === 'moveObject' &&
anObj.data.type === coinType
)
.map(({ data }) => data as SuiMoveObject);

const response = Coin.stakeCoin(
signer,
coins,
allCoinsForStake,
allSuiCoins,
amount,
validatorAddress
);
Expand Down

0 comments on commit e0f24f9

Please sign in to comment.