Skip to content

Commit

Permalink
Merge branch 'master' into lf/feat/math-bn-accept-null
Browse files Browse the repository at this point in the history
  • Loading branch information
LuizAsFight authored Sep 27, 2022
2 parents f613088 + fa83fcd commit cdbafcd
Show file tree
Hide file tree
Showing 16 changed files with 526 additions and 14 deletions.
8 changes: 8 additions & 0 deletions .changeset/strong-hotels-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@fuel-ts/contract": patch
"@fuel-ts/providers": patch
"@fuel-ts/transactions": patch
"@fuel-ts/wallet": patch
---

Added message support
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { NativeAssetId } from '@fuel-ts/constants';
import type { BN } from '@fuel-ts/math';
import { bn, toHex } from '@fuel-ts/math';
import { Provider } from '@fuel-ts/providers';
import { TestUtils } from '@fuel-ts/wallet';
import { Provider, ScriptTransactionRequest } from '@fuel-ts/providers';
import type { Message } from '@fuel-ts/providers';
import { Wallet, TestUtils } from '@fuel-ts/wallet';
import { readFileSync } from 'fs';
import { join } from 'path';

Expand Down Expand Up @@ -346,4 +347,117 @@ describe('Coverage Contract', () => {
};
expect(unhexed).toStrictEqual(last);
});

it('should get initial state messages from node', async () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');

const WALLET_A = new Wallet(
'0x1ff16505df75735a5bcf4cb4cf839903120c181dd9be6781b82cda23543bd242',
provider
);
const WALLET_B = new Wallet(
'0x30bb0bc68f5d2ec3b523cee5a65503031b40679d9c72280cd8088c2cfbc34e38',
provider
);

const EXPECTED_MESSAGES_A: Message[] = [
{
amount: bn(1),
sender: WALLET_B.address,
recipient: WALLET_A.address,
data: [8, 7, 6, 5, 4],
nonce: bn(1),
daHeight: bn(0),
},
];
const EXPECTED_MESSAGES_B: Message[] = [
{
amount: bn('12704439083013451934'),
sender: WALLET_A.address,
recipient: WALLET_B.address,
data: [7],
nonce: bn('1017517292834129547'),
daHeight: bn('3684546456337077810'),
},
];

const aMessages = await WALLET_A.getMessages();
const bMessages = await WALLET_B.getMessages();

expect(aMessages).toStrictEqual(EXPECTED_MESSAGES_A);
expect(bMessages).toStrictEqual(EXPECTED_MESSAGES_B);
});

it('should test sending input messages [1]', async () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');
const request = new ScriptTransactionRequest({ gasLimit: 1000000 });

const sender = await TestUtils.generateTestWallet(provider, [[1_000, NativeAssetId]]);
const receiver = await TestUtils.generateTestWallet(provider);

const messages: Message[] = [
{
amount: bn(900),
sender: sender.address,
recipient: receiver.address,
data: [12, 13, 14],
nonce: bn(823),
daHeight: bn(0),
},
];

request.addMessages(messages);
const response = await sender.sendTransaction(request);

await response.wait();
const receiverMessages = await receiver.getMessages();

expect(receiverMessages).toStrictEqual(messages);
});

it('should test sending input messages [3]', async () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');
const request = new ScriptTransactionRequest({ gasLimit: 1000000 });

const sender = await TestUtils.generateTestWallet(provider, [[1_000, NativeAssetId]]);
const receiver = await TestUtils.generateTestWallet(provider);

const messages: Message[] = [
{
amount: bn(111),
sender: sender.address,
recipient: receiver.address,
data: [11, 11, 11],
nonce: bn(100),
daHeight: bn(0),
},
{
amount: bn(222),
sender: sender.address,
recipient: receiver.address,
data: [22, 22, 22],
nonce: bn(200),
daHeight: bn(0),
},
{
amount: bn(333),
sender: sender.address,
recipient: receiver.address,
data: [33, 33, 33],
nonce: bn(300),
daHeight: bn(0),
},
];

request.addMessages(messages);
const response = await sender.sendTransaction(request);

await response.wait();
const receiverMessages = await receiver.getMessages();

// sort by nonce, messages are not guaranteed in order
receiverMessages.sort((a, b) => a.nonce.toNumber() - b.nonce.toNumber());

expect(receiverMessages).toStrictEqual(messages);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl CoverageContract for Contract {
},
}
}

