Skip to content

Commit f3c8071

Browse files
committed
feat(rpc): add fundAddress() method for funding accounts and
contracts - Add fundAddress() that supports both G... and C... addresses - Returns GetSuccessfulTransactionResponse for consistent return type - Mark requestAirdrop() as deprecated - Add unit tests for fundAddress()
1 parent 27f2c9e commit f3c8071

File tree

3 files changed

+236
-74
lines changed

3 files changed

+236
-74
lines changed

src/rpc/api.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@ export namespace Api {
4848
protocolVersion: string;
4949
}
5050

51-
/**
52-
* Result returned when funding a contract address via friendbot.
53-
*/
54-
export interface ContractFundingResult {
55-
contractId: string;
56-
hash: string;
57-
}
58-
5951
/** @see https://developers.stellar.org/docs/data/rpc/api-reference/methods/getLatestLedger */
6052
export interface GetLatestLedgerResponse {
6153
id: string;

src/rpc/server.ts

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,52 +1194,40 @@ export class RpcServer {
11941194
}
11951195

11961196
/**
1197-
* Fund a new account or contract using the network's Friendbot faucet, if any.
1197+
* Fund a new account using the network's Friendbot faucet, if any.
11981198
*
11991199
* @param {string | Account} address The address or account instance that we
1200-
* want to create and fund with Friendbot. Supports both G... (account) and
1201-
* C... (contract) addresses.
1200+
* want to create and fund with Friendbot
12021201
* @param {string} [friendbotUrl] Optionally, an explicit address for
12031202
* friendbot (by default: this calls the Soroban RPC
12041203
* {@link module:rpc.Server#getNetwork | getNetwork} method to try to
12051204
* discover this network's Friendbot url).
1206-
* @returns {Promise<Account | Api.ContractFundingResult>} An {@link Account}
1207-
* object for the created account (G... addresses), or a
1208-
* {@link Api.ContractFundingResult} for contract addresses (C...). For
1209-
* existing accounts, returns the account with populated sequence number
1210-
* (note that accounts will not be "topped off" if they already exist).
1205+
* @returns {Promise<Account>} An {@link Account} object for the created
1206+
* account, or the existing account if it's already funded with the
1207+
* populated sequence number (note that the account will not be "topped
1208+
* off" if it already exists)
12111209
* @throws {Error} If Friendbot is not configured on this network or request failure
12121210
*
12131211
* @see {@link https://developers.stellar.org/docs/learn/fundamentals/networks#friendbot | Friendbot docs}
12141212
* @see {@link module:Friendbot.Api.Response}
12151213
*
1216-
* @example
1217-
* // Funding an account (G... address)
1218-
* server
1219-
* .requestAirdrop("GBZC6Y2Y7Q3ZQ2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4")
1220-
* .then((result) => {
1221-
* if (result instanceof Account) {
1222-
* console.log("accountCreated:", result.accountId());
1223-
* }
1224-
* });
1214+
* @deprecated Use {@link Server.fundAddress} instead, which supports both
1215+
* account (G...) and contract (C...) addresses.
12251216
*
12261217
* @example
1227-
* // Funding a contract (C... address)
12281218
* server
1229-
* .requestAirdrop("CBZC6Y2Y7Q3ZQ2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4")
1230-
* .then((result) => {
1231-
* if ('contractId' in result) {
1232-
* console.log("contractFunded:", result.contractId, "hash:", result.hash);
1233-
* }
1219+
* .requestAirdrop("GBZC6Y2Y7Q3ZQ2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4QZJ2XZ3Z5YXZ6Z7Z2Y4")
1220+
* .then((accountCreated) => {
1221+
* console.log("accountCreated:", accountCreated);
1222+
* }).catch((error) => {
1223+
* console.error("error:", error);
12341224
* });
12351225
*/
12361226
public async requestAirdrop(
12371227
address: string | Pick<Account, "accountId">,
12381228
friendbotUrl?: string,
1239-
): Promise<Account | Api.ContractFundingResult> {
1229+
): Promise<Account> {
12401230
const account = typeof address === "string" ? address : address.accountId();
1241-
const isContract = StrKey.isValidContract(account);
1242-
12431231
friendbotUrl = friendbotUrl || (await this.getNetwork()).friendbotUrl;
12441232
if (!friendbotUrl) {
12451233
throw new Error("No friendbot URL configured for current network");
@@ -1250,14 +1238,6 @@ export class RpcServer {
12501238
`${friendbotUrl}?addr=${encodeURIComponent(account)}`,
12511239
);
12521240

1253-
// Contract addresses don't create accounts - they receive funds via SAC transfer
1254-
if (isContract) {
1255-
return {
1256-
contractId: account,
1257-
hash: response.data.hash,
1258-
};
1259-
}
1260-
12611241
let meta: xdr.TransactionMeta;
12621242
if (!response.data.result_meta_xdr) {
12631243
const txMeta = await this.getTransaction(response.data.hash);
@@ -1285,6 +1265,57 @@ export class RpcServer {
12851265
}
12861266
}
12871267

1268+
/**
1269+
* Fund an address using the network's Friendbot faucet, if any.
1270+
*
1271+
* This method supports both account (G...) and contract (C...) addresses.
1272+
*
1273+
* @param {string} address The address to fund. Can be either a Stellar
1274+
* account (G...) or contract (C...) address.
1275+
* @param {string} [friendbotUrl] Optionally, an explicit Friendbot URL
1276+
* (by default: this calls the Soroban RPC
1277+
* {@link module:rpc.Server#getNetwork | getNetwork} method to try to
1278+
* discover this network's Friendbot url).
1279+
* @returns {Promise<Api.GetSuccessfulTransactionResponse>} The transaction
1280+
* response from the Friendbot funding transaction.
1281+
* @throws {Error} If Friendbot is not configured on this network or the
1282+
* funding transaction fails.
1283+
*
1284+
* @see {@link https://developers.stellar.org/docs/learn/fundamentals/networks#friendbot | Friendbot docs}
1285+
*
1286+
* @example
1287+
* // Funding an account (G... address)
1288+
* const tx = await server.fundAddress("GBZC6Y2Y7...");
1289+
* console.log("Funded! Hash:", tx.txHash);
1290+
* // If you need the Account object:
1291+
* const account = await server.getAccount("GBZC6Y2Y7...");
1292+
*
1293+
* @example
1294+
* // Funding a contract (C... address)
1295+
* const tx = await server.fundAddress("CBZC6Y2Y7...");
1296+
* console.log("Contract funded! Hash:", tx.txHash);
1297+
*/
1298+
public async fundAddress(
1299+
address: string,
1300+
friendbotUrl?: string,
1301+
): Promise<Api.GetSuccessfulTransactionResponse> {
1302+
friendbotUrl = friendbotUrl || (await this.getNetwork()).friendbotUrl;
1303+
if (!friendbotUrl) {
1304+
throw new Error("No friendbot URL configured for current network");
1305+
}
1306+
1307+
const response = await this.httpClient.post<FriendbotApi.Response>(
1308+
`${friendbotUrl}?addr=${encodeURIComponent(address)}`,
1309+
);
1310+
1311+
const txResponse = await this.getTransaction(response.data.hash);
1312+
if (txResponse.status !== Api.GetTransactionStatus.SUCCESS) {
1313+
throw new Error(`Funding address ${address} failed`);
1314+
}
1315+
1316+
return txResponse;
1317+
}
1318+
12881319
/**
12891320
* Provides an analysis of the recent fee stats for regular and smart
12901321
* contract operations.

test/unit/server/soroban/request_airdrop.test.ts

Lines changed: 171 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -370,14 +370,89 @@ describe("Server#requestAirdrop", () => {
370370
expect(mockPost).toHaveBeenCalledTimes(3);
371371
});
372372

373-
it("returns ContractFundingResult for contract addresses (C...)", async () => {
373+
});
374+
375+
describe("Server#fundAddress", () => {
376+
let server: any;
377+
let mockPost: any;
378+
379+
// Valid XDR for transaction meta (from get_transaction.test.ts)
380+
const metaV4Xdr =
381+
"AAAAAgAAAAIAAAADAtL5awAAAAAAAAAAS0CFMhOtWUKJWerx66zxkxORaiH6/3RUq7L8zspD5RoAAAAAAcm9QAKVkpMAAHpMAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAAAC0vi5AAAAAGTB02oAAAAAAAAAAQLS+WsAAAAAAAAAAEtAhTITrVlCiVnq8eus8ZMTkWoh+v90VKuy/M7KQ+UaAAAAAAHJvUAClZKTAAB6TQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAAtL5awAAAABkwdd1AAAAAAAAAAEAAAAGAAAAAwLS+VQAAAACAAAAAG4cwu71zHNXx3jHCzRGOIthcnfwRgfN2f/AoHFLLMclAAAAAEySDkgAAAAAAAAAAkJVU0lORVNTAAAAAAAAAAC3JfDeo9vreItKNPoe74EkFIqWybeUQNFvLvURhHtskAAAAAAeQtHTL5f6TAAAXH0AAAAAAAAAAAAAAAAAAAABAtL5awAAAAIAAAAAbhzC7vXMc1fHeMcLNEY4i2Fyd/BGB83Z/8CgcUssxyUAAAAATJIOSAAAAAAAAAACQlVTSU5FU1MAAAAAAAAAALcl8N6j2+t4i0o0+h7vgSQUipbJt5RA0W8u9RGEe2yQAAAAAB5C0dNHf4CAAACLCQAAAAAAAAAAAAAAAAAAAAMC0vlUAAAAAQAAAABuHMLu9cxzV8d4xws0RjiLYXJ38EYHzdn/wKBxSyzHJQAAAAJCVVNJTkVTUwAAAAAAAAAAtyXw3qPb63iLSjT6Hu+BJBSKlsm3lEDRby71EYR7bJAAAAAAAABAL3//////////AAAAAQAAAAEAE3H3TnhnuQAAAAAAAAAAAAAAAAAAAAAAAAABAtL5awAAAAEAAAAAbhzC7vXMc1fHeMcLNEY4i2Fyd/BGB83Z/8CgcUssxyUAAAACQlVTSU5FU1MAAAAAAAAAALcl8N6j2+t4i0o0+h7vgSQUipbJt5RA0W8u9RGEe2yQAAAAAAAAQC9//////////wAAAAEAAAABABNx9J6Z4RkAAAAAAAAAAAAAAAAAAAAAAAAAAwLS+WsAAAAAAAAAAG4cwu71zHNXx3jHCzRGOIthcnfwRgfN2f/AoHFLLMclAAAAH37+zXQCXdRTAAASZAAAApIAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAABbBXKIigAAABhZWyiOAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAAtL0awAAAABkwbqrAAAAAAAAAAEC0vlrAAAAAAAAAABuHMLu9cxzV8d4xws0RjiLYXJ38EYHzdn/wKBxSyzHJQAAAB9+/s10Al3UUwAAEmQAAAKSAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAABAAAAWwVyiIoAAAAYWVsojgAAAAIAAAAAAAAAAAAAAAAAAAADAAAAAALS9GsAAAAAZMG6qwAAAAAAAAAA";
382+
383+
const successTxResponse = (hash: string) => ({
384+
data: {
385+
id: 1,
386+
result: {
387+
status: "SUCCESS",
388+
txHash: hash,
389+
latestLedger: 100,
390+
latestLedgerCloseTime: 12345,
391+
oldestLedger: 50,
392+
oldestLedgerCloseTime: 500,
393+
ledger: 12345,
394+
createdAt: 123456789010,
395+
applicationOrder: 2,
396+
feeBump: false,
397+
envelopeXdr:
398+
"AAAAAgAAAAAT/LQZdYz0FcQ4Xwyg8IM17rkUx3pPCCWLu+SowQ/T+gBLB24poiQa9iwAngAAAAEAAAAAAAAAAAAAAABkwdeeAAAAAAAAAAEAAAABAAAAAC/9E8hDhnktyufVBS5tqA734Yz5XrLX2XNgBgH/YEkiAAAADQAAAAAAAAAAAAA1/gAAAAAv/RPIQ4Z5Lcrn1QUubagO9+GM+V6y19lzYAYB/2BJIgAAAAAAAAAAAAA1/gAAAAQAAAACU0lMVkVSAAAAAAAAAAAAAFDutWuu6S6UPJBrotNSgfmXa27M++63OT7TYn1qjgy+AAAAAVNHWAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AAAACUEFMTEFESVVNAAAAAAAAAFDutWuu6S6UPJBrotNSgfmXa27M++63OT7TYn1qjgy+AAAAAlNJTFZFUgAAAAAAAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAAAAAAAACwQ/T+gAAAEA+ztVEKWlqHXNnqy6FXJeHr7TltHzZE6YZm5yZfzPIfLaqpp+5cyKotVkj3d89uZCQNsKsZI48uoyERLne+VwL/2BJIgAAAEA7323gPSaezVSa7Vi0J4PqsnklDH1oHLqNBLwi5EWo5W7ohLGObRVQZ0K0+ufnm4hcm9J4Cuj64gEtpjq5j5cM",
399+
resultXdr:
400+
"AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAANAAAAAAAAAAUAAAACZ4W6fmN63uhVqYRcHET+D2NEtJvhCIYflFh9GqtY+AwAAAACU0lMVkVSAAAAAAAAAAAAAFDutWuu6S6UPJBrotNSgfmXa27M++63OT7TYn1qjgy+AAAYW0toL2gAAAAAAAAAAAAANf4AAAACcgyAkXD5kObNTeRYciLh7R6ES/zzKp0n+cIK3Y6TjBkAAAABU0dYAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAGlGnIJrXAAAAAlNJTFZFUgAAAAAAAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAGFtLaC9oAAAAApmc7UgUBInrDvij8HMSridx2n1w3I8TVEn4sLr1LSpmAAAAAlBBTExBRElVTQAAAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAIUz88EqYAAAAAVNHWAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AABpRpyCa1wAAAAKYUsaaCZ233xB1p+lG7YksShJWfrjsmItbokiR3ifa0gAAAAJTSUxWRVIAAAAAAAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AABv52PPa5wAAAAJQQUxMQURJVU0AAAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AACFM/PBKmAAAAAJnhbp+Y3re6FWphFwcRP4PY0S0m+EIhh+UWH0aq1j4DAAAAAAAAAAAAAA9pAAAAAJTSUxWRVIAAAAAAAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AABv52PPa5wAAAAAv/RPIQ4Z5Lcrn1QUubagO9+GM+V6y19lzYAYB/2BJIgAAAAAAAAAAAAA9pAAAAAA=",
401+
resultMetaXdr: metaV4Xdr,
402+
events: {
403+
contractEventsXdr: [],
404+
transactionEventsXdr: [],
405+
},
406+
},
407+
},
408+
});
409+
410+
beforeEach(() => {
411+
server = new Server(serverUrl);
412+
mockPost = vi.spyOn(server.httpClient, "post");
413+
});
414+
415+
afterEach(() => {
416+
vi.clearAllMocks();
417+
});
418+
419+
it("funds an account address (G...) and returns transaction response", async () => {
420+
const friendbotUrl = "https://friendbot.stellar.org";
421+
const accountId =
422+
"GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI";
423+
const hash = "ae9f315c048d87a5f853bc15bf284a2c3c89eb0e1cb38c10409b77a877b830a8";
424+
425+
const networkResult = {
426+
friendbotUrl,
427+
passphrase: Networks.FUTURENET,
428+
protocolVersion: 20,
429+
};
430+
const networkResponse = { data: { result: networkResult } };
431+
432+
const friendbotResponse = {
433+
status: 200,
434+
data: { hash },
435+
};
436+
437+
mockPost
438+
.mockResolvedValueOnce(networkResponse) // getNetwork call
439+
.mockResolvedValueOnce(friendbotResponse) // friendbot call
440+
.mockResolvedValueOnce(successTxResponse(hash)); // getTransaction call
441+
442+
const result = await server.fundAddress(accountId);
443+
444+
expect(result.status).toBe("SUCCESS");
445+
expect(result.txHash).toBe(hash);
446+
expect(mockPost).toHaveBeenCalledWith(`${friendbotUrl}?addr=${accountId}`);
447+
expect(mockPost).toHaveBeenCalledTimes(3);
448+
});
449+
450+
it("funds a contract address (C...) and returns transaction response", async () => {
374451
const friendbotUrl = "https://friendbot.stellar.org";
375-
// Valid contract address (C...)
376452
const contractId = StellarSdk.StrKey.encodeContract(
377453
Buffer.from("0".repeat(64), "hex"),
378454
);
379-
const hash =
380-
"ae9f315c048d87a5f853bc15bf284a2c3c89eb0e1cb38c10409b77a877b830a8";
455+
const hash = "ae9f315c048d87a5f853bc15bf284a2c3c89eb0e1cb38c10409b77a877b830a8";
381456

382457
const networkResult = {
383458
friendbotUrl,
@@ -386,55 +461,119 @@ describe("Server#requestAirdrop", () => {
386461
};
387462
const networkResponse = { data: { result: networkResult } };
388463

389-
// Mock the friendbot call - contract funding returns hash but no account creation
390464
const friendbotResponse = {
391465
status: 200,
392-
data: {
393-
hash,
394-
result_meta_xdr: "someXdr", // Doesn't matter - should not be parsed for contracts
395-
},
466+
data: { hash },
396467
};
397468

398469
mockPost
399470
.mockResolvedValueOnce(networkResponse) // getNetwork call
400-
.mockResolvedValueOnce(friendbotResponse); // friendbot call
471+
.mockResolvedValueOnce(friendbotResponse) // friendbot call
472+
.mockResolvedValueOnce(successTxResponse(hash)); // getTransaction call
401473

402-
const result = await server.requestAirdrop(contractId);
474+
const result = await server.fundAddress(contractId);
403475

404-
// Should return ContractFundingResult, not Account
405-
expect(result).not.toBeInstanceOf(StellarSdk.Account);
406-
expect(result).toHaveProperty("contractId", contractId);
407-
expect(result).toHaveProperty("hash", hash);
408-
expect(mockPost).toHaveBeenCalledWith(serverUrl, {
409-
jsonrpc: "2.0",
410-
id: 1,
411-
method: "getNetwork",
412-
params: null,
413-
});
476+
expect(result.status).toBe("SUCCESS");
477+
expect(result.txHash).toBe(hash);
414478
expect(mockPost).toHaveBeenCalledWith(`${friendbotUrl}?addr=${contractId}`);
415-
expect(mockPost).toHaveBeenCalledTimes(2);
479+
expect(mockPost).toHaveBeenCalledTimes(3);
416480
});
417481

418-
it("does not throw 'No account created' for contract addresses", async () => {
482+
it("uses custom friendbot URL when provided", async () => {
419483
const customFriendbotUrl = "https://custom-friendbot.example.com";
420-
const contractId = StellarSdk.StrKey.encodeContract(
421-
Buffer.from("1".repeat(64), "hex"),
484+
const accountId =
485+
"GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI";
486+
const hash = "somehash123";
487+
488+
const friendbotResponse = {
489+
status: 200,
490+
data: { hash },
491+
};
492+
493+
mockPost
494+
.mockResolvedValueOnce(friendbotResponse) // friendbot call
495+
.mockResolvedValueOnce(successTxResponse(hash)); // getTransaction call
496+
497+
const result = await server.fundAddress(accountId, customFriendbotUrl);
498+
499+
expect(result.status).toBe("SUCCESS");
500+
// Should not call getNetwork when custom URL provided
501+
expect(mockPost).not.toHaveBeenCalledWith(
502+
expect.anything(),
503+
expect.objectContaining({ method: "getNetwork" }),
504+
);
505+
expect(mockPost).toHaveBeenCalledWith(
506+
`${customFriendbotUrl}?addr=${accountId}`,
422507
);
508+
expect(mockPost).toHaveBeenCalledTimes(2);
509+
});
510+
511+
it("throws error when no friendbot URL is configured", async () => {
512+
const accountId =
513+
"GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI";
514+
515+
const networkResult = {
516+
friendbotUrl: undefined,
517+
passphrase: Networks.FUTURENET,
518+
protocolVersion: 20,
519+
};
520+
const networkResponse = { data: { result: networkResult } };
521+
522+
mockPost.mockResolvedValueOnce(networkResponse);
523+
524+
await expect(server.fundAddress(accountId)).rejects.toThrow(
525+
"No friendbot URL configured",
526+
);
527+
});
528+
529+
it("throws error when funding fails", async () => {
530+
const friendbotUrl = "https://friendbot.stellar.org";
531+
const accountId =
532+
"GBZXN7PIRZGNMHGA7MUUUF4GWPY5AYPV6LY4UV2GL6VJGIQRXFDNMADI";
423533
const hash = "somehash123";
424534

535+
const networkResult = {
536+
friendbotUrl,
537+
passphrase: Networks.FUTURENET,
538+
protocolVersion: 20,
539+
};
540+
const networkResponse = { data: { result: networkResult } };
541+
425542
const friendbotResponse = {
426543
status: 200,
427544
data: { hash },
428545
};
429546

430-
mockPost.mockResolvedValueOnce(friendbotResponse);
547+
const failedTxResponse = {
548+
data: {
549+
id: 1,
550+
result: {
551+
status: "FAILED",
552+
txHash: hash,
553+
latestLedger: 100,
554+
latestLedgerCloseTime: 12345,
555+
oldestLedger: 50,
556+
oldestLedgerCloseTime: 500,
557+
ledger: 12345,
558+
createdAt: 123456789010,
559+
applicationOrder: 2,
560+
feeBump: false,
561+
envelopeXdr:
562+
"AAAAAgAAAAAT/LQZdYz0FcQ4Xwyg8IM17rkUx3pPCCWLu+SowQ/T+gBLB24poiQa9iwAngAAAAEAAAAAAAAAAAAAAABkwdeeAAAAAAAAAAEAAAABAAAAAC/9E8hDhnktyufVBS5tqA734Yz5XrLX2XNgBgH/YEkiAAAADQAAAAAAAAAAAAA1/gAAAAAv/RPIQ4Z5Lcrn1QUubagO9+GM+V6y19lzYAYB/2BJIgAAAAAAAAAAAAA1/gAAAAQAAAACU0lMVkVSAAAAAAAAAAAAAFDutWuu6S6UPJBrotNSgfmXa27M++63OT7TYn1qjgy+AAAAAVNHWAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AAAACUEFMTEFESVVNAAAAAAAAAFDutWuu6S6UPJBrotNSgfmXa27M++63OT7TYn1qjgy+AAAAAlNJTFZFUgAAAAAAAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAAAAAAAACwQ/T+gAAAEA+ztVEKWlqHXNnqy6FXJeHr7TltHzZE6YZm5yZfzPIfLaqpp+5cyKotVkj3d89uZCQNsKsZI48uoyERLne+VwL/2BJIgAAAEA7323gPSaezVSa7Vi0J4PqsnklDH1oHLqNBLwi5EWo5W7ohLGObRVQZ0K0+ufnm4hcm9J4Cuj64gEtpjq5j5cM",
563+
resultXdr:
564+
"AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAANAAAAAAAAAAUAAAACZ4W6fmN63uhVqYRcHET+D2NEtJvhCIYflFh9GqtY+AwAAAACU0lMVkVSAAAAAAAAAAAAAFDutWuu6S6UPJBrotNSgfmXa27M++63OT7TYn1qjgy+AAAYW0toL2gAAAAAAAAAAAAANf4AAAACcgyAkXD5kObNTeRYciLh7R6ES/zzKp0n+cIK3Y6TjBkAAAABU0dYAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAGlGnIJrXAAAAAlNJTFZFUgAAAAAAAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAGFtLaC9oAAAAApmc7UgUBInrDvij8HMSridx2n1w3I8TVEn4sLr1LSpmAAAAAlBBTExBRElVTQAAAAAAAABQ7rVrrukulDyQa6LTUoH5l2tuzPvutzk+02J9ao4MvgAAIUz88EqYAAAAAVNHWAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AABpRpyCa1wAAAAKYUsaaCZ233xB1p+lG7YksShJWfrjsmItbokiR3ifa0gAAAAJTSUxWRVIAAAAAAAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AABv52PPa5wAAAAJQQUxMQURJVU0AAAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AACFM/PBKmAAAAAJnhbp+Y3re6FWphFwcRP4PY0S0m+EIhh+UWH0aq1j4DAAAAAAAAAAAAAA9pAAAAAJTSUxWRVIAAAAAAAAAAAAAUO61a67pLpQ8kGui01KB+Zdrbsz77rc5PtNifWqODL4AABv52PPa5wAAAAAv/RPIQ4Z5Lcrn1QUubagO9+GM+V6y19lzYAYB/2BJIgAAAAAAAAAAAAA9pAAAAAA=",
565+
resultMetaXdr: metaV4Xdr,
566+
},
567+
},
568+
};
431569

432-
// Should NOT throw "No account created in transaction"
433-
const result = await server.requestAirdrop(contractId, customFriendbotUrl);
570+
mockPost
571+
.mockResolvedValueOnce(networkResponse)
572+
.mockResolvedValueOnce(friendbotResponse)
573+
.mockResolvedValueOnce(failedTxResponse);
434574

435-
expect(result).toEqual({
436-
contractId,
437-
hash,
438-
});
575+
await expect(server.fundAddress(accountId)).rejects.toThrow(
576+
`Funding address ${accountId} failed`,
577+
);
439578
});
440579
});

0 commit comments

Comments
 (0)