Skip to content

Commit

Permalink
Convenient Coin APIs (#192)
Browse files Browse the repository at this point in the history
* feat!: add TransactionRequest classes

* feat: add wallet coin APIs

* feat: add CoinQuantity

* feat: add `interfaces` package
  • Loading branch information
AlicanC committed Mar 22, 2022
1 parent be2ce59 commit b19615b
Show file tree
Hide file tree
Showing 34 changed files with 1,208 additions and 433 deletions.
278 changes: 191 additions & 87 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/contract/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@ethersproject/sha2": "^5.6.0",
"@fuel-ts/abi-coder": "^0.4.0",
"@fuel-ts/constants": "^0.4.0",
"@fuel-ts/interfaces": "^0.4.0",
"@fuel-ts/merkle": "^0.4.0",
"@fuel-ts/providers": "^0.4.0",
"@fuel-ts/wallet": "^0.4.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const setup = async (abi: ReadonlyArray<JsonFragment> | Interface = abiJSON) =>

// Create wallet
const wallet = Wallet.generate({ provider });
await seedWallet(wallet, [{ assetId: NativeAssetId, amount: 1 }]);
await seedWallet(wallet, [[1, NativeAssetId]]);

// Deploy contract
const bytecode = readFileSync(join(__dirname, './out/debug/call-test.bin'));
Expand Down
2 changes: 1 addition & 1 deletion packages/contract/src/contract-factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('Contract Factory', () => {
it('creates a factory from inputs', async () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');
const wallet = Wallet.generate({ provider });
await seedWallet(wallet, [{ assetId: NativeAssetId, amount: 1 }]);
await seedWallet(wallet, [[1, NativeAssetId]]);
const bytecode = readFileSync(
join(__dirname, './storage-test-contract/out/debug/storage-test.bin')
);
Expand Down
31 changes: 5 additions & 26 deletions packages/contract/src/contract-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { Logger } from '@ethersproject/logger';
import { randomBytes } from '@ethersproject/random';
import { Interface } from '@fuel-ts/abi-coder';
import type { JsonFragment } from '@fuel-ts/abi-coder';
import { NativeAssetId } from '@fuel-ts/constants';
import { Provider, OutputType, TransactionType, InputType } from '@fuel-ts/providers';
import { Provider, CreateTransactionRequest } from '@fuel-ts/providers';
import { Wallet } from '@fuel-ts/wallet';

import Contract from './contract';
Expand Down Expand Up @@ -52,42 +51,22 @@ export default class ContractFactory {
return logger.throwArgumentError('Cannot deploy without wallet', 'wallet', this.wallet);
}

// Collect enough coins to cover the fees
// TODO: Calculate the correct amount
const feeAmount = 1;
const coins = await this.wallet.provider.getCoinsToSpend(this.wallet.address, [
{ assetId: NativeAssetId, amount: feeAmount },
]);

// TODO: Receive this as a parameter
const storageSlots = [] as [];
const stateRoot = getContractStorageRoot(storageSlots);
const contractId = getContractId(this.bytecode, salt, stateRoot);
const response = await this.wallet.sendTransaction({
type: TransactionType.Create,
const request = new CreateTransactionRequest({
gasPrice: 0,
gasLimit: 1000000,
bytePrice: 0,
bytecodeWitnessIndex: 0,
salt,
storageSlots,
inputs: [
...coins.map((coin) => ({
type: InputType.Coin as const,
...coin,
witnessIndex: 1,
})),
],
outputs: [
{
type: OutputType.ContractCreated,
contractId,
stateRoot,
},
{ type: OutputType.Change, assetId: NativeAssetId, to: this.wallet.address },
],
witnesses: [this.bytecode],
});
request.addContractCreatedOutput(contractId, stateRoot);
await this.wallet.fund(request);
const response = await this.wallet.sendTransaction(request);

await response.wait();

Expand Down
4 changes: 2 additions & 2 deletions packages/contract/src/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('Contract', () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');
const spy = jest.spyOn(provider, 'sendTransaction');
const wallet = Wallet.generate({ provider });
await seedWallet(wallet, [{ assetId: NativeAssetId, amount: 1 }]);
await seedWallet(wallet, [[1, NativeAssetId]]);
const contract = new Contract(ZeroBytes32, [jsonFragment], wallet);
const interfaceSpy = jest.spyOn(contract.interface, 'encodeFunctionData');

Expand All @@ -57,7 +57,7 @@ describe('Contract', () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');
const spy = jest.spyOn(provider, 'sendTransaction');
const wallet = Wallet.generate({ provider });
await seedWallet(wallet, [{ assetId: NativeAssetId, amount: 1 }]);
await seedWallet(wallet, [[1, NativeAssetId]]);
const contract = new Contract(ZeroBytes32, [complexFragment], wallet);
const interfaceSpy = jest.spyOn(contract.interface, 'encodeFunctionData');

Expand Down
73 changes: 17 additions & 56 deletions packages/contract/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import type { BigNumberish } from '@ethersproject/bignumber';
import { Logger } from '@ethersproject/logger';
import type { JsonFragment, FunctionFragment } from '@fuel-ts/abi-coder';
import { Interface } from '@fuel-ts/abi-coder';
import { NativeAssetId } from '@fuel-ts/constants';
import { AbstractContract } from '@fuel-ts/interfaces';
import type { TransactionRequest } from '@fuel-ts/providers';
import { Provider, InputType, OutputType, TransactionType } from '@fuel-ts/providers';
import { ScriptTransactionRequest, Provider } from '@fuel-ts/providers';
import { Wallet } from '@fuel-ts/wallet';

import { contractCallScript } from './scripts';
Expand Down Expand Up @@ -37,27 +37,15 @@ const buildCall = (contract: Contract, func: FunctionFragment): ContractFunction
}

const data = contract.interface.encodeFunctionData(func, args);
const result = await contract.provider.call({
type: TransactionType.Script,
gasPrice: overrides?.gasPrice ?? 0,
const request = new ScriptTransactionRequest({
gasPrice: overrides?.gasPrice,
gasLimit: overrides?.gasLimit ?? 1000000,
bytePrice: overrides?.bytePrice ?? 0,
bytePrice: overrides?.bytePrice,
maturity: overrides?.maturity,
script: contractCallScript.bytes,
scriptData: contractCallScript.encodeScriptData([contract.id, data]),
inputs: [
{
type: InputType.Contract,
contractId: contract.id,
},
],
outputs: [
{
type: OutputType.Contract,
inputIndex: 0,
},
],
});
request.setScript(contractCallScript, [contract.id, data]);
request.addContract(contract);
const result = await contract.provider.call(request);
const encodedResult = contractCallScript.decodeScriptResult(result);
const returnValue = contract.interface.decodeFunctionResult(func, encodedResult)[0];

Expand All @@ -77,53 +65,25 @@ const buildSubmit = (contract: Contract, func: FunctionFragment): ContractFuncti

const data = contract.interface.encodeFunctionData(func, args);

// Collect enough coins to cover the fees
// TODO: Calculate the correct amount
const feeAmount = 1;
const coins = await contract.wallet.provider.getCoinsToSpend(contract.wallet.address, [
{ assetId: NativeAssetId, amount: feeAmount },
]);

// Submit the transaction
const response = await contract.wallet.sendTransaction({
type: TransactionType.Script,
gasPrice: overrides?.gasPrice ?? 0,
const request = new ScriptTransactionRequest({
gasPrice: overrides?.gasPrice,
gasLimit: overrides?.gasLimit ?? 1000000,
bytePrice: overrides?.bytePrice ?? 0,
bytePrice: overrides?.bytePrice,
maturity: overrides?.maturity,
script: contractCallScript.bytes,
scriptData: contractCallScript.encodeScriptData([contract.id, data]),
inputs: [
{
type: InputType.Contract,
contractId: contract.id,
},
...coins.map((coin) => ({
type: InputType.Coin as const,
...coin,
witnessIndex: 0,
})),
],
outputs: [
{
type: OutputType.Contract,
inputIndex: 0,
},
{
type: OutputType.Change,
assetId: NativeAssetId,
to: contract.wallet.address,
},
],
});
request.setScript(contractCallScript, [contract.id, data]);
request.addContract(contract);
await contract.wallet.fund(request);
const response = await contract.wallet.sendTransaction(request);
const result = await response.wait();
const encodedResult = contractCallScript.decodeScriptResult(result);
const returnValue = contract.interface.decodeFunctionResult(func, encodedResult)?.[0];

return returnValue;
};

export default class Contract {
export default class Contract extends AbstractContract {
interface!: Interface;
id!: string;
provider!: Provider | null;
Expand All @@ -141,6 +101,7 @@ export default class Contract {
transactionId?: string,
request?: TransactionRequest
) {
super();
this.interface = abi instanceof Interface ? abi : new Interface(abi);
this.id = id;
this.transaction = transactionId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const setup = async () => {

// Create wallet
const wallet = Wallet.generate({ provider });
await seedWallet(wallet, [{ assetId: NativeAssetId, amount: 1 }]);
await seedWallet(wallet, [[1, NativeAssetId]]);

// Deploy contract
const bytecode = readFileSync(join(__dirname, './out/debug/storage-test.bin'));
Expand Down
3 changes: 3 additions & 0 deletions packages/contract/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
{
"path": "../constants"
},
{
"path": "../interfaces"
},
{
"path": "../merkle"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/example-contract/src/example-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('ExampleContract', () => {
it('should return the input', async () => {
const provider = new Provider('http://127.0.0.1:4000/graphql');
const wallet = Wallet.generate({ provider });
await seedWallet(wallet, [{ assetId: NativeAssetId, amount: 1 }]);
await seedWallet(wallet, [[1, NativeAssetId]]);

// Deploy
const bytecode = fs.readFileSync(path.join(__dirname, '../out/debug/example-contract.bin'));
Expand Down
3 changes: 1 addition & 2 deletions packages/hasher/src/hasher.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ScriptTransactionRequest } from '@fuel-ts/providers';
import signMessageTest from '@fuel-ts/testcases/src/signMessage.json';
import signTransactionTest from '@fuel-ts/testcases/src/signTransaction.json';

Expand All @@ -16,7 +15,7 @@ describe('Hasher', () => {
});

it('Hash script transaction request', async () => {
const transactionRequest: ScriptTransactionRequest = signTransactionTest.transaction;
const transactionRequest = signTransactionTest.transaction;

expect(hashTransaction(transactionRequest)).toEqual(signTransactionTest.hashedTransaction);
});
Expand Down
9 changes: 5 additions & 4 deletions packages/hasher/src/hasher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { BigNumber } from '@ethersproject/bignumber';
import type { BytesLike } from '@ethersproject/bytes';
import { sha256 } from '@ethersproject/sha2';
import { ZeroBytes32 } from '@fuel-ts/constants';
import type { TransactionRequest, UtxoId } from '@fuel-ts/providers';
import type { TransactionRequestLike, UtxoId } from '@fuel-ts/providers';
import {
transactionFromRequest,
transactionRequestify,
OutputType,
InputType,
TransactionCoder,
Expand All @@ -28,9 +28,10 @@ export function hashMessage(msg: string) {
* @param transactionRequest - Transaction request to be hashed
* @returns sha256 hash of the transaction
*/
export function hashTransaction(transactionRequest: TransactionRequest) {
export function hashTransaction(transactionRequestLike: TransactionRequestLike) {
const transactionRequest = transactionRequestify(transactionRequestLike);
// Return a new transaction object without references to the original transaction request
const transaction = transactionFromRequest(transactionRequest);
const transaction = transactionRequest.toTransaction();

if (transaction.type === TransactionType.Script) {
transaction.receiptsRoot = ZeroBytes32;
Expand Down
4 changes: 4 additions & 0 deletions packages/interfaces/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
Loading

0 comments on commit b19615b

Please sign in to comment.