Skip to content
This repository was archived by the owner on Feb 8, 2020. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
package.json
package-lock.json
node_modules/
92 changes: 92 additions & 0 deletions contracts/TipsWallet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
pragma solidity 0.4.18;

import "./AddressSet.sol";


contract TipsWallet {

//--- Definitions
using AddressSet for AddressSet.Data;

//--- Storage
AddressSet.Data private owners;

uint256 public lastSettledBalance;
mapping(address => uint256) public settledShares;

//--- Constructor
function TipsWallet(address[] _owners) public {
require(_owners.length > 0);

for (uint256 i = 0; i < _owners.length; i++) {
owners.add(_owners[i]);
}
}

//--- Modifiers
modifier onlyOwners() {
require(owners.contains(msg.sender));
_;
}

//--- Fallback
/* solhint-disable no-empty-blocks */
function() public payable {
// postpone distribution to settlement
// keep the gas usage as low as possible
}
/* solhint-enable no-empty-blocks */

//--- Public mutable functions
function withdraw(uint256 value) public {
require(value > 0);
uint256 balance = settledShares[msg.sender];

require(value <= balance);

subShare(msg.sender, value);
msg.sender.transfer(balance);
}

function settle() public onlyOwners {
if (this.balance > lastSettledBalance) {
uint256 share = (this.balance - lastSettledBalance) / owners.count;

address owner = owners.head;
for (uint256 i = 0; i < owners.count; i++) {
addShare(owner, share);
owner = owners.getNext(owner);
}

lastSettledBalance = this.balance;
}
}

//--- Public view functions
function getOwners() public view returns (address[] result) {
result = new address[](owners.count);

address current = owners.head;
for (uint256 i = 0; i < result.length; i++) {
result[i] = current;
current = owners.getNext(current);
}
}

function getUnsettledBalance() public view returns (uint256) {
return this.balance - lastSettledBalance;
}

//--- Private mutable functions
function addShare(address account, uint256 value) private {
uint256 current = settledShares[account];
settledShares[account] += value;
assert(settledShares[account] >= current); // check overflow
}

function subShare(address account, uint256 value) private {
uint256 current = settledShares[account];
assert(value <= current); // check underflow
settledShares[account] -= value;
}
}
156 changes: 8 additions & 148 deletions globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,150 +1,10 @@
declare interface Web3 {
toAscii(hex: string): string;
fromAscii(ascii: string, padding?: number): string;
sha3(str: string, options?: { encoding: 'hex' }): string;
}

declare interface ContractBase {
address: string;
}

declare interface Contract<T> extends ContractBase {
deployed(): Promise<T>;
}

declare type TransactionOptions = {
from?: string;
gas?: number;
gasPrice?: number;
};

declare type TransactionReceipt = {
transactionHash: string;
transactionIndex: number;
blockHash: string;
blockNumber: number;
gasUsed: number;
cumulativeGasUsed: number;
contractAddress: string | null;
logs: [TransactionLog];
};

declare type TransactionLog = {
logIndex: number;
transactionIndex: number;
transactionHash: string;
blockHash: string;
blockNumber: number;
address: string;
type: string;
event: string;
args: any;
};

declare type TransactionResult = {
tx: string;
receipt: TransactionReceipt;
logs: [TransactionLog];
};

declare interface MigrationsContract extends Contract<Migrations> {
'new'(options?: TransactionOptions): Promise<Migrations>;
}

declare interface AddressSetLibrary extends Contract<AddressSet> {
'new'(options?: TransactionOptions): Promise<AddressSet>;
}

declare interface SignHashContract extends Contract<SignHash> {
'new'(options?: TransactionOptions): Promise<SignHash>;
}

declare interface SignHash {
sign(hash: string, options?: TransactionOptions): Promise<TransactionResult>;
revoke(
hash: string,
options?: TransactionOptions
): Promise<TransactionResult>;

addProof(
method: string,
value: string,
options?: TransactionOptions
): Promise<TransactionResult>;

removeProof(
method: string,
options?: TransactionOptions
): Promise<TransactionResult>;

getSigners(hash: string, maxCount: number): Promise<string[]>;

getProof(signer: string, method: string): Promise<string>;
}
import { SignHashArtifacts } from 'signhash';
import { ContractContextDefinition } from 'truffle';
import { Web3 } from 'web3';

