Skip to content

Commit

Permalink
feat(revokable vaults): init revokeVault and vaultedTransfer commands…
Browse files Browse the repository at this point in the history
… and methods PE-7514
  • Loading branch information
fedellen committed Jan 29, 2025
1 parent 19be835 commit 6ca44a1
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 4 deletions.
23 changes: 21 additions & 2 deletions src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ import {
listArNSReturnedNames,
listGateways,
} from './commands/readCommands.js';
import { transfer } from './commands/transfer.js';
import {
revokeVaultCLICommand,
transferCLICommand,
vaultedTransferCLICommand,
} from './commands/transfer.js';
import {
addressAndVaultIdOptions,
antStateOptions,
Expand All @@ -84,6 +88,7 @@ import {
tokenCostOptions,
transferOptions,
updateGatewaySettingsOptions,
vaultedTransferOptions,
writeActionOptions,
} from './options.js';
import {
Expand Down Expand Up @@ -424,7 +429,21 @@ makeCommand({
name: 'transfer',
description: 'Transfer ARIO to another address',
options: transferOptions,
action: transfer,
action: transferCLICommand,
});

makeCommand({
name: 'vaulted-transfer',
description: 'Transfer ARIO to another address into a locked vault',
options: vaultedTransferOptions,
action: vaultedTransferCLICommand,
});

makeCommand({
name: 'revoke-vault',
description: 'Revoke a vaulted transfer as the controller',
options: [...writeActionOptions, optionMap.vaultId, optionMap.recipient],
action: revokeVaultCLICommand,
});

makeCommand({
Expand Down
98 changes: 96 additions & 2 deletions src/cli/commands/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TransferCLIOptions } from '../types.js';
import {
AoRevokeVaultParams,
AoVaultedTransferParams,
} from '../../types/io.js';
import {
CLIWriteOptionsFromAoParams,
JsonSerializable,
TransferCLIOptions,
} from '../types.js';
import {
assertEnoughMARIOBalance,
confirmationPrompt,
formatARIOWithCommas,
formatMARIOToARIOWithCommas,
requiredMARIOFromOptions,
requiredPositiveIntegerFromOptions,
requiredStringFromOptions,
requiredTargetAndQuantityFromOptions,
writeARIOFromOptions,
writeActionTagsFromOptions,
} from '../utils.js';

export async function transfer(options: TransferCLIOptions) {
export async function transferCLICommand(options: TransferCLIOptions) {
const { target, arioQuantity } =
requiredTargetAndQuantityFromOptions(options);
const { ario, signerAddress } = writeARIOFromOptions(options);
Expand Down Expand Up @@ -59,3 +71,85 @@ export async function transfer(options: TransferCLIOptions) {

return output;
}

export async function vaultedTransferCLICommand(
o: CLIWriteOptionsFromAoParams<AoVaultedTransferParams>,
): Promise<JsonSerializable> {
const mARIOQuantity = requiredMARIOFromOptions(o, 'quantity');
const recipient = requiredStringFromOptions(o, 'recipient');
const { ario, signerAddress } = writeARIOFromOptions(o);
const lockLengthMs = requiredPositiveIntegerFromOptions(o, 'lockLengthMs');

if (!o.skipConfirmation) {
await assertEnoughMARIOBalance({
ario,
address: signerAddress,
mARIOQuantity,
});

const confirm = await confirmationPrompt(
`Are you sure you want transfer ${formatMARIOToARIOWithCommas(mARIOQuantity)} ARIO to ${recipient}, locked in a ${o.revokable ? 'non-' : ''}revokable vault for ${lockLengthMs}ms?`,
);
if (!confirm) {
return { message: 'Transfer aborted by user' };
}
}

const result = await ario.vaultedTransfer(
{
recipient,
quantity: mARIOQuantity,
lockLengthMs,
revokable: o.revokable,
},
writeActionTagsFromOptions(o),
);

const output = {
senderAddress: signerAddress,
transferResult: result,
message: `Successfully vaulted transferred ${formatMARIOToARIOWithCommas(mARIOQuantity)} ARIO to ${recipient}`,
};

return output;
}

export async function revokeVaultCLICommand(
o: CLIWriteOptionsFromAoParams<AoRevokeVaultParams>,
): Promise<JsonSerializable> {
const { ario, signerAddress } = writeARIOFromOptions(o);
const vaultId = requiredStringFromOptions(o, 'vaultId');
const recipient = requiredStringFromOptions(o, 'recipient');

if (!o.skipConfirmation) {
const vault = await ario.getVault({ vaultId, address: recipient });
if (!vault) {
throw new Error(
`Vault for recipient '${recipient}' with vault id '${vaultId}' not found`,
);
}

const confirm = await confirmationPrompt(
`Are you sure you want to revoke vault with id ${vaultId} from ${recipient}?`,
);
if (!confirm) {
return { message: 'Revoke aborted by user' };
}
}

const result = await ario.revokeVault(
{
vaultId,
recipient,
},
writeActionTagsFromOptions(o),
);

const output = {
senderAddress: signerAddress,
transferResult: result,
message: `Successfully revoked vault with id ${vaultId}`,
};

return output;
}
22 changes: 22 additions & 0 deletions src/cli/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,20 @@ export const optionMap = {
description:
'Where to fund the action from. e.g. "balance", "stakes", or "any',
},
revokable: {
alias: '--revokable',
description:
'Whether the vaulted transfer is revokable by the sender. Defaults to false',
type: 'boolean',
},
lockLengthMs: {
alias: '--lock-length-ms <lockLengthMs>',
description: 'The length of time in milliseconds to lock the transfer for',
},
recipient: {
alias: '--recipient <recipient>',
description: 'The recipient to interact with',
},
};

export const walletOptions = [
Expand Down Expand Up @@ -303,6 +317,14 @@ export const transferOptions = [
optionMap.target,
];

export const vaultedTransferOptions = [
...writeActionOptions,
optionMap.quantity,
optionMap.recipient,
optionMap.lockLengthMs,
optionMap.revokable,
];

export const operatorStakeOptions = [
...writeActionOptions,
optionMap.operatorStake,
Expand Down
7 changes: 7 additions & 0 deletions src/cli/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,13 @@ export function writeANTFromOptions(
});
}

export function booleanFromOptions<O extends GlobalCLIOptions>(
options: O,
key: string,
): boolean {
return !!options[key];
}

export function requiredStringFromOptions<O extends GlobalCLIOptions>(
options: O,
key: string,
Expand Down
42 changes: 42 additions & 0 deletions src/common/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ import {
AoIncreaseUndernameLimitParams,
AoPaginatedAddressParams,
AoRegistrationFees,
AoRevokeVaultParams,
AoTokenCostParams,
AoVaultData,
AoVaultedTransferParams,
AoWalletVault,
CostDetailsResult,
DemandFactorSettings,
Expand Down Expand Up @@ -770,6 +772,46 @@ export class ARIOWriteable extends ARIOReadable implements AoARIOWrite {
});
}

async vaultedTransfer(
{
recipient,
quantity,
lockLengthMs,
revokable = false,
}: AoVaultedTransferParams,
options?: WriteOptions,
): Promise<AoMessageResult> {
const { tags = [] } = options || {};

return this.process.send({
tags: [
...tags,
{ name: 'Action', value: 'Vaulted-Transfer' },
{ name: 'Recipient', value: recipient },
{ name: 'Quantity', value: quantity.toString() },
{ name: 'Lock-Length', value: lockLengthMs.toString() },
{ name: 'Revokable', value: `${revokable}` },
],
signer: this.signer,
});
}

async revokeVault(
{ vaultId, recipient }: AoRevokeVaultParams,
options?: WriteOptions,
): Promise<AoMessageResult> {
const { tags = [] } = options || {};
return this.process.send({
tags: [
...tags,
{ name: 'Action', value: 'Revoke-Vault' },
{ name: 'Vault-Id', value: vaultId },
{ name: 'Recipient', value: recipient },
],
signer: this.signer,
});
}

async joinNetwork(
{
operatorStake,
Expand Down
21 changes: 21 additions & 0 deletions src/types/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,18 @@ export type AoIncreaseUndernameLimitParams = AoArNSPurchaseParams & {
increaseCount: number;
};

export type AoVaultedTransferParams = {
recipient: WalletAddress;
quantity: mARIOToken | number;
lockLengthMs: number;
revokable?: boolean;
};

export type AoRevokeVaultParams = {
vaultId: TransactionId;
recipient: WalletAddress;
};

export type AoGatewayRegistrySettings = {
delegates: {
minStake: number;
Expand Down Expand Up @@ -625,6 +637,15 @@ export interface AoARIOWrite extends AoARIORead {
},
options?: WriteOptions,
): Promise<AoMessageResult>;
vaultedTransfer(
{ recipient, quantity, lockLengthMs, revokable }: AoVaultedTransferParams,
options?: WriteOptions,
): Promise<AoMessageResult>;
revokeVault(
{ vaultId, recipient }: AoRevokeVaultParams,
options?: WriteOptions,
): Promise<AoMessageResult>;

// TODO: these could be moved to a separate Gateways class that implements gateway specific interactions
joinNetwork(
params: AoJoinNetworkParams,
Expand Down

0 comments on commit 6ca44a1

Please sign in to comment.