Skip to content

Commit d3892e0

Browse files
feat(sdk-coin-sui): walrus unstaking tx support
TICKET: SC-1098
1 parent 47e3fb5 commit d3892e0

File tree

8 files changed

+724
-5
lines changed

8 files changed

+724
-5
lines changed

modules/sdk-coin-sui/src/lib/iface.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export enum SuiTransactionType {
2020
CustomTx = 'CustomTx',
2121
TokenTransfer = 'TokenTransfer',
2222
WalrusStakeWithPool = 'WalrusStakeWithPool',
23+
WalrusRequestWithdrawStake = 'WalrusRequestWithdrawStake',
24+
WalrusWithdrawStake = 'WalrusWithdrawStake',
2325
}
2426

2527
export interface TransactionExplanation extends BaseTransactionExplanation {
@@ -32,7 +34,8 @@ export type SuiProgrammableTransaction =
3234
| UnstakingProgrammableTransaction
3335
| CustomProgrammableTransaction
3436
| TokenTransferProgrammableTransaction
35-
| WalrusStakingProgrammableTransaction;
37+
| WalrusStakingProgrammableTransaction
38+
| WalrusWithdrawStakeProgrammableTransaction;
3639

3740
export interface TxData {
3841
id?: string;
@@ -87,6 +90,13 @@ export type WalrusStakingProgrammableTransaction =
8790
transactions: TransactionType[];
8891
};
8992

93+
export type WalrusWithdrawStakeProgrammableTransaction =
94+
| ProgrammableTransaction
95+
| {
96+
inputs: CallArg[] | TransactionBlockInput[];
97+
transactions: TransactionType[];
98+
};
99+
90100
export interface SuiTransaction<T = SuiProgrammableTransaction> {
91101
id?: string;
92102
type: SuiTransactionType;
@@ -110,6 +120,11 @@ export interface RequestWalrusStakeWithPool {
110120
validatorAddress: SuiAddress;
111121
}
112122

123+
export interface RequestWalrusWithdrawStake {
124+
amount?: number;
125+
stakedWal: SuiObjectRef;
126+
}
127+
113128
/**
114129
* Method names for the transaction method. Names change based on the type of transaction e.g 'request_add_delegation_mul_coin' for the staking transaction
115130
*/
@@ -119,13 +134,13 @@ export enum MethodNames {
119134
*
120135
* @see https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui_system.md#function-request_add_stake
121136
*/
122-
RequestAddStake = 'request_add_stake',
137+
RequestAddStake = '::sui_system::request_add_stake',
123138
/**
124139
* Withdraw some portion of a stake from a validator's staking pool.
125140
*
126141
* @see https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/docs/sui_system.md#function-request_withdraw_stake
127142
*/
128-
RequestWithdrawStake = 'request_withdraw_stake',
143+
RequestWithdrawStake = '::sui_system::request_withdraw_stake',
129144
/**
130145
* Split StakedSui self to two parts, one with principal split_amount, and the remaining principal is left in self.
131146
*
@@ -143,7 +158,19 @@ export enum MethodNames {
143158
*
144159
* @see https://github.com/MystenLabs/walrus-docs/blob/8ba15d67d7ed0e728077e1600866fddd46fd113b/contracts/walrus/sources/staking.move#L289
145160
*/
146-
WalrusStakeWithPool = 'stake_with_pool',
161+
WalrusStakeWithPool = '::staking::stake_with_pool',
162+
/**
163+
* @see https://github.com/MystenLabs/walrus-docs/blob/9307e66df0ea3f6555cdef78d46aefa62737e216/contracts/walrus/sources/staking.move#L221
164+
*/
165+
WalrusRequestWithdrawStake = '::staking::request_withdraw_stake',
166+
/**
167+
* @see https://github.com/MystenLabs/walrus-docs/blob/9307e66df0ea3f6555cdef78d46aefa62737e216/contracts/walrus/sources/staking.move#L231
168+
*/
169+
WalrusWithdrawStake = '::staking::withdraw_stake',
170+
/**
171+
* @see https://github.com/MystenLabs/walrus-docs/blob/9307e66df0ea3f6555cdef78d46aefa62737e216/contracts/walrus/sources/staking/staked_wal.move#L143
172+
*/
173+
WalrusSplitStakedWal = '::staked_wal::split',
147174
}
148175

149176
export interface SuiObjectInfo extends SuiObjectRef {

modules/sdk-coin-sui/src/lib/transaction.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ export abstract class Transaction<T> extends BaseTransaction {
190190
if (transactions.some((tx) => utils.getSuiTransactionType(tx) === SuiTransactionType.WalrusStakeWithPool)) {
191191
return SuiTransactionType.WalrusStakeWithPool;
192192
}
193+
if (transactions.some((tx) => utils.getSuiTransactionType(tx) === SuiTransactionType.WalrusRequestWithdrawStake)) {
194+
return SuiTransactionType.WalrusRequestWithdrawStake;
195+
}
196+
if (transactions.some((tx) => utils.getSuiTransactionType(tx) === SuiTransactionType.WalrusWithdrawStake)) {
197+
return SuiTransactionType.WalrusWithdrawStake;
198+
}
193199
if (transactions.some((tx) => utils.getSuiTransactionType(tx) === SuiTransactionType.AddStake)) {
194200
return SuiTransactionType.AddStake;
195201
}

modules/sdk-coin-sui/src/lib/transactionBuilderFactory.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
SuiProgrammableTransaction,
1414
TokenTransferProgrammableTransaction,
1515
WalrusStakingProgrammableTransaction,
16+
WalrusWithdrawStakeProgrammableTransaction,
1617
} from './iface';
1718
import { StakingTransaction } from './stakingTransaction';
1819
import { TransferTransaction } from './transferTransaction';
@@ -26,6 +27,8 @@ import { TokenTransferBuilder } from './tokenTransferBuilder';
2627
import { TokenTransferTransaction } from './tokenTransferTransaction';
2728
import { WalrusStakingBuilder } from './walrusStakingBuilder';
2829
import { WalrusStakingTransaction } from './walrusStakingTransaction';
30+
import { WalrusWithdrawStakeBuilder } from './walrusWithdrawStakeBuilder';
31+
import { WalrusWithdrawStakeTransaction } from './walrusWithdrawStakeTransaction';
2932

3033
export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
3134
constructor(_coinConfig: Readonly<CoinConfig>) {
@@ -62,6 +65,11 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
6265
const walrusStakeTx = new WalrusStakingTransaction(this._coinConfig);
6366
walrusStakeTx.fromRawTransaction(raw);
6467
return this.getWalrusStakingBuilder(walrusStakeTx);
68+
case SuiTransactionType.WalrusRequestWithdrawStake:
69+
case SuiTransactionType.WalrusWithdrawStake:
70+
const walrusRequestWithdrawStakeTransaction = new WalrusWithdrawStakeTransaction(this._coinConfig);
71+
walrusRequestWithdrawStakeTransaction.fromRawTransaction(raw);
72+
return this.getWalrusRequestWithdrawStakeBuilder(walrusRequestWithdrawStakeTransaction);
6573
default:
6674
throw new InvalidTransactionError('Invalid transaction');
6775
}
@@ -100,6 +108,13 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {
100108
return this.initializeBuilder(tx, new WalrusStakingBuilder(this._coinConfig));
101109
}
102110

111+
/** @inheritdoc */
112+
getWalrusRequestWithdrawStakeBuilder(
113+
tx?: Transaction<WalrusWithdrawStakeProgrammableTransaction>
114+
): WalrusWithdrawStakeBuilder {
115+
return this.initializeBuilder(tx, new WalrusWithdrawStakeBuilder(this._coinConfig));
116+
}
117+
103118
/** @inheritdoc */
104119
getWalletInitializationBuilder(): void {
105120
throw new Error('Method not implemented.');

modules/sdk-coin-sui/src/lib/utils.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ import {
1515
MethodNames,
1616
RequestAddStake,
1717
RequestWalrusStakeWithPool,
18+
RequestWalrusWithdrawStake,
1819
StakingProgrammableTransaction,
1920
WalrusStakingProgrammableTransaction,
21+
WalrusWithdrawStakeProgrammableTransaction,
2022
SuiObjectInfo,
2123
SuiProgrammableTransaction,
2224
SuiTransaction,
@@ -199,7 +201,10 @@ export class Utils implements BaseUtils {
199201
case SuiTransactionType.AddStake:
200202
case SuiTransactionType.WalrusStakeWithPool:
201203
return TransactionType.StakingAdd;
204+
case SuiTransactionType.WalrusRequestWithdrawStake:
205+
return TransactionType.StakingDeactivate;
202206
case SuiTransactionType.WithdrawStake:
207+
case SuiTransactionType.WalrusWithdrawStake:
203208
return TransactionType.StakingWithdraw;
204209
case SuiTransactionType.CustomTx:
205210
return TransactionType.CustomTx;
@@ -238,6 +243,13 @@ export class Utils implements BaseUtils {
238243
return SuiTransactionType.CustomTx;
239244
} else if (command.target.endsWith(MethodNames.WalrusStakeWithPool)) {
240245
return SuiTransactionType.WalrusStakeWithPool;
246+
} else if (
247+
command.target.endsWith(MethodNames.WalrusRequestWithdrawStake) ||
248+
command.target.endsWith(MethodNames.WalrusSplitStakedWal)
249+
) {
250+
return SuiTransactionType.WalrusRequestWithdrawStake;
251+
} else if (command.target.endsWith(MethodNames.WalrusWithdrawStake)) {
252+
return SuiTransactionType.WalrusWithdrawStake;
241253
} else {
242254
throw new InvalidTransactionError(`unsupported target method ${command.target}`);
243255
}
@@ -355,6 +367,47 @@ export class Utils implements BaseUtils {
355367
});
356368
}
357369

370+
getWalrusWithdrawStakeRequests(tx: WalrusWithdrawStakeProgrammableTransaction): RequestWalrusWithdrawStake {
371+
let amount: number | undefined = undefined;
372+
let stakedWal: SuiObjectRef;
373+
let stakedWalInputIdx = -1;
374+
375+
// TS won't let us use filter
376+
const moveCalls: MoveCallTransaction[] = [];
377+
tx.transactions.forEach((transaction) => {
378+
if (transaction.kind === 'MoveCall') {
379+
moveCalls.push(transaction);
380+
}
381+
});
382+
383+
if (moveCalls.length === 1) {
384+
// This is either request_withdraw full or withdraw full (either way, no amount)
385+
stakedWalInputIdx = ((moveCalls[0] as MoveCallTransaction).arguments[1] as TransactionBlockInput).index;
386+
} else if (moveCalls.length === 2) {
387+
// This is request_withdraw partial
388+
const amountInputIdx = ((moveCalls[0] as MoveCallTransaction).arguments[1] as TransactionBlockInput).index;
389+
amount = utils.getAmount(tx.inputs[amountInputIdx] as TransactionBlockInput);
390+
391+
stakedWalInputIdx = ((moveCalls[0] as MoveCallTransaction).arguments[0] as TransactionBlockInput).index;
392+
} else {
393+
throw new InvalidTransactionError('Invalid number of MoveCall transactions');
394+
}
395+
396+
let input = tx.inputs[stakedWalInputIdx];
397+
if ('value' in input) {
398+
input = input.value;
399+
}
400+
if ('Object' in input && isImmOrOwnedObj(input.Object)) {
401+
stakedWal = utils.normalizeSuiObjectRef(input.Object.ImmOrOwned as SuiObjectRef);
402+
} else {
403+
throw new InvalidTransactionError(
404+
`Expected StakedWal object at input index ${stakedWalInputIdx}, found ${input}`
405+
);
406+
}
407+
408+
return { amount, stakedWal };
409+
}
410+
358411
getAmount(input: SuiJsonValue | TransactionBlockInput): number {
359412
return isPureArg(input)
360413
? builder.de(BCS.U64, Buffer.from(new Uint16Array(input.Pure)).toString('base64'), 'base64')

0 commit comments

Comments
 (0)