Skip to content

Commit

Permalink
Merge branch 'rc/salamander' into db/chore/format-coverage-report
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbate authored Dec 22, 2023
2 parents 9346b9d + 8d84846 commit 4dba236
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 48 deletions.
7 changes: 7 additions & 0 deletions .changeset/soft-falcons-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@fuel-ts/providers": minor
"@fuel-ts/wallet": minor
"@fuel-ts/wallet-manager": minor
---

accepting string as address instead of only AbstractAddress
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe(__filename, () => {
});

const tx2 = await predicate.transfer(
receiverWallet.address,
receiverWallet.address.toB256(),
amountToPredicate - 1000,
BaseAssetId,
{
Expand Down
2 changes: 1 addition & 1 deletion packages/fuel-gauge/src/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ describe('Contract', () => {

const amountToContract = 100;

const tx = await wallet.transferToContract(contract.id, amountToContract, asset, {
const tx = await wallet.transferToContract(contract.id.toB256(), amountToContract, asset, {
gasPrice,
gasLimit: 10_000,
});
Expand Down
33 changes: 18 additions & 15 deletions packages/providers/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -843,16 +843,17 @@ export default class Provider {
}

async getResourcesForTransaction(
owner: AbstractAddress,
owner: string | AbstractAddress,
transactionRequestLike: TransactionRequestLike,
forwardingQuantities: CoinQuantity[] = []
) {
const ownerAddress = Address.fromAddressOrString(owner);
const transactionRequest = transactionRequestify(clone(transactionRequestLike));
const transactionCost = await this.getTransactionCost(transactionRequest, forwardingQuantities);

// Add the required resources to the transaction from the owner
transactionRequest.addResources(
await this.getResourcesToSpend(owner, transactionCost.requiredQuantities)
await this.getResourcesToSpend(ownerAddress, transactionCost.requiredQuantities)
);
// Refetch transaction costs with the new resources
// TODO: we could find a way to avoid fetch estimatePredicates again, by returning the transaction or
Expand All @@ -864,7 +865,7 @@ export default class Provider {
transactionRequest,
forwardingQuantities
);
const resources = await this.getResourcesToSpend(owner, requiredQuantities);
const resources = await this.getResourcesToSpend(ownerAddress, requiredQuantities);

return {
resources,
Expand All @@ -878,16 +879,17 @@ export default class Provider {
*/
async getCoins(
/** The address to get coins for */
owner: AbstractAddress,
owner: string | AbstractAddress,
/** The asset ID of coins to get */
assetId?: BytesLike,
/** Pagination arguments */
paginationArgs?: CursorPaginationArgs
): Promise<Coin[]> {
const ownerAddress = Address.fromAddressOrString(owner);
const result = await this.operations.getCoins({
first: 10,
...paginationArgs,
filter: { owner: owner.toB256(), assetId: assetId && hexlify(assetId) },
filter: { owner: ownerAddress.toB256(), assetId: assetId && hexlify(assetId) },
});

const coins = result.coins.edges.map((edge) => edge.node);
Expand All @@ -913,12 +915,13 @@ export default class Provider {
*/
async getResourcesToSpend(
/** The address to get coins for */
owner: AbstractAddress,
owner: string | AbstractAddress,
/** The quantities to get */
quantities: CoinQuantityLike[],
/** IDs of excluded resources from the selection. */
excludedIds?: ExcludeResourcesOption
): Promise<Resource[]> {
const ownerAddress = Address.fromAddressOrString(owner);
const excludeInput = {
messages: excludedIds?.messages?.map((nonce) => hexlify(nonce)) || [],
utxos: excludedIds?.utxos?.map((id) => hexlify(id)) || [],
Expand All @@ -931,7 +934,7 @@ export default class Provider {
excludeInput.utxos = Array.from(uniqueUtxos);
}
const coinsQuery = {
owner: owner.toB256(),
owner: ownerAddress.toB256(),
queryPerAsset: quantities
.map(coinQuantityfy)
.map(({ assetId, amount, max: maxPerAsset }) => ({
Expand Down Expand Up @@ -1108,12 +1111,12 @@ export default class Provider {
*/
async getContractBalance(
/** The contract ID to get the balance for */
contractId: AbstractAddress,
contractId: string | AbstractAddress,
/** The asset ID of coins to get */
assetId: BytesLike
): Promise<BN> {
const { contractBalance } = await this.operations.getContractBalance({
contract: contractId.toB256(),
contract: Address.fromAddressOrString(contractId).toB256(),
asset: hexlify(assetId),
});
return bn(contractBalance.amount, 10);
Expand All @@ -1128,12 +1131,12 @@ export default class Provider {
*/
async getBalance(
/** The address to get coins for */
owner: AbstractAddress,
owner: string | AbstractAddress,
/** The asset ID of coins to get */
assetId: BytesLike
): Promise<BN> {
const { balance } = await this.operations.getBalance({
owner: owner.toB256(),
owner: Address.fromAddressOrString(owner).toB256(),
assetId: hexlify(assetId),
});
return bn(balance.amount, 10);
Expand All @@ -1148,14 +1151,14 @@ export default class Provider {
*/
async getBalances(
/** The address to get coins for */
owner: AbstractAddress,
owner: string | AbstractAddress,
/** Pagination arguments */
paginationArgs?: CursorPaginationArgs
): Promise<CoinQuantity[]> {
const result = await this.operations.getBalances({
first: 10,
...paginationArgs,
filter: { owner: owner.toB256() },
filter: { owner: Address.fromAddressOrString(owner).toB256() },
});

const balances = result.balances.edges.map((edge) => edge.node);
Expand All @@ -1175,14 +1178,14 @@ export default class Provider {
*/
async getMessages(
/** The address to get message from */
address: AbstractAddress,
address: string | AbstractAddress,
/** Pagination arguments */
paginationArgs?: CursorPaginationArgs
): Promise<Message[]> {
const result = await this.operations.getMessages({
first: 10,
...paginationArgs,
owner: address.toB256(),
owner: Address.fromAddressOrString(address).toB256(),
});

const messages = result.messages.edges.map((edge) => edge.node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,9 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi
* @param address - The address to get the coin input witness index for.
* @param signature - The signature to update the witness with.
*/
updateWitnessByOwner(address: AbstractAddress, signature: BytesLike) {
const witnessIndex = this.getCoinInputWitnessIndexByOwner(address);
updateWitnessByOwner(address: string | AbstractAddress, signature: BytesLike) {
const ownerAddress = Address.fromAddressOrString(address);
const witnessIndex = this.getCoinInputWitnessIndexByOwner(ownerAddress);
if (typeof witnessIndex === 'number') {
this.updateWitness(witnessIndex, signature);
}
Expand Down
22 changes: 22 additions & 0 deletions packages/providers/test/provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1096,4 +1096,26 @@ describe('Provider', () => {
expect(usedFee.eq(0)).not.toBeTruthy();
expect(minFee.eq(0)).not.toBeTruthy();
});

it('should accept string addresses in methods that require an address', async () => {
const provider = await Provider.create(FUEL_NETWORK_URL);

const b256Str = Address.fromRandom().toB256();

const methodCalls = [
() => provider.getBalance(b256Str, BaseAssetId),
() => provider.getCoins(b256Str),
() => provider.getResourcesForTransaction(b256Str, new ScriptTransactionRequest()),
() => provider.getResourcesToSpend(b256Str, []),
() => provider.getContractBalance(b256Str, BaseAssetId),
() => provider.getBalances(b256Str),
() => provider.getMessages(b256Str),
];

const promises = methodCalls.map(async (call) => {
await expect(call()).resolves.toBeTruthy();
});

await Promise.all(promises);
});
});
4 changes: 3 additions & 1 deletion packages/wallet-manager/src/vaults/mnemonic-vault.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ describe('MnemonicVault', () => {

vault.addAccount();

expect(vault.getWallet(wallet.address).publicKey).toBe(walletManagerSpec.account_0.publicKey);
expect(vault.getWallet(wallet.address.toString()).publicKey).toBe(
walletManagerSpec.account_0.publicKey
);
});

it('Check if accounts are been added correctly', async () => {
Expand Down
9 changes: 5 additions & 4 deletions packages/wallet-manager/src/vaults/mnemonic-vault.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Address } from '@fuel-ts/address';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import type { AbstractAddress } from '@fuel-ts/interfaces';
import { Mnemonic } from '@fuel-ts/mnemonic';
Expand Down Expand Up @@ -82,17 +83,17 @@ export class MnemonicVault implements Vault<MnemonicVaultOptions> {
};
}

exportAccount(address: AbstractAddress): string {
exportAccount(address: string | AbstractAddress): string {
let numberOfAccounts = 0;

const ownerAddress = Address.fromAddressOrString(address);
// Look for the account that has the same address
do {
const wallet = Wallet.fromMnemonic(
this.#secret,
this.provider,
this.getDerivePath(numberOfAccounts)
);
if (wallet.address.equals(address)) {
if (wallet.address.equals(ownerAddress)) {
return wallet.privateKey;
}
numberOfAccounts += 1;
Expand All @@ -104,7 +105,7 @@ export class MnemonicVault implements Vault<MnemonicVaultOptions> {
);
}

getWallet(address: AbstractAddress): WalletUnlocked {
getWallet(address: string | AbstractAddress): WalletUnlocked {
const privateKey = this.exportAccount(address);
return Wallet.fromPrivateKey(privateKey, this.provider);
}
Expand Down
8 changes: 5 additions & 3 deletions packages/wallet-manager/src/vaults/privatekey-vault.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Address } from '@fuel-ts/address';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import type { AbstractAddress } from '@fuel-ts/interfaces';
import type { Provider } from '@fuel-ts/providers';
Expand Down Expand Up @@ -64,9 +65,10 @@ export class PrivateKeyVault implements Vault<PkVaultOptions> {
return this.getPublicAccount(wallet.privateKey);
}

exportAccount(address: AbstractAddress): string {
exportAccount(address: string | AbstractAddress): string {
const ownerAddress = Address.fromAddressOrString(address);
const privateKey = this.#privateKeys.find((pk) =>
Wallet.fromPrivateKey(pk, this.provider).address.equals(address)
Wallet.fromPrivateKey(pk, this.provider).address.equals(ownerAddress)
);

if (!privateKey) {
Expand All @@ -79,7 +81,7 @@ export class PrivateKeyVault implements Vault<PkVaultOptions> {
return privateKey;
}

getWallet(address: AbstractAddress): WalletUnlocked {
getWallet(address: string | AbstractAddress): WalletUnlocked {
const privateKey = this.exportAccount(address);
return Wallet.fromPrivateKey(privateKey, this.provider);
}
Expand Down
15 changes: 9 additions & 6 deletions packages/wallet-manager/src/wallet-manager.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Address } from '@fuel-ts/address';
import type { Keystore } from '@fuel-ts/crypto';
import { encrypt, decrypt } from '@fuel-ts/crypto';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
Expand Down Expand Up @@ -110,26 +111,28 @@ export class WalletManager extends EventEmitter {
/**
* Create a Wallet instance for the specific account
*/
getWallet(address: AbstractAddress): WalletUnlocked {
getWallet(address: string | AbstractAddress): WalletUnlocked {
const ownerAddress = Address.fromAddressOrString(address);
const vaultState = this.#vaults.find((vs) =>
vs.vault.getAccounts().find((a) => a.address.equals(address))
vs.vault.getAccounts().find((a) => a.address.equals(ownerAddress))
);
assert(vaultState, ERROR_MESSAGES.address_not_found);

return vaultState.vault.getWallet(address);
return vaultState.vault.getWallet(ownerAddress);
}

/**
* Export specific account privateKey
*/
exportPrivateKey(address: AbstractAddress) {
exportPrivateKey(address: string | AbstractAddress) {
const ownerAddress = Address.fromAddressOrString(address);
assert(!this.#isLocked, ERROR_MESSAGES.wallet_not_unlocked);
const vaultState = this.#vaults.find((vs) =>
vs.vault.getAccounts().find((a) => a.address.equals(address))
vs.vault.getAccounts().find((a) => a.address.equals(ownerAddress))
);
assert(vaultState, ERROR_MESSAGES.address_not_found);

return vaultState.vault.exportAccount(address);
return vaultState.vault.exportAccount(ownerAddress);
}

/**
Expand Down
18 changes: 10 additions & 8 deletions packages/wallet/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ export class Account extends AbstractAccount {
*/
async createTransfer(
/** Address of the destination */
destination: AbstractAddress,
destination: string | AbstractAddress,
/** Amount of coins */
amount: BigNumberish,
/** Asset ID of coins */
Expand All @@ -303,7 +303,7 @@ export class Account extends AbstractAccount {
const { minGasPrice } = this.provider.getGasConfig();
const params = { gasPrice: minGasPrice, ...txParams };
const request = new ScriptTransactionRequest(params);
request.addCoinOutput(destination, amount, assetId);
request.addCoinOutput(Address.fromAddressOrString(destination), amount, assetId);
const { maxFee, requiredQuantities } = await this.provider.getTransactionCost(request);
await this.fund(request, requiredQuantities, maxFee);
return request;
Expand All @@ -320,7 +320,7 @@ export class Account extends AbstractAccount {
*/
async transfer(
/** Address of the destination */
destination: AbstractAddress,
destination: string | AbstractAddress,
/** Amount of coins */
amount: BigNumberish,
/** Asset ID of coins */
Expand All @@ -343,21 +343,22 @@ export class Account extends AbstractAccount {
*/
async transferToContract(
/** Contract address */
contractId: AbstractAddress,
contractId: string | AbstractAddress,
/** Amount of coins */
amount: BigNumberish,
/** Asset ID of coins */
assetId: BytesLike = BaseAssetId,
/** Tx Params */
txParams: TxParamsType = {}
): Promise<TransactionResponse> {
const contractAddress = Address.fromAddressOrString(contractId);
const { minGasPrice } = this.provider.getGasConfig();
const params = { gasPrice: minGasPrice, ...txParams };

const script = await composeScriptForTransferringToContract();

const scriptData = formatScriptDataForTransferringToContract(
contractId.toB256(),
contractAddress.toB256(),
amount,
assetId
);
Expand All @@ -368,7 +369,7 @@ export class Account extends AbstractAccount {
scriptData,
});

request.addContractInputAndOutput(contractId);
request.addContractInputAndOutput(contractAddress);

const { maxFee, requiredQuantities } = await this.provider.getTransactionCost(request, [
{ amount: bn(amount), assetId: String(assetId) },
Expand All @@ -389,15 +390,16 @@ export class Account extends AbstractAccount {
*/
async withdrawToBaseLayer(
/** Address of the recipient on the base chain */
recipient: AbstractAddress,
recipient: string | AbstractAddress,
/** Amount of base asset */
amount: BigNumberish,
/** Tx Params */
txParams: TxParamsType = {}
): Promise<TransactionResponse> {
const recipientAddress = Address.fromAddressOrString(recipient);
// add recipient and amount to the transaction script code
const recipientDataArray = getBytesCopy(
'0x'.concat(recipient.toHexString().substring(2).padStart(64, '0'))
'0x'.concat(recipientAddress.toHexString().substring(2).padStart(64, '0'))
);
const amountDataArray = getBytesCopy(
'0x'.concat(bn(amount).toHex().substring(2).padStart(16, '0'))
Expand Down
Loading

0 comments on commit 4dba236

Please sign in to comment.