@tangany/waas
Version:
node.js SDK for Tangany Wallet as a Service API
217 lines (192 loc) • 9.12 kB
JavaScript
const { Waas } = require("../dist");
const { EthereumPublicNetwork } = require("../src/waas");
const { config } = require("dotenv");
const assert = require("assert");
const { checkEnvVars } = require("./helpers");
const { getRandomHex } = require("./helpers");
const { resolve } = require("path");
const util = require("util");
const path = resolve(process.cwd(), ".env");
config({ path });
checkEnvVars();
describe("WaaS sample Ethereum workflow", function () {
const timeout = 160e3;
this.timeout(timeout);
this.slow(timeout / 3);
const tokenWallet = process.env.E2E_WALLET; // Wallet with some Ether balance that owns the ERC20 token
const tokenAddress = process.env.E2E_TOKEN; // mintable & burnable ERC20 token address deployed by the tokenWallet to Goerli
const tokenAmount = "0.0032"; // Token amount used for transactions
const etherAmount = "0.002"; // Ether amount used for transactions
let tokenWalletAddress; // Token wallet address
let createdWallet; // Random created wallet name
let createdWalletAddress; // Created wallet address
let txHash; // Tx hashes
// Tangany-based smart contract ("Caller") used for testing here:
// https://github.com/Tangany/truffle-blueprint/blob/master/contracts/Caller.sol
const callerContract = "0x735fcc036022122082A6f870D6c02F5B3a38668B";
const api = new Waas({
ethereumNetwork: EthereumPublicNetwork.GOERLI, // All tests execute on the goerli testnet
}, undefined, true);
before(async function () {
tokenWalletAddress = (await api.wallet(tokenWallet).eth().get()).address;
})
it("should create a new wallet", async function () {
const { security, created, version, wallet, updated } = await api.wallet().create();
assert.ok(security);
assert.ok(created);
assert.ok(version);
assert.ok(wallet);
assert.ok(updated);
createdWallet = wallet;
console.log(`created wallet ${createdWallet}`);
});
it("should get the created wallet data", async function () {
assert.ok(createdWallet, "cannot run without previous tests");
const { security, created, version, wallet, updated } = await api.wallet(createdWallet).get();
assert.ok(security);
assert.ok(created);
assert.ok(version);
assert.ok(wallet);
assert.ok(updated);
console.log("wallet", { updated, wallet, version, created, security });
assert.strictEqual(wallet, createdWallet);
});
it("should get the Ethereum specs for created wallet", async function () {
assert.ok(createdWallet, "cannot run without previous tests");
const { address, balance, currency, nonce } = await api.wallet(createdWallet).eth().get();
assert.ok(address);
assert.strictEqual(balance, "0");
assert.strictEqual(currency, "tETH");
assert.ok(typeof nonce === "number");
createdWalletAddress = address;
console.log(`address for created wallet: ${createdWalletAddress}. Balance: ${balance}`);
});
it("should sign payload with wallet", async function () {
assert.ok(createdWallet, "cannot run without previous tests");
const payload = "messageToSign"
const res = await api.wallet(createdWallet).eth().personalSign(payload);
console.log(res);
assert.ok(res.address);
assert.ok(res.payloadHash);
assert.ok(res.payload);
assert.ok(res.payload == payload)
assert.ok(res.signature);
});
it("should interact with a smart contract using the universal contract endpoint", async function () {
const request = await api.wallet(tokenWallet).eth().contract(tokenAddress).sendAsync({
function: "transfer(address,uint256)",
inputs: [createdWalletAddress, "3200000000000000"]
});
console.log(`asynchronous transaction request '${request.id}' started...`);
await request.wait(35e5);
const { output } = await request.get();
txHash = output.hash;
console.log(output);
assert.ok(output);
});
it("should get the transaction status for the hash", async function () {
assert.ok(txHash, "cannot run without previous tests");
const { blockNr, isError, data, confirmations, status } = await api.eth(txHash).get();
console.log("inital tx status", { blockNr, isError, data, confirmations, status });
assert.strictEqual(isError, false);
assert.notStrictEqual(status, "unknown");
});
it("should wait for the transaction to get mined", async function () {
assert.ok(txHash, "cannot run without previous tests");
const { isError, blockNr } = await api.eth(txHash).wait(timeout);
assert.ok(typeof blockNr === "number");
console.log(`mined in blockNr ${blockNr}`);
});
it("should get the new token balance for the new wallet", async function () {
const { currency, balance } = await api.wallet(createdWallet).eth().erc20(tokenAddress).get();
assert.ok(currency);
assert.strictEqual(balance, tokenAmount);
console.log(`new token balance: ${balance}`);
});
it("should estimate the transaction fee for a transaction", async function () {
assert.ok(createdWalletAddress, "cannot run without previous tests");
const estimation = await api.wallet(tokenWallet).eth().estimateFee({ to: createdWalletAddress, amount: etherAmount });
console.log(`fee estimation: ${JSON.stringify(estimation, null, 2)}`);
})
it("should send small amount of ether to new wallet", async function () {
assert.ok(createdWalletAddress, "cannot run without previous tests");
const req = await api.wallet(tokenWallet).eth().sendAsync({ to: createdWalletAddress, amount: etherAmount });
console.log(`Wait for completion of request with id ${req.id}...`);
await req.wait(35e5);
const { output } = await req.get();
const hash = output.hash;
console.log(`transaction made with txhash ${hash}. Waiting for the transaction to get mined...`);
await api.eth(hash).wait(timeout);
console.log(output);
});
it("should estimate the transaction fee for a smart contract interaction", async function () {
const estimation = await api.wallet(tokenWallet).eth().contract(tokenAddress).estimateFee({
function: "transfer(address,uint256)",
inputs: [createdWalletAddress, "2500000000000000"]
});
console.log(`fee estimation: ${JSON.stringify(estimation, null, 2)}`);
});
it("should call a readonly smart contract function", async function(){
assert.ok(tokenWalletAddress, "cannot run without previous tests");
const contractResponse = await api.eth().contract(tokenAddress).call({
function: "balanceOf(address)",
inputs: [tokenWalletAddress],
outputs: ["uint256"]
});
console.log(`Contract call result: ${JSON.stringify(contractResponse)}`);
})
it("should call a readonly smart contract without arguments", async function () {
const symbol = await api.eth().contract(tokenAddress).call("symbol", ["string"]);
console.log(`Symbol of contract ${tokenAddress}: ${symbol[0].value}`);
// Omit the second argument, because the default value ["uint256"] is suitable for totalSupply()
const supply = await api.eth().contract(tokenAddress).call("totalSupply");
console.log(`Total supply of ${symbol[0].value}: ${supply[0].value}`);
});
it("should call a readonly smart contract function on behalf of a wallet", async function () {
assert.ok(tokenWalletAddress, "cannot run without previous tests");
assert.ok(createdWalletAddress, "cannot run without previous tests");
// balanceOf expects an address as first argument, which is set automatically in this overload
const balance = await api.wallet(tokenWallet).eth().contract(tokenAddress).call("balanceOf");
console.log(`balanceOf(${tokenWalletAddress}): ${balance[0].value}`);
// Since the allowance function expects several parameters, we use the overload with the configuration object
const allowance = await api.wallet(tokenWallet).eth().contract(tokenAddress).call({
function: "allowance(address,address)",
inputs: [tokenWalletAddress, createdWalletAddress],
outputs: ["uint256"],
});
console.log(`Result for allowance(${tokenWalletAddress}, ${createdWalletAddress}): ${JSON.stringify(allowance)}`);
});
it("should call a smart contract function with nested array argument", async function () {
const resultArr = await api.eth().contract(callerContract).call({
"function": "callFlattenAddressArray(address[][2])",
"inputs": [
[
[
"0x0120000000000000000000000000000000000000",
"0x0340000000000000000000000000000000000000"
],
[
"0x1330000000000000000000000000000000000000",
"0x1440000000000000000000000000000000000000",
"0x1550000000000000000000000000000000000000"
]
]
],
outputs: ["address[]"]
});
const expected = [
"0x0120000000000000000000000000000000000000",
"0x0340000000000000000000000000000000000000",
"0x1330000000000000000000000000000000000000",
"0x1440000000000000000000000000000000000000",
"0x1550000000000000000000000000000000000000"
];
assert.deepStrictEqual(resultArr[0].value, expected);
});
it("should delete the new wallet", async function () {
const { recoveryId, scheduledPurgeDate } = await api.wallet(createdWallet).delete();
assert.ok(recoveryId);
assert.ok(scheduledPurgeDate);
console.log(`soft deleted wallet ${recoveryId} and scheduled for purging at ${scheduledPurgeDate}`);
});
});