Test and implement "can post an ERC20 transfer and search for the transaction"
This commit is contained in:
parent
5aca5ebd69
commit
ca2394657d
@ -589,6 +589,124 @@ describe("CosmWasmConnection", () => {
|
||||
connection.disconnect();
|
||||
});
|
||||
|
||||
it("can post an ERC20 transfer and search for the transaction", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const sender = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
const senderAddress = connection.codec.identityToAddress(sender);
|
||||
|
||||
const recipient = makeRandomAddress();
|
||||
const unsigned = await connection.withDefaultFee<SendTransaction>({
|
||||
kind: "bcp/send",
|
||||
chainId: defaultChainId,
|
||||
sender: senderAddress,
|
||||
recipient: recipient,
|
||||
memo: "My first payment",
|
||||
amount: {
|
||||
quantity: "75",
|
||||
fractionalDigits: 0,
|
||||
tokenTicker: "ISA" as TokenTicker,
|
||||
},
|
||||
});
|
||||
const nonce = await connection.getNonce({ address: senderAddress });
|
||||
const signed = await profile.signTransaction(sender, unsigned, connection.codec, nonce);
|
||||
const postableBytes = connection.codec.bytesToPost(signed);
|
||||
const response = await connection.postTx(postableBytes);
|
||||
const { transactionId } = response;
|
||||
const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info));
|
||||
expect(blockInfo.state).toEqual(TransactionState.Succeeded);
|
||||
|
||||
// search by id
|
||||
const byIdResults = await connection.searchTx({ id: transactionId });
|
||||
expect(byIdResults.length).toEqual(1);
|
||||
const byIdResult = byIdResults[0];
|
||||
expect(byIdResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(byIdResult), "Expected transaction to succeed");
|
||||
assert(byIdResult.log, "Log must be available");
|
||||
const [firstByIdlog] = JSON.parse(byIdResult.log);
|
||||
expect(firstByIdlog.events.length).toEqual(2);
|
||||
expect(firstByIdlog.events[0].type).toEqual("message");
|
||||
expect(firstByIdlog.events[1].type).toEqual("wasm");
|
||||
// wasm event attributes added by contract
|
||||
expect(firstByIdlog.events[1].attributes).toContain({ key: "action", value: "transfer" });
|
||||
expect(firstByIdlog.events[1].attributes).toContain({ key: "sender", value: senderAddress });
|
||||
expect(firstByIdlog.events[1].attributes).toContain({ key: "recipient", value: recipient });
|
||||
// wasm event attributes added wasmd
|
||||
expect(firstByIdlog.events[1].attributes).toContain({
|
||||
key: "contract_address",
|
||||
value: defaultConfig.erc20Tokens![1].contractAddress,
|
||||
});
|
||||
const byIdTransaction = byIdResult.transaction;
|
||||
assert(isSendTransaction(byIdTransaction), "Expected send transaction");
|
||||
expect(byIdTransaction).toEqual(unsigned);
|
||||
|
||||
// search by sender address
|
||||
const bySenderResults = await connection.searchTx({ sentFromOrTo: senderAddress });
|
||||
expect(bySenderResults).toBeTruthy();
|
||||
expect(bySenderResults.length).toBeGreaterThanOrEqual(1);
|
||||
const bySenderResult = bySenderResults[bySenderResults.length - 1];
|
||||
expect(bySenderResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(bySenderResult), "Expected transaction to succeed");
|
||||
assert(bySenderResult.log, "Log must be available");
|
||||
const [firstBySenderLog] = JSON.parse(bySenderResult.log);
|
||||
expect(firstBySenderLog.events.length).toEqual(2);
|
||||
expect(firstBySenderLog.events[0].type).toEqual("message");
|
||||
expect(firstBySenderLog.events[1].type).toEqual("wasm");
|
||||
// wasm event attributes added by contract
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({ key: "action", value: "transfer" });
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({ key: "sender", value: senderAddress });
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({ key: "recipient", value: recipient });
|
||||
// wasm event attributes added wasmd
|
||||
expect(firstBySenderLog.events[1].attributes).toContain({
|
||||
key: "contract_address",
|
||||
value: defaultConfig.erc20Tokens![1].contractAddress,
|
||||
});
|
||||
const bySenderTransaction = bySenderResult.transaction;
|
||||
assert(isSendTransaction(bySenderTransaction), "Expected send transaction");
|
||||
expect(bySenderTransaction).toEqual(unsigned);
|
||||
|
||||
// search by recipient address
|
||||
const byRecipientResults = await connection.searchTx({ sentFromOrTo: recipient });
|
||||
expect(byRecipientResults.length).toBeGreaterThanOrEqual(1);
|
||||
const byRecipientResult = byRecipientResults[byRecipientResults.length - 1];
|
||||
expect(byRecipientResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(byRecipientResult), "Expected transaction to succeed");
|
||||
assert(byRecipientResult.log, "Log must be available");
|
||||
const [firstByRecipientLog] = JSON.parse(bySenderResult.log);
|
||||
expect(firstByRecipientLog.events.length).toEqual(2);
|
||||
expect(firstByRecipientLog.events[0].type).toEqual("message");
|
||||
expect(firstByRecipientLog.events[1].type).toEqual("wasm");
|
||||
// wasm event attributes added by contract
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({ key: "action", value: "transfer" });
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({ key: "sender", value: senderAddress });
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({ key: "recipient", value: recipient });
|
||||
// wasm event attributes added wasmd
|
||||
expect(firstByRecipientLog.events[1].attributes).toContain({
|
||||
key: "contract_address",
|
||||
value: defaultConfig.erc20Tokens![1].contractAddress,
|
||||
});
|
||||
const byRecipeintTransaction = byRecipientResult.transaction;
|
||||
assert(isSendTransaction(byRecipeintTransaction), "Expected send transaction");
|
||||
expect(byRecipeintTransaction).toEqual(unsigned);
|
||||
|
||||
// search by height
|
||||
const heightResults = await connection.searchTx({ height: byIdResult.height });
|
||||
expect(heightResults.length).toEqual(1);
|
||||
const heightResult = heightResults[0];
|
||||
expect(heightResult.transactionId).toEqual(transactionId);
|
||||
assert(isConfirmedTransaction(heightResult), "Expected transaction to succeed");
|
||||
assert(heightResult.log, "Log must be available");
|
||||
const [firstHeightLog] = JSON.parse(heightResult.log);
|
||||
expect(firstHeightLog.events.length).toEqual(2);
|
||||
const heightTransaction = heightResult.transaction;
|
||||
assert(isSendTransaction(heightTransaction), "Expected send transaction");
|
||||
expect(heightTransaction).toEqual(unsigned);
|
||||
|
||||
connection.disconnect();
|
||||
});
|
||||
|
||||
it("can search by minHeight and maxHeight", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
@ -980,47 +1098,4 @@ describe("CosmWasmConnection", () => {
|
||||
})().catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
describe("integration tests", () => {
|
||||
it("can send ERC20 tokens", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const connection = await CosmWasmConnection.establish(httpUrl, defaultAddressPrefix, defaultConfig);
|
||||
const profile = new UserProfile();
|
||||
const wallet = profile.addWallet(Secp256k1HdWallet.fromMnemonic(faucet.mnemonic));
|
||||
const sender = await profile.createIdentity(wallet.id, defaultChainId, faucet.path);
|
||||
const senderAddress = connection.codec.identityToAddress(sender);
|
||||
const recipient = makeRandomAddress();
|
||||
|
||||
const unsigned = await connection.withDefaultFee<SendTransaction>({
|
||||
kind: "bcp/send",
|
||||
chainId: defaultChainId,
|
||||
sender: senderAddress,
|
||||
recipient: recipient,
|
||||
memo: "My first payment",
|
||||
amount: {
|
||||
quantity: "75",
|
||||
fractionalDigits: 0,
|
||||
tokenTicker: "ISA" as TokenTicker,
|
||||
},
|
||||
});
|
||||
const nonce = await connection.getNonce({ address: senderAddress });
|
||||
const signed = await profile.signTransaction(sender, unsigned, connection.codec, nonce);
|
||||
const postableBytes = connection.codec.bytesToPost(signed);
|
||||
const response = await connection.postTx(postableBytes);
|
||||
const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info));
|
||||
expect(blockInfo.state).toEqual(TransactionState.Succeeded);
|
||||
|
||||
const recipientAccount = await connection.getAccount({ address: recipient });
|
||||
assert(recipientAccount, "Recipient account must have ISA tokens");
|
||||
expect(recipientAccount.balance).toEqual([
|
||||
{
|
||||
tokenTicker: "ISA" as TokenTicker,
|
||||
quantity: "75",
|
||||
fractionalDigits: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
connection.disconnect();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -60,6 +60,16 @@ function isDefined<X>(value: X | undefined): value is X {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
function deduplicate<T>(input: ReadonlyArray<T>, comparator: (a: T, b: T) => number): ReadonlyArray<T> {
|
||||
const out = new Array<T>();
|
||||
for (const element of input) {
|
||||
if (!out.find(o => comparator(o, element) === 0)) {
|
||||
out.push(element);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Account and undefined are valid events. The third option means no event fired yet */
|
||||
type LastWatchAccountEvent = Account | undefined | "no_event_fired_yet";
|
||||
|
||||
@ -324,7 +334,35 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
} else if (height) {
|
||||
txs = await this.cosmWasmClient.searchTx({ height: height }, filter);
|
||||
} else if (sentFromOrTo) {
|
||||
txs = await this.cosmWasmClient.searchTx({ sentFromOrTo: sentFromOrTo }, filter);
|
||||
const pendingRequests = new Array<Promise<readonly TxsResponse[]>>();
|
||||
pendingRequests.push(this.cosmWasmClient.searchTx({ sentFromOrTo: sentFromOrTo }, filter));
|
||||
for (const contract of this.erc20Tokens.map(token => token.contractAddress)) {
|
||||
const searchBySender = [
|
||||
{
|
||||
key: "wasm.contract_address",
|
||||
value: contract,
|
||||
},
|
||||
{
|
||||
key: "wasm.sender",
|
||||
value: sentFromOrTo,
|
||||
},
|
||||
];
|
||||
const searchByRecipient = [
|
||||
{
|
||||
key: "wasm.contract_address",
|
||||
value: contract,
|
||||
},
|
||||
{
|
||||
key: "wasm.recipient",
|
||||
value: sentFromOrTo,
|
||||
},
|
||||
];
|
||||
pendingRequests.push(this.cosmWasmClient.searchTx({ tags: searchBySender }, filter));
|
||||
pendingRequests.push(this.cosmWasmClient.searchTx({ tags: searchByRecipient }, filter));
|
||||
}
|
||||
const responses = await Promise.all(pendingRequests);
|
||||
const allResults = responses.reduce((accumulator, results) => accumulator.concat(results), []);
|
||||
txs = deduplicate(allResults, (a, b) => a.txhash.localeCompare(b.txhash));
|
||||
} else {
|
||||
throw new Error("Unsupported query");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user