fn echo_u8(input: u8) -> u8 {
input
}
Expand Down
1 change: 1 addition & 0 deletions packages/providers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export * from './coin-quantity';
export * from './coin';
export * from './provider';
export * from './message';
export { default as Provider } from './provider';
export * from './transaction-request';
export * from './transaction-response';
Expand Down
14 changes: 14 additions & 0 deletions packages/providers/src/message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { AbstractAddress } from '@fuel-ts/interfaces';
import type { BN } from '@fuel-ts/math';

/**
* A Fuel message
*/
export type Message = {
amount: BN;
sender: AbstractAddress;
recipient: AbstractAddress;
data: number[];
daHeight: BN;
nonce: BN;
};
31 changes: 31 additions & 0 deletions packages/providers/src/operations.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ fragment coinFragment on Coin {
blockCreated
}

fragment messageFragment on Message {
amount
sender
recipient
data
nonce
daHeight
}

fragment balanceFragment on Balance {
owner
amount
Expand Down Expand Up @@ -254,6 +263,28 @@ query getBalances(
}
}

query getMessages(
$owner: Address!
$after: String
$before: String
$first: Int
$last: Int
) {
messages(
owner: $owner
after: $after
before: $before
first: $first
last: $last
) {
edges {
node {
...messageFragment
}
}
}
}

