Skip to content
Merged
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
51 changes: 28 additions & 23 deletions modules/abstract-substrate/src/lib/iface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,70 +17,74 @@ export enum SectionNames {

/**
* Method names for the transaction method. Names change based on the type of transaction e.g 'bond' for the staking transaction
*
* This is implemented as a const object with string literals to allow for extension in derived modules.
*/
export enum MethodNames {
export const MethodNames = {
/**
* Transfer the entire transferable balance from the caller account.
*
* @see https://polkadot.js.org/docs/substrate/extrinsics/#transferalldest-multiaddress-keep_alive-bool
*/
TransferAll = 'transferAll',
TransferAll: 'transferAll' as const,
/**
* Same as the transfer call, but with a check that the transfer will not kill the origin account.
*
* @see https://polkadot.js.org/docs/substrate/extrinsics/#transferkeepalivedest-multiaddress-value-compactu128
*/
TransferKeepAlive = 'transferKeepAlive',
TransferKeepAlive: 'transferKeepAlive' as const,
/**
* Transfer funds with an optional memo attached.
* The memo allows adding context or metadata to the transaction, commonly used for recordkeeping or identification.
*
* @see https://developers.polymesh.network/sdk-docs/enums/Generated/Types/BalancesTx/#transferwithmemo
*/
TransferWithMemo = 'transferWithMemo',
AddStake = 'addStake',
RemoveStake = 'removeStake',

TransferWithMemo: 'transferWithMemo' as const,
AddStake: 'addStake' as const,
RemoveStake: 'removeStake' as const,
/**
* Take the origin account as a stash and lock up value of its balance.
*/
Bond = 'bond',
Bond: 'bond' as const,
/**
* Add some extra amount that have appeared in the stash free_balance into the balance up for staking.
*/
BondExtra = 'bondExtra',
BondExtra: 'bondExtra' as const,
/**
* Declare the desire to nominate targets for the origin controller.
*/
Nominate = 'nominate',
Nominate: 'nominate' as const,
/**
* Declare no desire to either validate or nominate.
*/
Chill = 'chill',
Chill: 'chill' as const,
/**
* Schedule a portion of the stash to be unlocked ready for transfer out after the bond period ends.
*/
Unbond = 'unbond',
Unbond: 'unbond' as const,
/**
* Remove any unlocked chunks from the unlocking queue from our management.
*/
WithdrawUnbonded = 'withdrawUnbonded',
WithdrawUnbonded: 'withdrawUnbonded' as const,
/**
* Send a batch of dispatch calls.
*/
Batch = 'batch',
Batch: 'batch' as const,
/**
* Send a batch of dispatch calls and atomically execute them.
*/
BatchAll = 'batchAll',
BatchAll: 'batchAll' as const,
} as const;

/**
* Registers a Decentralized Identifier (DID) along with Customer Due Diligence (CDD) information.
*
* @see https://developers.polymesh.network/sdk-docs/enums/Generated/Types/IdentityTx/#cddregisterdidwithcdd
*/
RegisterDidWithCDD = 'cddRegisterDidWithCdd',
}
/**
* Type representing the keys of the MethodNames object
*/
export type MethodNamesType = keyof typeof MethodNames;

/**
* Type representing the values of the MethodNames object
*/
export type MethodNamesValues = (typeof MethodNames)[MethodNamesType];

/**
* The transaction data returned from the toJson() function of a transaction
Expand All @@ -106,6 +110,7 @@ export interface TxData {
netuid?: string;
numSlashingSpans?: number;
batchCalls?: BatchCallObject[];
memo?: string;
}

/**
Expand Down Expand Up @@ -193,7 +198,7 @@ export interface TxMethod {
| UnbondArgs
| WithdrawUnbondedArgs
| BatchArgs;
name: MethodNames;
name: MethodNamesValues;
pallet: string;
}

Expand Down
9 changes: 6 additions & 3 deletions modules/abstract-substrate/src/lib/nativeTransferBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,16 @@ export abstract class NativeTransferBuilder extends TransactionBuilder {
/** @inheritdoc */
protected fromImplementation(rawTransaction: string): Transaction {
const tx = super.fromImplementation(rawTransaction);
if (this._method?.name === MethodNames.TransferKeepAlive) {
if (!this._method || !this._method.args) {
throw new InvalidTransactionError('Transaction method or args are undefined');
}
if (this._method.name === MethodNames.TransferKeepAlive) {
const txMethod = this._method.args as TransferArgs;
this.amount(txMethod.value);
this.to({
address: utils.decodeSubstrateAddress(txMethod.dest.id, this.getAddressFormat()),
});
} else if (this._method?.name === MethodNames.TransferAll) {
} else if (this._method.name === MethodNames.TransferAll) {
this._sweepFreeBalance = true;
const txMethod = this._method.args as TransferAllArgs;
this.sweep(txMethod.keepAlive);
Expand All @@ -136,7 +139,7 @@ export abstract class NativeTransferBuilder extends TransactionBuilder {
});
} else {
throw new InvalidTransactionError(
`Invalid Transaction Type: ${this._method?.name}. Expected a transferKeepAlive or a proxy transferKeepAlive transaction`
`Invalid Transaction Type: ${this._method.name}. Expected a transferKeepAlive or a proxy transferKeepAlive transaction`
);
}
return tx;
Expand Down
82 changes: 80 additions & 2 deletions modules/sdk-coin-polyx/src/lib/iface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,88 @@ import { DecodedUnsignedTx } from '@substrate/txwrapper-core/lib/types';

export type AnyJson = string | number | boolean | null | { [key: string]: AnyJson } | Array<AnyJson>;

/**
* Extended TxData interface for Polyx transactions
* Adds assetId field to the base TxData interface from abstract-substrate
*/
export interface TxData extends Interface.TxData {
assetId?: string;
fromDID?: string;
toDID?: string;
}

/**
* Settlement type for Polyx transactions
*/
export enum SettlementType {
SettleOnAffirmation = 'SettleOnAffirmation',
}

/**
* Portfolio kind for Polyx transactions
*/
export enum PortfolioKind {
Default = 'Default',
}

/**
* Method names for Polyx transactions.
* Extends the base MethodNames from Interface with additional Polyx-specific methods.
*/
export const MethodNames = {
// Include all values from the base object
...Interface.MethodNames,

/**
* Registers a Decentralized Identifier (DID) along with Customer Due Diligence (CDD) information.
*
* @see https://developers.polymesh.network/sdk-docs/enums/Generated/Types/IdentityTx/#cddregisterdidwithcdd
*/
RegisterDidWithCDD: 'cddRegisterDidWithCdd' as const,

/**
* Pre-approves an asset.
*/
PreApproveAsset: 'preApproveAsset' as const,

AddAndAffirmWithMediators: 'addAndAffirmWithMediators' as const,
} as const;

// Create a type that represents the keys of this object
export type MethodNamesType = keyof typeof MethodNames;

// Create a type that represents the values of this object
export type MethodNamesValues = (typeof MethodNames)[MethodNamesType];

export interface RegisterDidWithCDDArgs extends Args {
targetAccount: string;
secondaryKeys: [];
expiry: null;
}

export interface TxMethod extends Omit<Interface.TxMethod, 'args'> {
export interface PreApproveAssetArgs extends Args {
assetId: string;
}

export interface AddAndAffirmWithMediatorsArgs extends Args {
venueId: null;
settlementType: SettlementType.SettleOnAffirmation;
tradeDate: null;
valueDate: null;
legs: Array<{
fungible: {
sender: { did: string; kind: PortfolioKind.Default };
receiver: { did: string; kind: PortfolioKind.Default };
assetId: string;
amount: string;
};
}>;
portfolios: Array<{ did: string; kind: PortfolioKind.Default }>;
instructionMemo: string;
mediators: [];
}

export interface TxMethod extends Omit<Interface.TxMethod, 'args' | 'name'> {
args:
| Interface.TransferArgs
| Interface.TransferAllArgs
Expand All @@ -23,7 +98,10 @@ export interface TxMethod extends Omit<Interface.TxMethod, 'args'> {
| Interface.UnbondArgs
| Interface.WithdrawUnbondedArgs
| Interface.BatchArgs
| RegisterDidWithCDDArgs;
| RegisterDidWithCDDArgs
| PreApproveAssetArgs
| AddAndAffirmWithMediatorsArgs;
name: MethodNamesValues;
}

export interface DecodedTx extends Omit<DecodedUnsignedTx, 'method'> {
Expand Down
2 changes: 2 additions & 0 deletions modules/sdk-coin-polyx/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export { TransactionBuilderFactory } from './transactionBuilderFactory';
export { PolyxBaseBuilder } from './baseBuilder';
export { TransferBuilder } from './transferBuilder';
export { RegisterDidWithCDDBuilder } from './registerDidWithCDDBuilder';
export { PreApproveAssetBuilder } from './preApproveAssetBuilder';
export { TokenTransferBuilder } from './tokenTransferBuilder';
export { Transaction as PolyxTransaction } from './transaction';
export { BondExtraBuilder } from './bondExtraBuilder';
export { BatchStakingBuilder as BatchBuilder } from './batchStakingBuilder';
Expand Down
90 changes: 90 additions & 0 deletions modules/sdk-coin-polyx/src/lib/preApproveAssetBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { TransactionType, InvalidTransactionError } from '@bitgo/sdk-core';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { DecodedSignedTx, DecodedSigningPayload, defineMethod, UnsignedTransaction } from '@substrate/txwrapper-core';
import { Interface } from '@bitgo/abstract-substrate';
import { PolyxBaseBuilder } from './baseBuilder';
import { TxMethod, PreApproveAssetArgs, MethodNames } from './iface';
import { PreApproveAssetTransactionSchema } from './txnSchema';
import { Transaction } from './transaction';

export class PreApproveAssetBuilder extends PolyxBaseBuilder<TxMethod, Transaction> {
protected _assetId: string;
protected _method: TxMethod;

constructor(_coinConfig: Readonly<CoinConfig>) {
super(_coinConfig);
this._transaction = new Transaction(_coinConfig);
}

protected get transactionType(): TransactionType {
return TransactionType.TrustLine;
}

protected buildTransaction(): UnsignedTransaction {
const baseTxInfo = this.createBaseTxInfo();
return this.preApproveAsset(
{
assetId: this._assetId,
},
baseTxInfo
);
}

/**
* Sets the asset ID for the pre-approval transaction.
*
* @param {string} assetId - The ID of the asset to be pre-approved.
* @returns {this} The current instance of the builder.
*/
assetId(assetId: string): this {
this._assetId = assetId;
return this;
}

/** @inheritdoc */
protected fromImplementation(rawTransaction: string): Transaction {
const tx = super.fromImplementation(rawTransaction);
if (this._method?.name === MethodNames.PreApproveAsset) {
const txMethod = this._method.args as PreApproveAssetArgs;
this.assetId(txMethod.assetId);
} else {
throw new InvalidTransactionError(`Invalid Transaction Type: ${this._method?.name}. Expected preApproveAsset`);
}
return tx;
}

/** @inheritdoc */
validateDecodedTransaction(decodedTxn: DecodedSigningPayload | DecodedSignedTx, rawTransaction?: string): void {
if (decodedTxn.method?.name === MethodNames.PreApproveAsset) {
const txMethod = decodedTxn.method.args as PreApproveAssetArgs;
const assetId = txMethod.assetId;

const validationResult = PreApproveAssetTransactionSchema.validate({ assetId });
if (!validationResult) {
throw new InvalidTransactionError('Invalid transaction: assetId is required');
}
}
}

/**
* Construct a transaction to pre-approve an asset
*
* @param {PreApproveAssetArgs} args Arguments to be passed to the preApproveAsset method
* @param {Interface.CreateBaseTxInfo} info Base txn info required to construct the pre-approve asset txn
* @returns {UnsignedTransaction} an unsigned transaction for asset pre-approval
*/
private preApproveAsset(args: PreApproveAssetArgs, info: Interface.CreateBaseTxInfo): UnsignedTransaction {
console.log(`PreApproveAssetBuilder: preApproveAsset called with args: ${JSON.stringify(args)}`);
return defineMethod(
{
method: {
args,
name: 'preApproveAsset',
pallet: 'asset',
},
...info.baseTxInfo,
},
info.options
);
}
}
8 changes: 4 additions & 4 deletions modules/sdk-coin-polyx/src/lib/registerDidWithCDDBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PolyxBaseBuilder } from './baseBuilder';
import { DecodedSignedTx, DecodedSigningPayload, defineMethod, UnsignedTransaction } from '@substrate/txwrapper-core';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { TransactionType, BaseAddress, InvalidTransactionError } from '@bitgo/sdk-core';
import { RegisterDidWithCDDArgs, TxMethod } from './iface';
import { RegisterDidWithCDDArgs, TxMethod, MethodNames } from './iface';
import { RegisterDidWithCDDTransactionSchema } from './txnSchema';
import { Transaction } from './transaction';

Expand Down Expand Up @@ -48,18 +48,18 @@ export class RegisterDidWithCDDBuilder extends PolyxBaseBuilder<TxMethod, Transa
/** @inheritdoc */
protected fromImplementation(rawTransaction: string): Transaction {
const tx = super.fromImplementation(rawTransaction);
if (this._method?.name === Interface.MethodNames.RegisterDidWithCDD) {
if (this._method?.name === MethodNames.RegisterDidWithCDD) {
const txMethod = this._method.args as RegisterDidWithCDDArgs;
this.to({ address: utils.decodeSubstrateAddress(txMethod.targetAccount, this.getAddressFormat()) });
} else {
throw new InvalidTransactionError(`Invalid Transaction Type: ${this._method?.name}. Expected transferWithMemo`);
throw new InvalidTransactionError(`Invalid Transaction Type: ${this._method?.name}. Expected RegisterDidWithCDD`);
}
return tx;
}

/** @inheritdoc */
validateDecodedTransaction(decodedTxn: DecodedSigningPayload | DecodedSignedTx, rawTransaction?: string): void {
if (decodedTxn.method?.name === Interface.MethodNames.RegisterDidWithCDD) {
if (decodedTxn.method?.name === MethodNames.RegisterDidWithCDD) {
const txMethod = decodedTxn.method.args as RegisterDidWithCDDArgs;
const targetAccount = txMethod.targetAccount;
const secondaryKeys = txMethod.secondaryKeys;
Expand Down
Loading