declare interface Signed {
hash: string;
signer: string;
declare global {
const artifacts: SignHashArtifacts;
const web3: Web3;
const contract: ContractContextDefinition;
const assert: Chai.Assert;
}

declare interface Revoked {
hash: string;
signer: string;
}

declare interface ProofAdded {
signer: string;
method: string;
value: string;
}

declare interface ProofRemoved {
signer: string;
method: string;
}

declare interface Migrations {
setCompleted(
completed: number,
options?: TransactionOptions
): Promise<TransactionResult>;

upgrade(
address: string,
options?: TransactionOptions
): Promise<TransactionResult>;
}

declare interface AddressSet {
get(): Promise<string[]>;

add(
element: string,
options?: TransactionOptions
): Promise<TransactionResult>;
}

declare interface Artifacts {
require(name: './Migrations.sol'): MigrationsContract;
require(name: './AddressSet.sol'): AddressSetLibrary;
require(name: './SignHash.sol'): SignHashContract;
require(name: string): ContractBase;
}

declare interface Deployer extends Promise<void> {
deploy(object: ContractBase): Promise<void>;

link(
library: ContractBase,
contracts: ContractBase | [ContractBase]
): Promise<void>;
}

interface ContractContextDefinition extends Mocha.IContextDefinition {
(description: string, callback: (accounts: string[]) => void): Mocha.ISuite;
}

declare const artifacts: Artifacts;
declare const contract: ContractContextDefinition;
declare const assert: Chai.Assert;
declare const web3: Web3;
126 changes: 126 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
declare module 'signhash' {
import { BigNumber } from 'bignumber.js';

import {
Artifacts,
Contract,
DeployedContractBase,
TransactionOptions,
TransactionResult
} from 'truffle';

import { Address } from 'web3';

interface MigrationsContract extends Contract<Migrations> {
'new'(options?: TransactionOptions): Promise<Migrations>;
}

interface AddressSetLibrary extends Contract<AddressSet> {
'new'(options?: TransactionOptions): Promise<AddressSet>;
}

interface SignHashContract extends Contract<SignHash> {
'new'(options?: TransactionOptions): Promise<SignHash>;
}

interface TipsWalletContract extends Contract<SignHash> {
'new'(
developers: Address[],
options?: TransactionOptions
): Promise<TipsWallet>;
}

interface SignHash extends DeployedContractBase {
sign(
hash: string,
options?: TransactionOptions
): Promise<TransactionResult>;

revoke(
hash: string,
options?: TransactionOptions
): Promise<TransactionResult>;

addProof(
method: string,
value: string,
options?: TransactionOptions
): Promise<TransactionResult>;

removeProof(
method: string,
options?: TransactionOptions
): Promise<TransactionResult>;

getSigners(
hash: string,
maxCount: number | string | BigNumber
): Promise<Address[]>;

getProof(signer: Address, method: string): Promise<string>;
}

interface Signed {
hash: string;
signer: Address;
}

interface Revoked {
hash: string;
signer: Address;
}

interface ProofAdded {
signer: Address;
method: string;
value: string;
}

interface ProofRemoved {
signer: Address;
method: string;
}

interface TipsWallet extends DeployedContractBase {
getOwners(): Promise<Address[]>;

getUnsettledBalance(): Promise<BigNumber>;

settledShares(account: Address): Promise<BigNumber>;

settle(options?: TransactionOptions): Promise<void>;

withdraw(
value: number | string | BigNumber,
options?: TransactionOptions
): Promise<void>;
}

interface Migrations extends DeployedContractBase {
setCompleted(
completed: number | string | BigNumber,
options?: TransactionOptions
): Promise<TransactionResult>;

upgrade(
address: Address,
options?: TransactionOptions
): Promise<TransactionResult>;
}

interface AddressSet {
get(): Promise<Address[]>;

add(
element: Address,
options?: TransactionOptions
): Promise<TransactionResult>;
}

interface SignHashArtifacts extends Artifacts {
require(name: './Migrations.sol'): MigrationsContract;
require(name: './AddressSet.sol'): AddressSetLibrary;
require(name: './SignHash.sol'): SignHashContract;
require(name: './TipsWallet.sol'): TipsWalletContract;
}
}
2 changes: 2 additions & 0 deletions migrations/1_initial_migration.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Deployer } from 'truffle';

const Migrations = artifacts.require('./Migrations.sol');

async function deploy(deployer: Deployer): Promise<void> {
Expand Down
2 changes: 2 additions & 0 deletions migrations/2_deploy_contracts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Deployer } from 'truffle';

const SignHash = artifacts.require('./SignHash.sol');

async function deploy(deployer: Deployer): Promise<void> {
Expand Down
Loading