Skip to content

Commit

Permalink
STREAM-554: fix aptos metadata id deriving (#95)
Browse files Browse the repository at this point in the history
* STREAM-554: fix aptos metadata id deriving, separate wallet from types
  • Loading branch information
Yolley authored Oct 12, 2023
1 parent fe6e4d7 commit 7075607
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 101 deletions.
132 changes: 66 additions & 66 deletions packages/stream/aptos/StreamClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from "../common/types";
import { APTOS_PROGRAM_IDS } from "./constants";
import { Contract, ICreateStreamAptosExt, ITransactionAptosExt, StreamResource } from "./types";
import { AptosWalletWrapper } from "./wallet";

export default class AptosStreamClient extends BaseStreamClient {
private programId: string;
Expand Down Expand Up @@ -49,36 +50,19 @@ export default class AptosStreamClient extends BaseStreamClient {
streamData: ICreateStreamData,
{ senderWallet }: ICreateStreamAptosExt
): Promise<ICreateResult> {
const acc = new AptosAccount(); // Generate random address as seeds for derriving "escrow" account
const seeds = acc.address().hex();
const payload = {
type: "create",
function: `${this.programId}::protocol::create`,
type_arguments: [streamData.tokenId],
arguments: [
seeds,
streamData.amount.toString(),
streamData.period,
streamData.amountPerPeriod.toString(),
streamData.start,
streamData.cliffAmount.toString(),
streamData.cancelableBySender,
streamData.cancelableByRecipient,
streamData.transferableBySender,
streamData.transferableByRecipient,
streamData.canTopup,
streamData.canPause || false,
streamData.canUpdateRate || false,
streamData.automaticWithdrawal || false,
streamData.withdrawalFrequency || 0,
streamData.name,
streamData.recipient,
],
};
const wallet = new AptosWalletWrapper(senderWallet, this.client);

const { hash } = await senderWallet.signAndSubmitTransaction(payload);
const [metadataId, payload] = this.generateMultiPayloads(
{
...streamData,
recipients: [{ ...streamData }],
},
wallet
)[0];

return { ixs: [payload], txId: hash, metadataId: seeds };
const hash = await wallet.signAndSubmitTransaction(payload);

return { ixs: [payload], txId: hash, metadataId };
}

/**
Expand All @@ -88,27 +72,28 @@ export default class AptosStreamClient extends BaseStreamClient {
multipleStreamData: ICreateMultipleStreamData,
{ senderWallet }: ICreateStreamAptosExt
): Promise<IMultiTransactionResult> {
const payloads = this.generateMultiPayloads(multipleStreamData);
const wallet = new AptosWalletWrapper(senderWallet, this.client);

const payloads = this.generateMultiPayloads(multipleStreamData, wallet);

const txs: string[] = [];
const metadatas: string[] = [];
const metadataToRecipient: Record<string, IRecipient> = {};
const errors: ICreateMultiError[] = [];

for (let i = 0; i < payloads.length; i++) {
const payload = payloads[i];
const [metadataId, payload] = payloads[i];
const recipient = multipleStreamData.recipients[i];
try {
const { hash } = await senderWallet.signAndSubmitTransaction(payload);
const hash = await wallet.signAndSubmitTransaction(payload);

txs.push(hash);
} catch (e: any) {
errors.push({
error: e?.toString() ?? "Unkown error!",
error: e?.toString() ?? "Unknown error!",
recipient: recipient.recipient,
});
} finally {
const metadataId = payload.arguments[0];
metadatas.push(metadataId);
metadataToRecipient[metadataId] = recipient;
}
Expand All @@ -134,8 +119,9 @@ export default class AptosStreamClient extends BaseStreamClient {
type_arguments: [tokenId],
arguments: [withdrawData.id, withdrawData.amount.toString()],
};
const wallet = new AptosWalletWrapper(senderWallet, this.client);

const { hash } = await senderWallet.signAndSubmitTransaction(payload);
const hash = await wallet.signAndSubmitTransaction(payload);

return { ixs: [payload], txId: hash };
}
Expand All @@ -153,8 +139,9 @@ export default class AptosStreamClient extends BaseStreamClient {
type_arguments: [tokenId],
arguments: [cancelData.id],
};
const wallet = new AptosWalletWrapper(senderWallet, this.client);

const { hash } = await senderWallet.signAndSubmitTransaction(payload);
const hash = await wallet.signAndSubmitTransaction(payload);

return { ixs: [payload], txId: hash };
}
Expand All @@ -172,8 +159,9 @@ export default class AptosStreamClient extends BaseStreamClient {
type_arguments: [tokenId],
arguments: [transferData.id, transferData.newRecipient],
};
const wallet = new AptosWalletWrapper(senderWallet, this.client);

const { hash } = await senderWallet.signAndSubmitTransaction(payload);
const hash = await wallet.signAndSubmitTransaction(payload);

return { ixs: [payload], txId: hash };
}
Expand All @@ -191,8 +179,9 @@ export default class AptosStreamClient extends BaseStreamClient {
type_arguments: [tokenId],
arguments: [topupData.id, topupData.amount.toString()],
};
const wallet = new AptosWalletWrapper(senderWallet, this.client);

const { hash } = await senderWallet.signAndSubmitTransaction(payload);
const hash = await wallet.signAndSubmitTransaction(payload);

return { ixs: [payload], txId: hash };
}
Expand Down Expand Up @@ -228,6 +217,8 @@ export default class AptosStreamClient extends BaseStreamClient {
updateData: IUpdateData,
{ senderWallet, tokenId }: ITransactionAptosExt
): Promise<ITransactionResult> {
const wallet = new AptosWalletWrapper(senderWallet, this.client);

const payload = {
type: "update",
function: `${this.programId}::protocol::update`,
Expand All @@ -240,7 +231,7 @@ export default class AptosStreamClient extends BaseStreamClient {
],
};

const { hash } = await senderWallet.signAndSubmitTransaction(payload);
const hash = await wallet.signAndSubmitTransaction(payload);

return { ixs: [payload], txId: hash };
}
Expand All @@ -258,35 +249,44 @@ export default class AptosStreamClient extends BaseStreamClient {

// Utility function to prepare transaction payloads for multiple recipients.
private generateMultiPayloads(
multipleStreamData: ICreateMultipleStreamData
): Types.TransactionPayload_EntryFunctionPayload[] {
multipleStreamData: ICreateMultipleStreamData,
wallet: AptosWalletWrapper<any>
): [string, Types.TransactionPayload_EntryFunctionPayload][] {
return multipleStreamData.recipients.map((recipient) => {
const acc = new AptosAccount(); // Generate random address as seeds for derriving "escrow" account
const seeds = acc.address().hex();
return {
type: "create",
function: `${this.programId}::protocol::create`,
type_arguments: [multipleStreamData.tokenId],
arguments: [
seeds,
recipient.amount.toString(),
multipleStreamData.period,
recipient.amountPerPeriod.toString(),
multipleStreamData.start,
recipient.cliffAmount.toString(),
multipleStreamData.cancelableBySender,
multipleStreamData.cancelableByRecipient,
multipleStreamData.transferableBySender,
multipleStreamData.transferableByRecipient,
multipleStreamData.canTopup,
multipleStreamData.canPause || false,
multipleStreamData.canUpdateRate || false,
multipleStreamData.automaticWithdrawal || false,
multipleStreamData.withdrawalFrequency || 0,
recipient.name,
recipient.recipient,
],
};
const acc = new AptosAccount(); // Generate random address as seeds for deriving "escrow" account
const seeds = acc.address();
const metadataId = AptosAccount.getResourceAccountAddress(
wallet.address,
seeds.toUint8Array()
);
console.log(seeds);
return [
metadataId.toString(),
{
type: "create",
function: `${this.programId}::protocol::create`,
type_arguments: [multipleStreamData.tokenId],
arguments: [
seeds.toUint8Array(),
recipient.amount.toString(),
multipleStreamData.period,
recipient.amountPerPeriod.toString(),
multipleStreamData.start,
recipient.cliffAmount.toString(),
multipleStreamData.cancelableBySender,
multipleStreamData.cancelableByRecipient,
multipleStreamData.transferableBySender,
multipleStreamData.transferableByRecipient,
multipleStreamData.canTopup,
multipleStreamData.canPause || false,
multipleStreamData.canUpdateRate || false,
multipleStreamData.automaticWithdrawal || false,
multipleStreamData.withdrawalFrequency || 0,
recipient.name,
recipient.recipient,
],
},
];
});
}
}
3 changes: 2 additions & 1 deletion packages/stream/aptos/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AptosAccount } from "aptos";
import { WalletContextState } from "@manahippo/aptos-wallet-adapter";
import BN from "bn.js";

Expand All @@ -6,7 +7,7 @@ import { Stream, StreamType } from "../common/types";
import { getNumberFromBN } from "../common/utils";

export interface ICreateStreamAptosExt {
senderWallet: WalletContextState;
senderWallet: WalletContextState | AptosAccount;
}

export type ITransactionAptosExt = ICreateStreamAptosExt & {
Expand Down
42 changes: 42 additions & 0 deletions packages/stream/aptos/wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
AptosAccount,
AptosClient,
Types,
TransactionBuilderRemoteABI,
MaybeHexString,
} from "aptos";
import { WalletContextState } from "@manahippo/aptos-wallet-adapter";

export class AptosWalletWrapper<T extends WalletContextState | AptosAccount> {
wallet: T;

address: MaybeHexString;

client: AptosClient;

constructor(wallet: T, client: AptosClient) {
this.client = client;
this.wallet = wallet;
if (wallet instanceof AptosAccount) {
this.address = wallet.address();
} else {
this.address = wallet.account!.address!;
}
}

public async signAndSubmitTransaction(
input: Types.TransactionPayload_EntryFunctionPayload
): Promise<string> {
if (this.wallet instanceof AptosAccount) {
const builder = new TransactionBuilderRemoteABI(this.client, {
sender: this.address,
});
const rawTxn = await builder.build(input.function, input.type_arguments, input.arguments);
const signedTx = await this.client.signTransaction(this.wallet, rawTxn);
const tx = await this.client.submitSignedBCSTransaction(signedTx);
await this.client.waitForTransaction(tx.hash);
return tx.hash;
}
return (await this.wallet.signAndSubmitTransaction(input)).hash;
}
}
2 changes: 1 addition & 1 deletion packages/stream/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@streamflow/stream",
"version": "5.3.0",
"version": "5.4.0",
"description": "JavaScript SDK to interact with Streamflow protocol.",
"main": "dist/index.js",
"homepage": "https://github.com/streamflow-finance/js-sdk/",
Expand Down
2 changes: 1 addition & 1 deletion packages/stream/sui/StreamClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import {
ICreateStreamSuiExt,
ITransactionSuiExt,
ISuiIdParameters,
SuiWalletWrapper,
StreamResource,
} from "./types";
import { SuiWalletWrapper } from "./wallet";

export default class SuiStreamClient extends BaseStreamClient {
private programId: string;
Expand Down
32 changes: 0 additions & 32 deletions packages/stream/sui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { WalletContextState } from "@suiet/wallet-kit";
import { TransactionBlock } from "@mysten/sui.js/transactions";
import {
ExecuteTransactionRequestType,
SuiClient,
SuiTransactionBlockResponse,
SuiTransactionBlockResponseOptions,
} from "@mysten/sui.js/client";
import BN from "bn.js";
Expand Down Expand Up @@ -242,33 +240,3 @@ export interface SuiSignAndExecuteTransactionBlockInput {
requestType?: ExecuteTransactionRequestType;
options?: SuiTransactionBlockResponseOptions;
}

export class SuiWalletWrapper<T extends WalletContextState | Keypair> {
wallet: T;

address: string;

client: SuiClient;

constructor(wallet: T, client: SuiClient) {
this.client = client;
this.wallet = wallet;
if (wallet instanceof Keypair) {
this.address = wallet.toSuiAddress();
} else {
this.address = wallet.address!;
}
}

public async signAndExecuteTransactionBlock(
input: SuiSignAndExecuteTransactionBlockInput
): Promise<SuiTransactionBlockResponse> {
if (this.wallet instanceof Keypair) {
return this.client.signAndExecuteTransactionBlock({
...input,
signer: this.wallet,
});
}
return this.wallet.signAndExecuteTransactionBlock(input);
}
}
35 changes: 35 additions & 0 deletions packages/stream/sui/wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Keypair } from "@mysten/sui.js/cryptography";
import { WalletContextState } from "@suiet/wallet-kit";
import { SuiClient, SuiTransactionBlockResponse } from "@mysten/sui.js/client";

import { SuiSignAndExecuteTransactionBlockInput } from "./types";

export class SuiWalletWrapper<T extends WalletContextState | Keypair> {
wallet: T;

address: string;

client: SuiClient;

constructor(wallet: T, client: SuiClient) {
this.client = client;
this.wallet = wallet;
if (wallet instanceof Keypair) {
this.address = wallet.toSuiAddress();
} else {
this.address = wallet.address!;
}
}

public async signAndExecuteTransactionBlock(
input: SuiSignAndExecuteTransactionBlockInput
): Promise<SuiTransactionBlockResponse> {
if (this.wallet instanceof Keypair) {
return this.client.signAndExecuteTransactionBlock({
...input,
signer: this.wallet,
});
}
return this.wallet.signAndExecuteTransactionBlock(input);
}
}

0 comments on commit 7075607

Please sign in to comment.