Skip to content

Commit

Permalink
GnosisSafe.setSigners()
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelomorgado committed Feb 28, 2019
1 parent f5ead9a commit b929ebd
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 31 deletions.
57 changes: 38 additions & 19 deletions packages/tasit-identity-contract/src/GnosisSafe.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { Contract, ERC20, ERC721 } = Action;
const { ERC20Detailed } = ERC20;
const { ERC721Full } = ERC721;
import GnosisSafeUtils from "./GnosisSafeUtils";
import ActionUtils from "tasit-action/dist/contract/Utils.js";

import gnosisSafeABI from "../../tasit-contracts/abi/GnosisSafe.json";
import erc20ABI from "../../tasit-contracts/abi/MyERC20Full.json";
Expand All @@ -25,32 +26,54 @@ const operations = {

const { CALL } = operations;

const areValidSigners = signers => {
const { isEthersJsSigner: isSigner } = ActionUtils;
const { isArray } = Array;

if (!isArray(signers)) return false;

const allAreValid = !signers.map(isSigner).includes(false);

if (!allAreValid) return false;

return true;
};

// Extended Gnosis Safe wallet contract with higher-level functions
export default class GnosisSafe extends Contract {
#utils;
#signers;

constructor(address, wallet) {
const abi = gnosisSafeABI;
super(address, abi, wallet);
this.#utils = new GnosisSafeUtils(this);
}

transferERC20 = async (signers, tokenAddress, toAddress, value) => {
setSigners = signers => {
if (!areValidSigners(signers))
throw new Error(
`Cannot set invalid signers for the Gnosis Safe contract.`
);

this.#signers = signers;
};

transferERC20 = async (tokenAddress, toAddress, value) => {
const data = this.#utils.encodeFunctionCall(erc20ABI, "transfer", [
toAddress,
value,
]);
const etherValue = "0";
const action = await this.#executeTransaction(
signers,
data,
tokenAddress,
etherValue
);
return action;
};

transferNFT = async (signers, tokenAddress, toAddress, tokenId) => {
transferNFT = async (tokenAddress, toAddress, tokenId) => {
const fromAddress = this.getAddress();
const data = this.#utils.encodeFunctionCall(erc721ABI, "safeTransferFrom", [
fromAddress,
Expand All @@ -59,47 +82,43 @@ export default class GnosisSafe extends Contract {
]);
const etherValue = "0";
const action = await this.#executeTransaction(
signers,
data,
tokenAddress,
etherValue
);
return action;
};

transferEther = async (signers, toAddress, value) => {
transferEther = async (toAddress, value) => {
const data = "0x";
const etherValue = value;
const action = await this.#executeTransaction(
signers,
data,
toAddress,
etherValue
);
const action = await this.#executeTransaction(data, toAddress, etherValue);
return action;
};

addSignerWithThreshold = async (signers, newSignerAddress, newThreshold) => {
addSignerWithThreshold = async (newSignerAddress, newThreshold) => {
const data = this.#utils.encodeFunctionCall(
this.getABI(),
"addOwnerWithThreshold",
[newSignerAddress, newThreshold]
);
const to = this.getAddress();
const etherValue = "0";
const action = await this.#executeTransaction(
signers,
data,
to,
etherValue
);
const action = await this.#executeTransaction(data, to, etherValue);
return action;
};

// Note: Should we move this function to sync to keep same behavior as
// contract's write functions that returns an Action object?
// See more: https://github.com/tasitlabs/TasitSDK/issues/234
#executeTransaction = async (signers, data, toAddress, etherValue) => {
#executeTransaction = async (data, toAddress, etherValue) => {
const signers = this.#signers;

if (!signers)
throw new Error(
`Cannot send an action to Gnosis Safe contract without signers.`
);

const to = toAddress;

const operation = CALL;
Expand Down
16 changes: 4 additions & 12 deletions packages/tasit-identity-contract/src/GnosisSafe.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ describe("GnosisSafe", () => {

ephemeralWallet = Account.create();

const signers = [johnWallet];

// Contract deployment setup with john (accounts[9]) as the only owner
// To change that, edit the file "tasit-contract/3rd-parties/gnosis/scripts/2_deploy_contracts.js"
gnosisSafe = new GnosisSafe(GNOSIS_SAFE_ADDRESS);
gnosisSafe.setSigners(signers);

erc20 = new ERC20Full(ERC20_ADDRESS);

Expand Down Expand Up @@ -65,16 +68,11 @@ describe("GnosisSafe", () => {
});

it("contract account should send ethers back to owner", async () => {
const signers = [johnWallet];
const { address: toAddress } = johnWallet;
const value = ONE;

gnosisSafe.setWallet(johnWallet);
const execTxAction = await gnosisSafe.transferEther(
signers,
toAddress,
value
);
const execTxAction = await gnosisSafe.transferEther(toAddress, value);
await execTxAction.waitForNonceToUpdate();

const balance = await provider.getBalance(GNOSIS_SAFE_ADDRESS);
Expand All @@ -90,14 +88,12 @@ describe("GnosisSafe", () => {
});

it("contract account should send ERC20 tokens back to owner", async () => {
const signers = [johnWallet];
const tokenAddress = ERC20_ADDRESS;
const { address: toAddress } = johnWallet;
const value = ONE;

gnosisSafe.setWallet(johnWallet);
const action = await gnosisSafe.transferERC20(
signers,
tokenAddress,
toAddress,
value
Expand All @@ -120,13 +116,11 @@ describe("GnosisSafe", () => {
});

it("contract account should send NFT tokens back to owner", async () => {
const signers = [johnWallet];
const tokenAddress = NFT_ADDRESS;
const { address: toAddress } = johnWallet;

gnosisSafe.setWallet(johnWallet);
const execTxAction = await gnosisSafe.transferNFT(
signers,
tokenAddress,
toAddress,
tokenId
Expand All @@ -147,13 +141,11 @@ describe("GnosisSafe", () => {
const thresholdBefore = await gnosisSafe.getThreshold();
expect(`${thresholdBefore}`).to.equal(`1`);

const signers = [johnWallet];
const { address: newSignerAddress } = ephemeralWallet;
const newThreshold = `2`;

gnosisSafe.setWallet(johnWallet);
const action = await gnosisSafe.addSignerWithThreshold(
signers,
newSignerAddress,
newThreshold
);
Expand Down

0 comments on commit b929ebd

Please sign in to comment.