mutation dryRun($encodedTransaction: HexString!, $utxoValidation: Boolean) {
dryRun(tx: $encodedTransaction, utxoValidation: $utxoValidation) {
...receiptFragment
Expand Down
30 changes: 30 additions & 0 deletions packages/providers/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { arrayify, hexlify } from '@ethersproject/bytes';
import type { Network } from '@ethersproject/networks';
import type { InputValue } from '@fuel-ts/abi-coder';
import { AbiCoder } from '@fuel-ts/abi-coder';
import { Address } from '@fuel-ts/address';
import { NativeAssetId } from '@fuel-ts/constants';
import type { AbstractAddress, AbstractPredicate } from '@fuel-ts/interfaces';
import type { BigNumberish, BN } from '@fuel-ts/math';
import { max, bn, multiply } from '@fuel-ts/math';
import type { Transaction } from '@fuel-ts/transactions';
import {
InputMessageCoder,
GAS_PRICE_FACTOR,
MAX_GAS_PER_TX,
ReceiptType,
Expand All @@ -28,6 +30,7 @@ import { getSdk as getOperationsSdk } from './__generated__/operations';
import type { Coin } from './coin';
import type { CoinQuantity, CoinQuantityLike } from './coin-quantity';
import { coinQuantityfy } from './coin-quantity';
import type { Message } from './message';
import { ScriptTransactionRequest, transactionRequestify } from './transaction-request';
import type { TransactionRequestLike } from './transaction-request';
import type {
Expand Down Expand Up @@ -507,6 +510,33 @@ export default class Provider {
}));
}

/**
* Returns message for the given address
*/
async getMessages(
/** The address to get message from */
address: AbstractAddress,
/** Pagination arguments */
paginationArgs?: CursorPaginationArgs
): Promise<Message[]> {
const result = await this.operations.getMessages({
first: 10,
...paginationArgs,
owner: address.toB256(),
});

const messages = result.messages.edges!.map((edge) => edge!.node!);

return messages.map((message) => ({
amount: bn(message.amount),
sender: Address.fromAddressOrString(message.sender),
recipient: Address.fromAddressOrString(message.recipient),
data: InputMessageCoder.decodeData(message.data),
daHeight: bn(message.daHeight),
nonce: bn(message.nonce),
}));
}

async buildSpendPredicate(
predicate: AbstractPredicate,
amountToSpend: BigNumberish,
Expand Down
50 changes: 49 additions & 1 deletion packages/providers/src/transaction-request/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,33 @@ export type CoinTransactionRequestInput = {
/** Predicate input data (parameters) */
predicateData?: BytesLike;
};
export type MessageTransactionRequestInput = {
type: InputType.Message;

/** Amount of coins */
amount: BigNumberish;

/** Address of sender */
sender: BytesLike;

/** Address of sender */
recipient: BytesLike;

/** Index of witness that authorizes the message */
witnessIndex: number;

/** data of message */
data: number[];

/** Unique nonce of message */
nonce: BigNumberish;

/** Predicate bytecode */
predicate?: BytesLike;

/** Predicate input data (parameters) */
predicateData?: BytesLike;
};
export type ContractTransactionRequestInput = {
type: InputType.Contract;

Expand All @@ -45,7 +72,10 @@ export type ContractTransactionRequestInput = {
/** Contract ID */
contractId: BytesLike;
};
export type TransactionRequestInput = CoinTransactionRequestInput | ContractTransactionRequestInput;
export type TransactionRequestInput =
| CoinTransactionRequestInput
| ContractTransactionRequestInput
| MessageTransactionRequestInput;

export const inputify = (value: TransactionRequestInput): Input => {
switch (value.type) {
Expand Down Expand Up @@ -89,6 +119,24 @@ export const inputify = (value: TransactionRequestInput): Input => {
contractID: hexlify(value.contractId),
};
}
case InputType.Message: {
const predicate = arrayify(value.predicate ?? '0x');
const predicateData = arrayify(value.predicateData ?? '0x');
return {
type: InputType.Message,
sender: hexlify(value.sender),
recipient: hexlify(value.recipient),
amount: bn(value.amount),
nonce: bn(value.nonce),
witnessIndex: value.witnessIndex,
dataLength: value.data.length,
predicateLength: predicate.length,
predicateDataLength: predicateData.length,
data: value.data,
predicate: hexlify(predicate),
predicateData: hexlify(predicateData),
};
}
default: {
throw new Error('Invalid Input type');
}
Expand Down
26 changes: 26 additions & 0 deletions packages/providers/src/transaction-request/transaction-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import type { Coin } from '../coin';
import type { CoinQuantity, CoinQuantityLike } from '../coin-quantity';
import { coinQuantityfy } from '../coin-quantity';
import type { Message } from '../message';
import { calculatePriceWithFactor } from '../util';

import type {
Expand Down Expand Up @@ -328,6 +329,31 @@ abstract class BaseTransactionRequest implements BaseTransactionRequestLike {
amount: gasFee.isZero() ? bn(1) : gasFee,
};
}

/**
* Converts the given Message to a MessageInput
*/
addMessage(message: Message) {
let witnessIndex = this.getCoinInputWitnessIndexByOwner(message.recipient);

// Insert a dummy witness if no witness exists
if (typeof witnessIndex !== 'number') {
witnessIndex = this.createWitness();
}

// Insert the MessageInput
this.pushInput({
type: InputType.Message,
...message,
sender: message.sender.toBytes(),
recipient: message.recipient.toBytes(),
witnessIndex,
});
}

addMessages(messages: ReadonlyArray<Message>) {
messages.forEach((message) => this.addMessage(message));
}
}

export interface ScriptTransactionRequestLike extends BaseTransactionRequestLike {
Expand Down
1 change: 1 addition & 0 deletions packages/transactions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"license": "Apache-2.0",
"dependencies": {
"@ethersproject/bytes": "^5.4.0",
"@ethersproject/sha2": "^5.5.0",
"@fuel-ts/abi-coder": "workspace:*",
"@fuel-ts/constants": "workspace:*",
"@fuel-ts/math": "workspace:*"
Expand Down
Loading

0 comments on commit cdbafcd

Please sign in to comment.