From d66e50dad646287a2e3602f2288207a17dea9a4a Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Fri, 31 Aug 2018 14:48:43 -0500 Subject: [PATCH] Changes to address Rob's comments. Added generic/event_triggered transformer, tests, and repo migrations for Burn and Mint events --- ...911134701_create_token_burn_table.down.sql | 1 + ...80911134701_create_token_burn_table.up.sql | 13 + ...911134708_create_token_mint_table.down.sql | 1 + ...80911134708_create_token_mint_table.up.sql | 14 + examples/constants/constants.go | 102 ++++--- .../event_triggered/converter.go | 58 ++-- .../event_triggered/converter_test.go | 73 ++--- .../erc20_watcher/event_triggered/entity.go | 3 +- .../event_triggered/integration_test.go | 111 +++----- .../event_triggered/repository.go | 24 +- .../event_triggered/repository_test.go | 24 +- .../event_triggered/transformer.go | 36 +-- .../event_triggered/transformer_test.go | 65 ++--- .../every_block/every_block_suite_test.go | 4 +- examples/erc20_watcher/every_block/getter.go | 14 +- .../erc20_watcher/every_block/getter_test.go | 2 +- .../every_block/integration_test.go | 6 +- .../erc20_watcher/every_block/repository.go | 5 +- .../every_block/repository_test.go | 3 +- .../erc20_watcher/every_block/transformer.go | 20 +- .../every_block/transformer_test.go | 20 +- examples/generic/config.go | 12 +- examples/generic/event_triggered/converter.go | 117 ++++++++ .../generic/event_triggered/converter_test.go | 148 ++++++++++ examples/generic/event_triggered/entity.go | 39 +++ .../event_triggered_suite_test.go | 27 ++ .../event_triggered/integration_test.go | 133 +++++++++ examples/generic/event_triggered/model.go | 34 +++ .../generic/event_triggered/repository.go | 50 ++++ .../event_triggered/repository_test.go | 229 ++++++++++++++++ .../generic/event_triggered/transformer.go | 87 ++++++ .../event_triggered/transformer_test.go | 111 ++++++++ .../every_block/every_block_suite_test.go | 4 +- examples/generic/every_block/getter.go | 26 +- examples/generic/every_block/getter_test.go | 5 +- examples/generic/fetcher.go | 1 + examples/generic/helpers/helpers.go | 1 + examples/generic/retriever.go | 95 +++++-- examples/mocks/converter.go | 78 ++++++ examples/mocks/event_repo.go | 47 +++- examples/mocks/fetcher.go | 3 +- examples/mocks/getter.go | 1 + examples/test_helpers/database.go | 53 ++++ integration_test/contract_test.go | 1 + integration_test/geth_blockchain_test.go | 1 + .../integration_test_suite_test.go | 4 +- test_config/test_config.go | 2 +- utils/utils.go | 5 +- .../btcsuite/btcd/btcec/btcec_test.go | 252 +++++++++--------- 49 files changed, 1688 insertions(+), 477 deletions(-) create mode 100644 db/migrations/20180911134701_create_token_burn_table.down.sql create mode 100644 db/migrations/20180911134701_create_token_burn_table.up.sql create mode 100644 db/migrations/20180911134708_create_token_mint_table.down.sql create mode 100644 db/migrations/20180911134708_create_token_mint_table.up.sql create mode 100644 examples/generic/event_triggered/converter.go create mode 100644 examples/generic/event_triggered/converter_test.go create mode 100644 examples/generic/event_triggered/entity.go create mode 100644 examples/generic/event_triggered/event_triggered_suite_test.go create mode 100644 examples/generic/event_triggered/integration_test.go create mode 100644 examples/generic/event_triggered/model.go create mode 100644 examples/generic/event_triggered/repository.go create mode 100644 examples/generic/event_triggered/repository_test.go create mode 100644 examples/generic/event_triggered/transformer.go create mode 100644 examples/generic/event_triggered/transformer_test.go create mode 100644 examples/mocks/converter.go diff --git a/db/migrations/20180911134701_create_token_burn_table.down.sql b/db/migrations/20180911134701_create_token_burn_table.down.sql new file mode 100644 index 00000000..f22d52c6 --- /dev/null +++ b/db/migrations/20180911134701_create_token_burn_table.down.sql @@ -0,0 +1 @@ +DROP TABLE token_burns; \ No newline at end of file diff --git a/db/migrations/20180911134701_create_token_burn_table.up.sql b/db/migrations/20180911134701_create_token_burn_table.up.sql new file mode 100644 index 00000000..b2a25217 --- /dev/null +++ b/db/migrations/20180911134701_create_token_burn_table.up.sql @@ -0,0 +1,13 @@ +CREATE TABLE token_burns ( + id SERIAL, + vulcanize_log_id INTEGER NOT NULL UNIQUE, + token_name CHARACTER VARYING(66) NOT NULL, + token_address CHARACTER VARYING(66) NOT NULL, + burner CHARACTER VARYING(66) NOT NULL, + tokens DECIMAL NOT NULL, + block INTEGER NOT NULL, + tx CHARACTER VARYING(66) NOT NULL, + CONSTRAINT log_index_fk FOREIGN KEY (vulcanize_log_id) + REFERENCES logs (id) + ON DELETE CASCADE +) \ No newline at end of file diff --git a/db/migrations/20180911134708_create_token_mint_table.down.sql b/db/migrations/20180911134708_create_token_mint_table.down.sql new file mode 100644 index 00000000..0725fcb9 --- /dev/null +++ b/db/migrations/20180911134708_create_token_mint_table.down.sql @@ -0,0 +1 @@ +DROP TABLE token_mints; \ No newline at end of file diff --git a/db/migrations/20180911134708_create_token_mint_table.up.sql b/db/migrations/20180911134708_create_token_mint_table.up.sql new file mode 100644 index 00000000..85396e7d --- /dev/null +++ b/db/migrations/20180911134708_create_token_mint_table.up.sql @@ -0,0 +1,14 @@ +CREATE TABLE token_mints ( + id SERIAL, + vulcanize_log_id INTEGER NOT NULL UNIQUE, + token_name CHARACTER VARYING(66) NOT NULL, + token_address CHARACTER VARYING(66) NOT NULL, + minter CHARACTER VARYING(66) NOT NULL, + mintee CHARACTER VARYING(66) NOT NULL, + tokens DECIMAL NOT NULL, + block INTEGER NOT NULL, + tx CHARACTER VARYING(66) NOT NULL, + CONSTRAINT log_index_fk FOREIGN KEY (vulcanize_log_id) + REFERENCES logs (id) + ON DELETE CASCADE +) \ No newline at end of file diff --git a/examples/constants/constants.go b/examples/constants/constants.go index 3a8d3a4d..3c708224 100644 --- a/examples/constants/constants.go +++ b/examples/constants/constants.go @@ -15,61 +15,95 @@ package constants import ( - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/vulcanize/vulcanizedb/examples/generic/helpers" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/filters" - "github.com/vulcanize/vulcanizedb/pkg/geth" - "log" ) -var err error +// Event enums +type Event int -//Contract Addresses +const ( + TransferEvent Event = 0 + ApprovalEvent Event = 1 + BurnEvent Event = 2 + MintEvent Event = 3 +) + +func (e Event) String() string { + strings := [...]string{ + "Transfer", + "Approval", + "Burn", + "Mint", + } + + if e < TransferEvent || e > MintEvent { + return "Unknown" + } + + return strings[e] +} + +func (e Event) Signature() string { + strings := [...]string{ + helpers.GenerateSignature("Transfer(address,address,uint)"), + helpers.GenerateSignature("Approval(address,address,uint)"), + helpers.GenerateSignature("Burn(address,uint)"), + helpers.GenerateSignature("Mint(address,uint)"), + } + + if e < TransferEvent || e > MintEvent { + return "Unknown" + } + + return strings[e] +} + +// Contract Addresses var DaiContractAddress = "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359" var TusdContractAddress = "0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E" -//Abis - -var ParsedDaiAbi abi.ABI +// Contract Owner +var DaiContractOwner = "0x0000000000000000000000000000000000000000" +var TusdContractOwner = "0x9978d2d229a69b3aef93420d132ab22b44e3578f" +// Contract Abis var DaiAbiString = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"name_","type":"bytes32"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"push","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"move","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"start","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"},{"name":"guy","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"wad","type":"uint256"}],"name":"pull","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"symbol_","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"}]` -var ParsedTusdAbi abi.ABI - var TusdAbiString = `[{"constant":true,"inputs":[],"name":"burnMin","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"delegateAllowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"burnFeeFlat","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_canReceiveMintWhiteList","type":"address"},{"name":"_canBurnWhiteList","type":"address"},{"name":"_blackList","type":"address"},{"name":"_noFeesList","type":"address"}],"name":"setLists","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"}],"name":"reclaimToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newContract","type":"address"}],"name":"delegateToNewContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_transferFeeNumerator","type":"uint80"},{"name":"_transferFeeDenominator","type":"uint80"},{"name":"_mintFeeNumerator","type":"uint80"},{"name":"_mintFeeDenominator","type":"uint80"},{"name":"_mintFeeFlat","type":"uint256"},{"name":"_burnFeeNumerator","type":"uint80"},{"name":"_burnFeeDenominator","type":"uint80"},{"name":"_burnFeeFlat","type":"uint256"}],"name":"changeStakingFees","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"canReceiveMintWhiteList","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"delegatedFrom","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"},{"name":"origSender","type":"address"}],"name":"delegateApprove","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"contractAddr","type":"address"}],"name":"reclaimContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"allowances","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"delegateBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"origSender","type":"address"}],"name":"delegateTransferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claimOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sheet","type":"address"}],"name":"setBalanceSheet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"addedValue","type":"uint256"},{"name":"origSender","type":"address"}],"name":"delegateIncreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"burnFeeNumerator","outputs":[{"name":"","type":"uint80"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"canBurnWhiteList","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"burnMax","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mintFeeDenominator","outputs":[{"name":"","type":"uint80"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"staker","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"setDelegatedFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"noFeesList","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newMin","type":"uint256"},{"name":"newMax","type":"uint256"}],"name":"changeBurnBounds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"delegateTotalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"balances","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"}],"name":"changeName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"mintFeeNumerator","outputs":[{"name":"","type":"uint80"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"transferFeeNumerator","outputs":[{"name":"","type":"uint80"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"subtractedValue","type":"uint256"},{"name":"origSender","type":"address"}],"name":"delegateDecreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"origSender","type":"address"}],"name":"delegateTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"reclaimEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newStaker","type":"address"}],"name":"changeStaker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"wipeBlacklistedAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"from_","type":"address"},{"name":"value_","type":"uint256"},{"name":"data_","type":"bytes"}],"name":"tokenFallback","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"burnFeeDenominator","outputs":[{"name":"","type":"uint80"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"blackList","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"transferFeeDenominator","outputs":[{"name":"","type":"uint80"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mintFeeFlat","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"sheet","type":"address"}],"name":"setAllowanceSheet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":false,"stateMutability":"nonpayable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newMin","type":"uint256"},{"indexed":false,"name":"newMax","type":"uint256"}],"name":"ChangeBurnBoundsEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"WipedAccount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"newContract","type":"address"}],"name":"DelegatedTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"burner","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]` -// Parsed abi initialization -func init() { - ParsedDaiAbi, err = geth.ParseAbi(DaiAbiString) - if err != nil { - log.Fatal("constants: unable to parse dai abi") - } - - ParsedTusdAbi, err = geth.ParseAbi(TusdAbiString) - if err != nil { - log.Fatal("constants: unable to parse true usd abi") - } -} - -// Hashed event signatures -var TransferEventSignature = helpers.GenerateSignature("Transfer(address,address,uint)") -var ApprovalEventSignature = helpers.GenerateSignature("Approval(address,address,uint)") - // Filters -var DaiFilters = []filters.LogFilter{ +var DaiERC20Filters = []filters.LogFilter{ { - Name: "Transfer", - FromBlock: 0, + Name: TransferEvent.String(), + FromBlock: 4752008, ToBlock: -1, Address: DaiContractAddress, - Topics: core.Topics{TransferEventSignature}, + Topics: core.Topics{TransferEvent.Signature()}, }, { - Name: "Approval", - FromBlock: 0, + Name: ApprovalEvent.String(), + FromBlock: 4752008, ToBlock: -1, Address: DaiContractAddress, - Topics: core.Topics{ApprovalEventSignature}, + Topics: core.Topics{ApprovalEvent.Signature()}, + }, +} + +var TusdGenericFilters = []filters.LogFilter{ + { + Name: BurnEvent.String(), + FromBlock: 5197514, + ToBlock: -1, + Address: TusdContractAddress, + Topics: core.Topics{BurnEvent.Signature()}, + }, + { + Name: MintEvent.String(), + FromBlock: 5197514, + ToBlock: -1, + Address: TusdContractAddress, + Topics: core.Topics{MintEvent.Signature()}, }, } diff --git a/examples/erc20_watcher/event_triggered/converter.go b/examples/erc20_watcher/event_triggered/converter.go index c75c5269..563b24f1 100644 --- a/examples/erc20_watcher/event_triggered/converter.go +++ b/examples/erc20_watcher/event_triggered/converter.go @@ -17,9 +17,12 @@ package event_triggered import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/generic" "github.com/vulcanize/vulcanizedb/examples/generic/helpers" "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/geth" ) // Converter converts a raw event log into its corresponding entity @@ -27,26 +30,35 @@ import ( type ERC20ConverterInterface interface { ToTransferEntity(watchedEvent core.WatchedEvent) (*TransferEntity, error) - ToTransferModel(entity TransferEntity) TransferModel + ToTransferModel(entity *TransferEntity) *TransferModel ToApprovalEntity(watchedEvent core.WatchedEvent) (*ApprovalEntity, error) - ToApprovalModel(entity ApprovalEntity) ApprovalModel + ToApprovalModel(entity *ApprovalEntity) *ApprovalModel } type ERC20Converter struct { config generic.ContractConfig } -func NewERC20Converter(config generic.ContractConfig) ERC20Converter { - return ERC20Converter{ +func NewERC20Converter(config generic.ContractConfig) (*ERC20Converter, error) { + var err error + + config.ParsedAbi, err = geth.ParseAbi(config.Abi) + if err != nil { + return nil, err + } + + converter := &ERC20Converter{ config: config, } + + return converter, nil } func (c ERC20Converter) ToTransferEntity(watchedEvent core.WatchedEvent) (*TransferEntity, error) { result := &TransferEntity{} contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) event := helpers.ConvertToLog(watchedEvent) - err := contract.UnpackLog(result, "Transfer", event) + err := contract.UnpackLog(result, constants.TransferEvent.String(), event) if err != nil { return result, err } @@ -58,20 +70,19 @@ func (c ERC20Converter) ToTransferEntity(watchedEvent core.WatchedEvent) (*Trans return result, nil } -func (c ERC20Converter) ToTransferModel(transferEntity TransferEntity) TransferModel { - to := transferEntity.Dst.String() - from := transferEntity.Src.String() - tokens := transferEntity.Wad.String() - block := transferEntity.Block - tx := transferEntity.TxHash - return TransferModel{ +func (c ERC20Converter) ToTransferModel(entity *TransferEntity) *TransferModel { + to := entity.Dst.String() + from := entity.Src.String() + tokens := entity.Wad.String() + + return &TransferModel{ TokenName: c.config.Name, TokenAddress: c.config.Address, To: to, From: from, Tokens: tokens, - Block: block, - TxHash: tx, + Block: entity.Block, + TxHash: entity.TxHash, } } @@ -79,7 +90,7 @@ func (c ERC20Converter) ToApprovalEntity(watchedEvent core.WatchedEvent) (*Appro result := &ApprovalEntity{} contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) event := helpers.ConvertToLog(watchedEvent) - err := contract.UnpackLog(result, "Approval", event) + err := contract.UnpackLog(result, constants.ApprovalEvent.String(), event) if err != nil { return result, err } @@ -91,19 +102,18 @@ func (c ERC20Converter) ToApprovalEntity(watchedEvent core.WatchedEvent) (*Appro return result, nil } -func (c ERC20Converter) ToApprovalModel(TransferEntity ApprovalEntity) ApprovalModel { - tokenOwner := TransferEntity.Src.String() - spender := TransferEntity.Guy.String() - tokens := TransferEntity.Wad.String() - block := TransferEntity.Block - tx := TransferEntity.TxHash - return ApprovalModel{ +func (c ERC20Converter) ToApprovalModel(entity *ApprovalEntity) *ApprovalModel { + tokenOwner := entity.Src.String() + spender := entity.Guy.String() + tokens := entity.Wad.String() + + return &ApprovalModel{ TokenName: c.config.Name, TokenAddress: c.config.Address, Owner: tokenOwner, Spender: spender, Tokens: tokens, - Block: block, - TxHash: tx, + Block: entity.Block, + TxHash: entity.TxHash, } } diff --git a/examples/erc20_watcher/event_triggered/converter_test.go b/examples/erc20_watcher/event_triggered/converter_test.go index 5a95a966..49242077 100644 --- a/examples/erc20_watcher/event_triggered/converter_test.go +++ b/examples/erc20_watcher/event_triggered/converter_test.go @@ -18,6 +18,7 @@ import ( "github.com/ethereum/go-ethereum/common" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" "github.com/vulcanize/vulcanizedb/examples/generic" @@ -27,7 +28,7 @@ import ( var expectedTransferModel = event_triggered.TransferModel{ TokenName: "Dai", - TokenAddress: "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359", + TokenAddress: constants.DaiContractAddress, To: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", From: "0x000000000000000000000000000000000000Af21", Tokens: "1097077688018008265106216665536940668749033598146", @@ -37,7 +38,7 @@ var expectedTransferModel = event_triggered.TransferModel{ var expectedTransferEntity = event_triggered.TransferEntity{ TokenName: "Dai", - TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), + TokenAddress: common.HexToAddress(constants.DaiContractAddress), Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), Dst: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), Wad: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), @@ -47,7 +48,7 @@ var expectedTransferEntity = event_triggered.TransferEntity{ var expectedApprovalModel = event_triggered.ApprovalModel{ TokenName: "Dai", - TokenAddress: "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359", + TokenAddress: constants.DaiContractAddress, Owner: "0x000000000000000000000000000000000000Af21", Spender: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", Tokens: "1097077688018008265106216665536940668749033598146", @@ -57,7 +58,7 @@ var expectedApprovalModel = event_triggered.ApprovalModel{ var expectedApprovalEntity = event_triggered.ApprovalEntity{ TokenName: "Dai", - TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), + TokenAddress: common.HexToAddress(constants.DaiContractAddress), Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), Guy: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), Wad: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), @@ -67,12 +68,12 @@ var expectedApprovalEntity = event_triggered.ApprovalEntity{ var transferEvent = core.WatchedEvent{ LogID: 1, - Name: "Transfer", + Name: constants.TransferEvent.String(), BlockNumber: 5488076, Address: constants.DaiContractAddress, TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", Index: 110, - Topic0: constants.TransferEventSignature, + Topic0: constants.TransferEvent.Signature(), Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", Topic3: "", @@ -81,12 +82,12 @@ var transferEvent = core.WatchedEvent{ var approvalEvent = core.WatchedEvent{ LogID: 1, - Name: "Approval", + Name: constants.ApprovalEvent.String(), BlockNumber: 5488076, Address: constants.DaiContractAddress, TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", Index: 110, - Topic0: constants.ApprovalEventSignature, + Topic0: constants.ApprovalEvent.Signature(), Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", Topic3: "", @@ -95,20 +96,19 @@ var approvalEvent = core.WatchedEvent{ var _ = Describe("Transfer Converter", func() { - daiConverter := event_triggered.NewERC20Converter(generic.DaiConfig) + var daiConverter *event_triggered.ERC20Converter + var err error + + BeforeEach(func() { + daiConverter, err = event_triggered.NewERC20Converter(generic.DaiConfig) + Expect(err).NotTo(HaveOccurred()) + }) It("converts a watched transfer event into a TransferEntity", func() { result, err := daiConverter.ToTransferEntity(transferEvent) Expect(err).NotTo(HaveOccurred()) - - Expect(result.TokenName).To(Equal(expectedTransferEntity.TokenName)) - Expect(result.TokenAddress).To(Equal(expectedTransferEntity.TokenAddress)) - Expect(result.Dst).To(Equal(expectedTransferEntity.Dst)) - Expect(result.Src).To(Equal(expectedTransferEntity.Src)) - Expect(result.Wad).To(Equal(expectedTransferEntity.Wad)) - Expect(result.Block).To(Equal(expectedTransferEntity.Block)) - Expect(result.TxHash).To(Equal(expectedTransferEntity.TxHash)) + Expect(result).To(Equal(&expectedTransferEntity)) }) It("converts a TransferEntity to an TransferModel", func() { @@ -116,35 +116,27 @@ var _ = Describe("Transfer Converter", func() { result, err := daiConverter.ToTransferEntity(transferEvent) Expect(err).NotTo(HaveOccurred()) - model := daiConverter.ToTransferModel(*result) - - Expect(model.TokenName).To(Equal(expectedTransferModel.TokenName)) - Expect(model.TokenAddress).To(Equal(expectedTransferModel.TokenAddress)) - Expect(model.To).To(Equal(expectedTransferModel.To)) - Expect(model.From).To(Equal(expectedTransferModel.From)) - Expect(model.Tokens).To(Equal(expectedTransferModel.Tokens)) - Expect(model.Block).To(Equal(expectedTransferModel.Block)) - Expect(model.TxHash).To(Equal(expectedTransferModel.TxHash)) + model := daiConverter.ToTransferModel(result) + Expect(model).To(Equal(&expectedTransferModel)) }) }) var _ = Describe("Approval Converter", func() { - daiConverter := event_triggered.NewERC20Converter(generic.DaiConfig) + var daiConverter *event_triggered.ERC20Converter + var err error + + BeforeEach(func() { + daiConverter, err = event_triggered.NewERC20Converter(generic.DaiConfig) + Expect(err).NotTo(HaveOccurred()) + }) It("converts a watched approval event into a ApprovalEntity", func() { result, err := daiConverter.ToApprovalEntity(approvalEvent) Expect(err).NotTo(HaveOccurred()) - - Expect(result.TokenName).To(Equal(expectedApprovalEntity.TokenName)) - Expect(result.TokenAddress).To(Equal(expectedApprovalEntity.TokenAddress)) - Expect(result.Src).To(Equal(expectedApprovalEntity.Src)) - Expect(result.Guy).To(Equal(expectedApprovalEntity.Guy)) - Expect(result.Wad).To(Equal(expectedApprovalEntity.Wad)) - Expect(result.Block).To(Equal(expectedApprovalEntity.Block)) - Expect(result.TxHash).To(Equal(expectedApprovalEntity.TxHash)) + Expect(result).To(Equal(&expectedApprovalEntity)) }) It("converts a ApprovalEntity to an ApprovalModel", func() { @@ -152,15 +144,8 @@ var _ = Describe("Approval Converter", func() { result, err := daiConverter.ToApprovalEntity(approvalEvent) Expect(err).NotTo(HaveOccurred()) - model := daiConverter.ToApprovalModel(*result) - - Expect(model.TokenName).To(Equal(expectedApprovalModel.TokenName)) - Expect(model.TokenAddress).To(Equal(expectedApprovalModel.TokenAddress)) - Expect(model.Owner).To(Equal(expectedApprovalModel.Owner)) - Expect(model.Spender).To(Equal(expectedApprovalModel.Spender)) - Expect(model.Tokens).To(Equal(expectedApprovalModel.Tokens)) - Expect(model.Block).To(Equal(expectedApprovalModel.Block)) - Expect(model.TxHash).To(Equal(expectedApprovalModel.TxHash)) + model := daiConverter.ToApprovalModel(result) + Expect(model).To(Equal(&expectedApprovalModel)) }) }) diff --git a/examples/erc20_watcher/event_triggered/entity.go b/examples/erc20_watcher/event_triggered/entity.go index f8e3114c..f3cfce2f 100644 --- a/examples/erc20_watcher/event_triggered/entity.go +++ b/examples/erc20_watcher/event_triggered/entity.go @@ -15,8 +15,9 @@ package event_triggered import ( - "github.com/ethereum/go-ethereum/common" "math/big" + + "github.com/ethereum/go-ethereum/common" ) type TransferEntity struct { diff --git a/examples/erc20_watcher/event_triggered/integration_test.go b/examples/erc20_watcher/event_triggered/integration_test.go index d7cfe305..856d7d59 100644 --- a/examples/erc20_watcher/event_triggered/integration_test.go +++ b/examples/erc20_watcher/event_triggered/integration_test.go @@ -22,12 +22,8 @@ import ( "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" "github.com/vulcanize/vulcanizedb/examples/generic" "github.com/vulcanize/vulcanizedb/examples/test_helpers" - "github.com/vulcanize/vulcanizedb/pkg/config" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "math/rand" - "time" ) var transferLog = core.Log{ @@ -36,7 +32,7 @@ var transferLog = core.Log{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", Index: 110, Topics: [4]string{ - constants.TransferEventSignature, + constants.TransferEvent.Signature(), "0x000000000000000000000000000000000000000000000000000000000000af21", "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", "", @@ -50,7 +46,7 @@ var approvalLog = core.Log{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", Index: 110, Topics: [4]string{ - constants.ApprovalEventSignature, + constants.ApprovalEvent.Signature(), "0x000000000000000000000000000000000000000000000000000000000000af21", "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", "", @@ -74,100 +70,65 @@ var logs = []core.Log{ var _ = Describe("Integration test with vulcanizedb", func() { var db *postgres.DB - rand.Seed(time.Now().UnixNano()) BeforeEach(func() { - var err error - db, err = postgres.NewDB(config.Database{ - Hostname: "localhost", - Name: "vulcanize_private", - Port: 5432, - }, core.Node{}) - Expect(err).NotTo(HaveOccurred()) - - receiptRepository := repositories.ReceiptRepository{DB: db} - blockRepository := *repositories.NewBlockRepository(db) - - blockNumber := rand.Int63() - blockId := test_helpers.CreateBlock(blockNumber, blockRepository) - - receipt := core.Receipt{ - Logs: logs, - } - receipts := []core.Receipt{receipt} - - err = receiptRepository.CreateReceiptsAndLogs(blockId, receipts) - Expect(err).ToNot(HaveOccurred()) - - var vulcanizeLogIds []int64 - err = db.Select(&vulcanizeLogIds, `SELECT id FROM logs`) - Expect(err).ToNot(HaveOccurred()) - + db = test_helpers.SetupIntegrationDB(db, logs) }) AfterEach(func() { - _, err := db.Exec(`DELETE FROM token_transfers`) - Expect(err).ToNot(HaveOccurred()) - _, err = db.Exec(`DELETE FROM token_approvals`) - Expect(err).ToNot(HaveOccurred()) - _, err = db.Exec(`DELETE FROM log_filters`) - Expect(err).ToNot(HaveOccurred()) - _, err = db.Exec(`DELETE FROM logs`) - Expect(err).ToNot(HaveOccurred()) + db = test_helpers.TearDownIntegrationDB(db) }) - It("creates transfer entry for each Transfer event received", func() { - transformer := event_triggered.NewTransformer(db, generic.DaiConfig) + It("creates token_transfers entry for each Transfer event received", func() { + transformer, err := event_triggered.NewTransformer(db, generic.DaiConfig) + Expect(err).ToNot(HaveOccurred()) transformer.Execute() var count int - err := db.QueryRow(`SELECT COUNT(*) FROM token_transfers`).Scan(&count) + err = db.QueryRow(`SELECT COUNT(*) FROM token_transfers`).Scan(&count) Expect(err).ToNot(HaveOccurred()) Expect(count).To(Equal(1)) - type dbRow struct { - DBID uint64 `db:"id"` - VulcanizeLogID int64 `db:"vulcanize_log_id"` - event_triggered.TransferModel - } - var transfer dbRow - err = db.Get(&transfer, `SELECT * FROM token_transfers WHERE block=$1`, logs[0].BlockNumber) + transfer := event_triggered.TransferModel{} + + err = db.Get(&transfer, `SELECT + token_name, + token_address, + to_address, + from_address, + tokens, + block, + tx + FROM token_transfers WHERE block=$1`, logs[0].BlockNumber) Expect(err).ToNot(HaveOccurred()) - Expect(transfer.TokenName).To(Equal(expectedTransferModel.TokenName)) - Expect(transfer.TokenAddress).To(Equal(expectedTransferModel.TokenAddress)) - Expect(transfer.To).To(Equal(expectedTransferModel.To)) - Expect(transfer.From).To(Equal(expectedTransferModel.From)) - Expect(transfer.Tokens).To(Equal(expectedTransferModel.Tokens)) - Expect(transfer.Block).To(Equal(expectedTransferModel.Block)) - Expect(transfer.TxHash).To(Equal(expectedTransferModel.TxHash)) + Expect(transfer).To(Equal(expectedTransferModel)) }) - It("creates approval entry for each Approval event received", func() { - transformer := event_triggered.NewTransformer(db, generic.DaiConfig) + It("creates token_approvals entry for each Approval event received", func() { + transformer, err := event_triggered.NewTransformer(db, generic.DaiConfig) + Expect(err).ToNot(HaveOccurred()) transformer.Execute() var count int - err := db.QueryRow(`SELECT COUNT(*) FROM token_approvals`).Scan(&count) + err = db.QueryRow(`SELECT COUNT(*) FROM token_approvals`).Scan(&count) Expect(err).ToNot(HaveOccurred()) Expect(count).To(Equal(1)) - type dbRow struct { - DBID uint64 `db:"id"` - VulcanizeLogID int64 `db:"vulcanize_log_id"` - event_triggered.ApprovalModel - } - var transfer dbRow - err = db.Get(&transfer, `SELECT * FROM token_approvals WHERE block=$1`, logs[0].BlockNumber) + approval := event_triggered.ApprovalModel{} + + err = db.Get(&approval, `SELECT + token_name, + token_address, + owner, + spender, + tokens, + block, + tx + FROM token_approvals WHERE block=$1`, logs[0].BlockNumber) Expect(err).ToNot(HaveOccurred()) - Expect(transfer.TokenName).To(Equal(expectedApprovalModel.TokenName)) - Expect(transfer.TokenAddress).To(Equal(expectedApprovalModel.TokenAddress)) - Expect(transfer.Owner).To(Equal(expectedApprovalModel.Owner)) - Expect(transfer.Spender).To(Equal(expectedApprovalModel.Spender)) - Expect(transfer.Tokens).To(Equal(expectedApprovalModel.Tokens)) - Expect(transfer.Block).To(Equal(expectedApprovalModel.Block)) - Expect(transfer.TxHash).To(Equal(expectedApprovalModel.TxHash)) + Expect(approval).To(Equal(expectedApprovalModel)) }) }) diff --git a/examples/erc20_watcher/event_triggered/repository.go b/examples/erc20_watcher/event_triggered/repository.go index 37981541..d9238a69 100644 --- a/examples/erc20_watcher/event_triggered/repository.go +++ b/examples/erc20_watcher/event_triggered/repository.go @@ -18,16 +18,16 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) -type Datastore interface { - CreateTransfer(model TransferModel, vulcanizeLogId int64) error - CreateApproval(model ApprovalModel, vulcanizeLogId int64) error +type ERC20EventDatastore interface { + CreateTransfer(model *TransferModel, vulcanizeLogId int64) error + CreateApproval(model *ApprovalModel, vulcanizeLogId int64) error } -type Repository struct { +type ERC20EventRepository struct { *postgres.DB } -func (repository Repository) CreateTransfer(transferModel TransferModel, vulcanizeLogId int64) error { +func (repository ERC20EventRepository) CreateTransfer(transferModel *TransferModel, vulcanizeLogId int64) error { _, err := repository.DB.Exec( `INSERT INTO token_transfers (vulcanize_log_id, token_name, token_address, to_address, from_address, tokens, block, tx) @@ -35,14 +35,10 @@ func (repository Repository) CreateTransfer(transferModel TransferModel, vulcani ON CONFLICT (vulcanize_log_id) DO NOTHING`, vulcanizeLogId, transferModel.TokenName, transferModel.TokenAddress, transferModel.To, transferModel.From, transferModel.Tokens, transferModel.Block, transferModel.TxHash) - if err != nil { - return err - } - - return nil + return err } -func (repository Repository) CreateApproval(approvalModel ApprovalModel, vulcanizeLogId int64) error { +func (repository ERC20EventRepository) CreateApproval(approvalModel *ApprovalModel, vulcanizeLogId int64) error { _, err := repository.DB.Exec( `INSERT INTO token_approvals (vulcanize_log_id, token_name, token_address, owner, spender, tokens, block, tx) @@ -50,9 +46,5 @@ func (repository Repository) CreateApproval(approvalModel ApprovalModel, vulcani ON CONFLICT (vulcanize_log_id) DO NOTHING`, vulcanizeLogId, approvalModel.TokenName, approvalModel.TokenAddress, approvalModel.Owner, approvalModel.Spender, approvalModel.Tokens, approvalModel.Block, approvalModel.TxHash) - if err != nil { - return err - } - - return nil + return err } diff --git a/examples/erc20_watcher/event_triggered/repository_test.go b/examples/erc20_watcher/event_triggered/repository_test.go index a1c251e6..2adb39b2 100644 --- a/examples/erc20_watcher/event_triggered/repository_test.go +++ b/examples/erc20_watcher/event_triggered/repository_test.go @@ -15,9 +15,13 @@ package event_triggered_test import ( + "math/rand" + "time" + "github.com/ethereum/go-ethereum/common" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" "github.com/vulcanize/vulcanizedb/examples/generic/helpers" "github.com/vulcanize/vulcanizedb/examples/test_helpers" @@ -25,11 +29,9 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" - "math/rand" - "time" ) -var transferEntity = event_triggered.TransferEntity{ +var transferEntity = &event_triggered.TransferEntity{ TokenName: "Dai", TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), @@ -39,7 +41,7 @@ var transferEntity = event_triggered.TransferEntity{ TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", } -var approvalEntity = event_triggered.ApprovalEntity{ +var approvalEntity = &event_triggered.ApprovalEntity{ TokenName: "Dai", TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), Src: common.HexToAddress("0x000000000000000000000000000000000000Af21"), @@ -51,7 +53,8 @@ var approvalEntity = event_triggered.ApprovalEntity{ var _ = Describe("Approval and Transfer Repository Tests", func() { var db *postgres.DB - var repository event_triggered.Repository + var converter event_triggered.ERC20Converter + var repository event_triggered.ERC20EventRepository var logRepository repositories.LogRepository var blockRepository repositories.BlockRepository var receiptRepository repositories.ReceiptRepository @@ -89,7 +92,8 @@ var _ = Describe("Approval and Transfer Repository Tests", func() { err = logRepository.Get(&vulcanizeLogId, `SELECT id FROM logs`) Expect(err).ToNot(HaveOccurred()) - repository = event_triggered.Repository{DB: db} + repository = event_triggered.ERC20EventRepository{DB: db} + converter = event_triggered.ERC20Converter{} }) @@ -97,12 +101,11 @@ var _ = Describe("Approval and Transfer Repository Tests", func() { db.Query(`DELETE FROM logs`) db.Query(`DELETE FROM log_filters`) db.Query(`DELETE FROM token_transfers`) + db.Query(`DELETE FROM token_approvals`) - repository.DB.Exec(`DELETE FROM token_transfers`) }) It("Creates a new Transfer record", func() { - converter := event_triggered.ERC20Converter{} model := converter.ToTransferModel(transferEntity) err := repository.CreateTransfer(model, vulcanizeLogId) Expect(err).ToNot(HaveOccurred()) @@ -127,7 +130,6 @@ var _ = Describe("Approval and Transfer Repository Tests", func() { }) It("does not duplicate token_transfers that have already been seen", func() { - converter := event_triggered.ERC20Converter{} model := converter.ToTransferModel(transferEntity) err := repository.CreateTransfer(model, vulcanizeLogId) @@ -144,7 +146,6 @@ var _ = Describe("Approval and Transfer Repository Tests", func() { It("Removes a Transfer record when the corresponding log is removed", func() { var exists bool - converter := event_triggered.ERC20Converter{} model := converter.ToTransferModel(transferEntity) err := repository.CreateTransfer(model, vulcanizeLogId) Expect(err).ToNot(HaveOccurred()) @@ -168,7 +169,6 @@ var _ = Describe("Approval and Transfer Repository Tests", func() { }) It("Creates a new Approval record", func() { - converter := event_triggered.ERC20Converter{} model := converter.ToApprovalModel(approvalEntity) err := repository.CreateApproval(model, vulcanizeLogId) Expect(err).ToNot(HaveOccurred()) @@ -193,7 +193,6 @@ var _ = Describe("Approval and Transfer Repository Tests", func() { }) It("does not duplicate token_approvals that have already been seen", func() { - converter := event_triggered.ERC20Converter{} model := converter.ToApprovalModel(approvalEntity) err := repository.CreateApproval(model, vulcanizeLogId) @@ -210,7 +209,6 @@ var _ = Describe("Approval and Transfer Repository Tests", func() { It("Removes a Approval record when the corresponding log is removed", func() { var exists bool - converter := event_triggered.ERC20Converter{} model := converter.ToApprovalModel(approvalEntity) err := repository.CreateApproval(model, vulcanizeLogId) Expect(err).ToNot(HaveOccurred()) diff --git a/examples/erc20_watcher/event_triggered/transformer.go b/examples/erc20_watcher/event_triggered/transformer.go index 8060c5a3..7ae95ae3 100644 --- a/examples/erc20_watcher/event_triggered/transformer.go +++ b/examples/erc20_watcher/event_triggered/transformer.go @@ -15,9 +15,9 @@ package event_triggered import ( + "fmt" "log" - "fmt" "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/generic" "github.com/vulcanize/vulcanizedb/libraries/shared" @@ -26,50 +26,56 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" ) -type DaiTransformer struct { +type ERC20EventTransformer struct { Converter ERC20ConverterInterface WatchedEventRepository datastore.WatchedEventRepository FilterRepository datastore.FilterRepository - Repository Datastore + Repository ERC20EventDatastore } -func NewTransformer(db *postgres.DB, config generic.ContractConfig) shared.Transformer { +func NewTransformer(db *postgres.DB, config generic.ContractConfig) (shared.Transformer, error) { var transformer shared.Transformer - cnvtr := NewERC20Converter(config) + + cnvtr, err := NewERC20Converter(config) + if err != nil { + return transformer, err + } + wer := repositories.WatchedEventRepository{DB: db} fr := repositories.FilterRepository{DB: db} - lkr := Repository{DB: db} - transformer = &DaiTransformer{ + lkr := ERC20EventRepository{DB: db} + transformer = ERC20EventTransformer{ Converter: cnvtr, WatchedEventRepository: wer, FilterRepository: fr, Repository: lkr, } - for _, filter := range constants.DaiFilters { + + for _, filter := range constants.DaiERC20Filters { fr.CreateFilter(filter) } - return transformer + return transformer, nil } -func (tr DaiTransformer) Execute() error { - for _, filter := range constants.DaiFilters { +func (tr ERC20EventTransformer) Execute() error { + for _, filter := range constants.DaiERC20Filters { watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name) if err != nil { log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err) return err } for _, we := range watchedEvents { - if filter.Name == "Transfer" { + if filter.Name == constants.TransferEvent.String() { entity, err := tr.Converter.ToTransferEntity(*we) - model := tr.Converter.ToTransferModel(*entity) + model := tr.Converter.ToTransferModel(entity) if err != nil { log.Printf("Error persisting data for Dai Transfers (watchedEvent.LogID %d):\n %s", we.LogID, err) } tr.Repository.CreateTransfer(model, we.LogID) } - if filter.Name == "Approval" { + if filter.Name == constants.ApprovalEvent.String() { entity, err := tr.Converter.ToApprovalEntity(*we) - model := tr.Converter.ToApprovalModel(*entity) + model := tr.Converter.ToApprovalModel(entity) if err != nil { log.Printf("Error persisting data for Dai Approvals (watchedEvent.LogID %d):\n %s", we.LogID, err) } diff --git a/examples/erc20_watcher/event_triggered/transformer_test.go b/examples/erc20_watcher/event_triggered/transformer_test.go index e49d5c4a..a02583f9 100644 --- a/examples/erc20_watcher/event_triggered/transformer_test.go +++ b/examples/erc20_watcher/event_triggered/transformer_test.go @@ -17,43 +17,13 @@ package event_triggered_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" "github.com/vulcanize/vulcanizedb/examples/mocks" "github.com/vulcanize/vulcanizedb/pkg/core" ) -type MockERC20Converter struct { - watchedEvents []*core.WatchedEvent - transfersToConvert []event_triggered.TransferEntity - approvalsToConvert []event_triggered.ApprovalEntity - block int64 -} - -func (mlkc *MockERC20Converter) ToTransferModel(entity event_triggered.TransferEntity) event_triggered.TransferModel { - mlkc.transfersToConvert = append(mlkc.transfersToConvert, entity) - return event_triggered.TransferModel{} -} - -func (mlkc *MockERC20Converter) ToTransferEntity(watchedEvent core.WatchedEvent) (*event_triggered.TransferEntity, error) { - mlkc.watchedEvents = append(mlkc.watchedEvents, &watchedEvent) - e := &event_triggered.TransferEntity{Block: watchedEvent.BlockNumber} - mlkc.block++ - return e, nil -} - -func (mlkc *MockERC20Converter) ToApprovalModel(entity event_triggered.ApprovalEntity) event_triggered.ApprovalModel { - mlkc.approvalsToConvert = append(mlkc.approvalsToConvert, entity) - return event_triggered.ApprovalModel{} -} - -func (mlkc *MockERC20Converter) ToApprovalEntity(watchedEvent core.WatchedEvent) (*event_triggered.ApprovalEntity, error) { - mlkc.watchedEvents = append(mlkc.watchedEvents, &watchedEvent) - e := &event_triggered.ApprovalEntity{Block: watchedEvent.BlockNumber} - mlkc.block++ - return e, nil -} - var blockID1 = int64(5428074) var logID1 = int64(113) var blockID2 = int64(5428405) @@ -62,12 +32,12 @@ var logID2 = int64(100) var fakeWatchedEvents = []*core.WatchedEvent{ { LogID: logID1, - Name: "Transfer", + Name: constants.TransferEvent.String(), BlockNumber: blockID1, Address: constants.DaiContractAddress, TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", Index: 110, - Topic0: constants.TransferEventSignature, + Topic0: constants.TransferEvent.Signature(), Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", Topic3: "", @@ -75,12 +45,12 @@ var fakeWatchedEvents = []*core.WatchedEvent{ }, { LogID: logID2, - Name: "Approval", + Name: constants.ApprovalEvent.String(), BlockNumber: blockID2, Address: constants.DaiContractAddress, TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", Index: 110, - Topic0: constants.ApprovalEventSignature, + Topic0: constants.ApprovalEvent.Signature(), Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", Topic3: "", @@ -89,19 +59,20 @@ var fakeWatchedEvents = []*core.WatchedEvent{ } var _ = Describe("Mock ERC20 transformer", func() { - var mockERC20Converter MockERC20Converter + var mockERC20Converter mocks.MockERC20Converter var watchedEventsRepo mocks.MockWatchedEventsRepository var mockEventRepo mocks.MockEventRepo var filterRepo mocks.MockFilterRepository - var transformer event_triggered.DaiTransformer + var transformer event_triggered.ERC20EventTransformer BeforeEach(func() { - mockERC20Converter = MockERC20Converter{} + mockERC20Converter = mocks.MockERC20Converter{} watchedEventsRepo = mocks.MockWatchedEventsRepository{} watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents) mockEventRepo = mocks.MockEventRepo{} filterRepo = mocks.MockFilterRepository{} - transformer = event_triggered.DaiTransformer{ + + transformer = event_triggered.ERC20EventTransformer{ Converter: &mockERC20Converter, WatchedEventRepository: &watchedEventsRepo, FilterRepository: filterRepo, @@ -112,22 +83,22 @@ var _ = Describe("Mock ERC20 transformer", func() { It("calls the watched events repo with correct filter", func() { transformer.Execute() Expect(len(watchedEventsRepo.Names)).To(Equal(2)) - Expect(watchedEventsRepo.Names).To(ConsistOf([]string{"Transfer", "Approval"})) + Expect(watchedEventsRepo.Names).To(ConsistOf([]string{constants.TransferEvent.String(), constants.ApprovalEvent.String()})) }) It("calls the mock ERC20 converter with the watched events", func() { transformer.Execute() - Expect(len(mockERC20Converter.watchedEvents)).To(Equal(2)) - Expect(mockERC20Converter.watchedEvents).To(ConsistOf(fakeWatchedEvents)) + Expect(len(mockERC20Converter.WatchedEvents)).To(Equal(2)) + Expect(mockERC20Converter.WatchedEvents).To(ConsistOf(fakeWatchedEvents)) }) - It("converts a Transfer entity to a model", func() { + It("converts a Transfer and Approval entity to their models", func() { transformer.Execute() - Expect(len(mockERC20Converter.transfersToConvert)).To(Equal(1)) - Expect(mockERC20Converter.transfersToConvert[0].Block).To(Equal(blockID1)) + Expect(len(mockERC20Converter.TransfersToConvert)).To(Equal(1)) + Expect(mockERC20Converter.TransfersToConvert[0].Block).To(Equal(blockID1)) - Expect(len(mockERC20Converter.approvalsToConvert)).To(Equal(1)) - Expect(mockERC20Converter.approvalsToConvert[0].Block).To(Equal(blockID2)) + Expect(len(mockERC20Converter.ApprovalsToConvert)).To(Equal(1)) + Expect(mockERC20Converter.ApprovalsToConvert[0].Block).To(Equal(blockID2)) }) It("persists Transfer and Approval data for each watched Transfer or Approval event", func() { diff --git a/examples/erc20_watcher/every_block/every_block_suite_test.go b/examples/erc20_watcher/every_block/every_block_suite_test.go index e25398b1..dd5aa214 100644 --- a/examples/erc20_watcher/every_block/every_block_suite_test.go +++ b/examples/erc20_watcher/every_block/every_block_suite_test.go @@ -15,12 +15,12 @@ package every_block_test import ( + "io/ioutil" + "log" "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "io/ioutil" - "log" ) func TestEveryBlock(t *testing.T) { diff --git a/examples/erc20_watcher/every_block/getter.go b/examples/erc20_watcher/every_block/getter.go index 52c02d9d..4574440b 100644 --- a/examples/erc20_watcher/every_block/getter.go +++ b/examples/erc20_watcher/every_block/getter.go @@ -32,13 +32,13 @@ type ERC20GetterInterface interface { } // Getter struct -type Getter struct { +type ERC20Getter struct { fetcher generic.Fetcher } // Initializes and returns a Getter with the given blockchain -func NewGetter(blockChain core.BlockChain) Getter { - return Getter{ +func NewGetter(blockChain core.BlockChain) ERC20Getter { + return ERC20Getter{ fetcher: generic.Fetcher{ BlockChain: blockChain, }, @@ -46,19 +46,19 @@ func NewGetter(blockChain core.BlockChain) Getter { } // Public getter methods for calling contract methods -func (g Getter) GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { +func (g ERC20Getter) GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { return g.fetcher.FetchBigInt("totalSupply", contractAbi, contractAddress, blockNumber, nil) } -func (g Getter) GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { +func (g ERC20Getter) GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { return g.fetcher.FetchBigInt("balanceOf", contractAbi, contractAddress, blockNumber, methodArgs) } -func (g Getter) GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { +func (g ERC20Getter) GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { return g.fetcher.FetchBigInt("allowance", contractAbi, contractAddress, blockNumber, methodArgs) } // Method to retrieve the Getter's blockchain -func (g Getter) GetBlockChain() core.BlockChain { +func (g ERC20Getter) GetBlockChain() core.BlockChain { return g.fetcher.BlockChain } diff --git a/examples/erc20_watcher/every_block/getter_test.go b/examples/erc20_watcher/every_block/getter_test.go index c41726b0..de8edd6a 100644 --- a/examples/erc20_watcher/every_block/getter_test.go +++ b/examples/erc20_watcher/every_block/getter_test.go @@ -17,12 +17,12 @@ package every_block_test import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/ethereum/go-ethereum/common" "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" "github.com/vulcanize/vulcanizedb/pkg/fakes" diff --git a/examples/erc20_watcher/every_block/integration_test.go b/examples/erc20_watcher/every_block/integration_test.go index a91ddb85..862be926 100644 --- a/examples/erc20_watcher/every_block/integration_test.go +++ b/examples/erc20_watcher/every_block/integration_test.go @@ -15,8 +15,12 @@ package every_block_test import ( + "math/big" + "strconv" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" "github.com/vulcanize/vulcanizedb/examples/generic" @@ -25,8 +29,6 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" "github.com/vulcanize/vulcanizedb/pkg/fakes" - "math/big" - "strconv" ) func setLastBlockOnChain(blockChain *fakes.MockBlockChain, blockNumber int64) { diff --git a/examples/erc20_watcher/every_block/repository.go b/examples/erc20_watcher/every_block/repository.go index 15fa7325..317186c4 100644 --- a/examples/erc20_watcher/every_block/repository.go +++ b/examples/erc20_watcher/every_block/repository.go @@ -16,12 +16,13 @@ package every_block import ( "fmt" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "log" + + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) // Interface definition for a generic ERC20 token repository -type ERC20RepositoryInterface interface { +type ERC20TokenDatastore interface { CreateSupply(supply TokenSupply) error CreateBalance(balance TokenBalance) error CreateAllowance(allowance TokenAllowance) error diff --git a/examples/erc20_watcher/every_block/repository_test.go b/examples/erc20_watcher/every_block/repository_test.go index 5b6176ad..3bba610b 100644 --- a/examples/erc20_watcher/every_block/repository_test.go +++ b/examples/erc20_watcher/every_block/repository_test.go @@ -15,6 +15,8 @@ package every_block_test import ( + "math/rand" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -24,7 +26,6 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" "github.com/vulcanize/vulcanizedb/test_config" - "math/rand" ) var _ = Describe("ERC20 Token Supply Repository", func() { diff --git a/examples/erc20_watcher/every_block/transformer.go b/examples/erc20_watcher/every_block/transformer.go index 72db2adc..c1aa3ed2 100644 --- a/examples/erc20_watcher/every_block/transformer.go +++ b/examples/erc20_watcher/every_block/transformer.go @@ -16,23 +16,25 @@ package every_block import ( "fmt" + "log" + "math/big" + "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/examples/generic" "github.com/vulcanize/vulcanizedb/libraries/shared" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" - "log" - "math/big" ) -type Transformer struct { +type ERC20Transformer struct { Getter ERC20GetterInterface - Repository ERC20RepositoryInterface - Retriever generic.Retriever + Repository ERC20TokenDatastore + Retriever generic.TokenHolderRetriever Config generic.ContractConfig } -func (t *Transformer) SetConfiguration(config generic.ContractConfig) { +func (t *ERC20Transformer) SetConfiguration(config generic.ContractConfig) { t.Config = config } @@ -43,8 +45,8 @@ type ERC20TokenTransformerInitializer struct { func (i ERC20TokenTransformerInitializer) NewERC20TokenTransformer(db *postgres.DB, blockchain core.BlockChain) shared.Transformer { getter := NewGetter(blockchain) repository := ERC20TokenRepository{DB: db} - retriever := generic.NewRetriever(db, i.Config.Address) - transformer := Transformer{ + retriever := generic.NewTokenHolderRetriever(db, i.Config.Address) + transformer := ERC20Transformer{ Getter: &getter, Repository: &repository, Retriever: retriever, @@ -81,7 +83,7 @@ func newTransformerError(err error, blockNumber int64, msg string) error { return &e } -func (t Transformer) Execute() error { +func (t ERC20Transformer) Execute() error { var upperBoundBlock int64 blockchain := t.Getter.GetBlockChain() lastBlock := blockchain.LastBlock().Int64() diff --git a/examples/erc20_watcher/every_block/transformer_test.go b/examples/erc20_watcher/every_block/transformer_test.go index 224739e7..d3590607 100644 --- a/examples/erc20_watcher/every_block/transformer_test.go +++ b/examples/erc20_watcher/every_block/transformer_test.go @@ -15,17 +15,19 @@ package every_block_test import ( + "math/big" + "math/rand" + "strconv" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block" "github.com/vulcanize/vulcanizedb/examples/generic" "github.com/vulcanize/vulcanizedb/examples/mocks" "github.com/vulcanize/vulcanizedb/examples/test_helpers" "github.com/vulcanize/vulcanizedb/pkg/fakes" - "math/big" - "math/rand" - "strconv" ) var testContractConfig = generic.ContractConfig{ @@ -41,7 +43,7 @@ var config = testContractConfig var _ = Describe("Everyblock transformer", func() { var getter mocks.Getter var repository mocks.ERC20TokenRepository - var transformer every_block.Transformer + var transformer every_block.ERC20Transformer var blockChain *fakes.MockBlockChain var initialSupply = "27647235749155415536952630" var initialSupplyPlusOne = "27647235749155415536952631" @@ -57,10 +59,10 @@ var _ = Describe("Everyblock transformer", func() { repository = mocks.ERC20TokenRepository{} repository.SetMissingSupplyBlocks([]int64{config.FirstBlock}) db := test_helpers.CreateNewDatabase() - rt := generic.NewRetriever(db, config.Address) + rt := generic.NewTokenHolderRetriever(db, config.Address) //setting the mock repository to return the first block as the missing blocks - transformer = every_block.Transformer{ + transformer = every_block.ERC20Transformer{ Getter: &getter, Repository: &repository, Retriever: rt, @@ -150,7 +152,7 @@ var _ = Describe("Everyblock transformer", func() { It("returns an error if the call to get missing blocks fails", func() { failureRepository := mocks.FailureRepository{} failureRepository.SetMissingSupplyBlocksFail(true) - transformer = every_block.Transformer{ + transformer = every_block.ERC20Transformer{ Getter: &getter, Repository: &failureRepository, } @@ -165,7 +167,7 @@ var _ = Describe("Everyblock transformer", func() { failureBlockchain.SetLastBlock(&defaultLastBlock) failureBlockchain.SetFetchContractDataErr(fakes.FakeError) getter := every_block.NewGetter(failureBlockchain) - transformer = every_block.Transformer{ + transformer = every_block.ERC20Transformer{ Getter: &getter, Repository: &repository, } @@ -180,7 +182,7 @@ var _ = Describe("Everyblock transformer", func() { failureRepository.SetMissingSupplyBlocks([]int64{config.FirstBlock}) failureRepository.SetCreateSupplyFail(true) - transformer = every_block.Transformer{ + transformer = every_block.ERC20Transformer{ Getter: &getter, Repository: &failureRepository, } diff --git a/examples/generic/config.go b/examples/generic/config.go index 26755bcf..f5d96e32 100644 --- a/examples/generic/config.go +++ b/examples/generic/config.go @@ -21,6 +21,7 @@ import ( type ContractConfig struct { Address string + Owner string Abi string ParsedAbi abi.ABI FirstBlock int64 @@ -30,9 +31,18 @@ type ContractConfig struct { var DaiConfig = ContractConfig{ Address: constants.DaiContractAddress, + Owner: constants.DaiContractOwner, Abi: constants.DaiAbiString, - ParsedAbi: constants.ParsedDaiAbi, FirstBlock: int64(4752008), LastBlock: -1, Name: "Dai", } + +var TusdConfig = ContractConfig{ + Address: constants.TusdContractAddress, + Owner: constants.TusdContractOwner, + Abi: constants.TusdAbiString, + FirstBlock: int64(5197514), + LastBlock: -1, + Name: "Tusd", +} diff --git a/examples/generic/event_triggered/converter.go b/examples/generic/event_triggered/converter.go new file mode 100644 index 00000000..0a80a1a1 --- /dev/null +++ b/examples/generic/event_triggered/converter.go @@ -0,0 +1,117 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/examples/constants" + "github.com/vulcanize/vulcanizedb/examples/generic" + "github.com/vulcanize/vulcanizedb/examples/generic/helpers" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/geth" +) + +// Converter converts a raw event log into its corresponding entity +// and can subsequently convert the entity into a model + +type GenericConverterInterface interface { + ToBurnEntity(watchedEvent core.WatchedEvent) (*BurnEntity, error) + ToBurnModel(entity *BurnEntity) *BurnModel + ToMintEntity(watchedEvent core.WatchedEvent) (*MintEntity, error) + ToMintModel(entity *MintEntity) *MintModel +} + +type GenericConverter struct { + config generic.ContractConfig +} + +func NewGenericConverter(config generic.ContractConfig) (*GenericConverter, error) { + var err error + + config.ParsedAbi, err = geth.ParseAbi(config.Abi) + if err != nil { + return nil, err + } + + converter := &GenericConverter{ + config: config, + } + + return converter, nil +} + +func (c GenericConverter) ToBurnEntity(watchedEvent core.WatchedEvent) (*BurnEntity, error) { + result := &BurnEntity{} + contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) + event := helpers.ConvertToLog(watchedEvent) + err := contract.UnpackLog(result, constants.BurnEvent.String(), event) + if err != nil { + return result, err + } + result.TokenName = c.config.Name + result.TokenAddress = common.HexToAddress(c.config.Address) + result.Block = watchedEvent.BlockNumber + result.TxHash = watchedEvent.TxHash + + return result, nil +} + +func (c GenericConverter) ToBurnModel(entity *BurnEntity) *BurnModel { + burner := entity.Burner.String() + tokens := entity.Value.String() + + return &BurnModel{ + TokenName: c.config.Name, + TokenAddress: c.config.Address, + Burner: burner, + Tokens: tokens, + Block: entity.Block, + TxHash: entity.TxHash, + } +} + +func (c GenericConverter) ToMintEntity(watchedEvent core.WatchedEvent) (*MintEntity, error) { + result := &MintEntity{} + contract := bind.NewBoundContract(common.HexToAddress(c.config.Address), c.config.ParsedAbi, nil, nil, nil) + event := helpers.ConvertToLog(watchedEvent) + err := contract.UnpackLog(result, constants.MintEvent.String(), event) + if err != nil { + return result, err + } + result.TokenName = c.config.Name + result.TokenAddress = common.HexToAddress(c.config.Address) + result.Block = watchedEvent.BlockNumber + result.TxHash = watchedEvent.TxHash + + return result, nil +} + +func (c GenericConverter) ToMintModel(entity *MintEntity) *MintModel { + mintee := entity.To.String() + minter := c.config.Owner + tokens := entity.Amount.String() + + return &MintModel{ + TokenName: c.config.Name, + TokenAddress: c.config.Address, + Mintee: mintee, + Minter: minter, + Tokens: tokens, + Block: entity.Block, + TxHash: entity.TxHash, + } +} diff --git a/examples/generic/event_triggered/converter_test.go b/examples/generic/event_triggered/converter_test.go new file mode 100644 index 00000000..bd6cd41d --- /dev/null +++ b/examples/generic/event_triggered/converter_test.go @@ -0,0 +1,148 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered_test + +import ( + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/examples/constants" + "github.com/vulcanize/vulcanizedb/examples/generic" + "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" + "github.com/vulcanize/vulcanizedb/examples/generic/helpers" + "github.com/vulcanize/vulcanizedb/pkg/core" +) + +var expectedBurnModel = event_triggered.BurnModel{ + TokenName: "Tusd", + TokenAddress: constants.TusdContractAddress, + Burner: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", + Tokens: "1097077688018008265106216665536940668749033598146", + Block: 5488076, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", +} + +var expectedBurnEntity = event_triggered.BurnEntity{ + TokenName: "Tusd", + TokenAddress: common.HexToAddress(constants.TusdContractAddress), + Burner: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), + Value: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), + Block: 5488076, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", +} + +var expectedMintModel = event_triggered.MintModel{ + TokenName: "Tusd", + TokenAddress: constants.TusdContractAddress, + Minter: constants.TusdContractOwner, + Mintee: "0x09BbBBE21a5975cAc061D82f7b843bCE061BA391", + Tokens: "1097077688018008265106216665536940668749033598146", + Block: 5488076, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", +} + +var expectedMintEntity = event_triggered.MintEntity{ + TokenName: "Tusd", + TokenAddress: common.HexToAddress(constants.TusdContractAddress), + To: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), + Amount: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), + Block: 5488076, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", +} + +var burnEvent = core.WatchedEvent{ + LogID: 1, + Name: constants.BurnEvent.String(), + BlockNumber: 5488076, + Address: constants.TusdContractAddress, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Index: 110, + Topic0: constants.BurnEvent.Signature(), + Topic1: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", + Topic2: "", + Topic3: "", + Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", +} + +var mintEvent = core.WatchedEvent{ + LogID: 1, + Name: constants.MintEvent.String(), + BlockNumber: 5488076, + Address: constants.TusdContractAddress, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Index: 110, + Topic0: constants.MintEvent.Signature(), + Topic1: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", + Topic2: "", + Topic3: "", + Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", +} + +var _ = Describe("Transfer Converter", func() { + + var converter *event_triggered.GenericConverter + var err error + + BeforeEach(func() { + converter, err = event_triggered.NewGenericConverter(generic.TusdConfig) + Expect(err).NotTo(HaveOccurred()) + }) + + It("converts a watched burn event into a BurnEntity", func() { + + result, err := converter.ToBurnEntity(burnEvent) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(&expectedBurnEntity)) + }) + + It("converts a BurnEntity to a BurnModel", func() { + + result, err := converter.ToBurnEntity(burnEvent) + Expect(err).NotTo(HaveOccurred()) + + model := converter.ToBurnModel(result) + Expect(model).To(Equal(&expectedBurnModel)) + }) + +}) + +var _ = Describe("Approval Converter", func() { + + var converter *event_triggered.GenericConverter + var err error + + BeforeEach(func() { + converter, err = event_triggered.NewGenericConverter(generic.TusdConfig) + Expect(err).NotTo(HaveOccurred()) + }) + + It("converts a watched mint event into a MintEntity", func() { + + result, err := converter.ToMintEntity(mintEvent) + Expect(err).NotTo(HaveOccurred()) + Expect(result).To(Equal(&expectedMintEntity)) + }) + + It("converts a MintEntity to a MintModel", func() { + + result, err := converter.ToMintEntity(mintEvent) + Expect(err).NotTo(HaveOccurred()) + + model := converter.ToMintModel(result) + Expect(model).To(Equal(&expectedMintModel)) + }) + +}) diff --git a/examples/generic/event_triggered/entity.go b/examples/generic/event_triggered/entity.go new file mode 100644 index 00000000..9bfbe814 --- /dev/null +++ b/examples/generic/event_triggered/entity.go @@ -0,0 +1,39 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + +type BurnEntity struct { + TokenName string + TokenAddress common.Address + Burner common.Address + Value *big.Int + Block int64 + TxHash string +} + +type MintEntity struct { + TokenName string + TokenAddress common.Address + To common.Address + Amount *big.Int + Block int64 + TxHash string +} diff --git a/examples/generic/event_triggered/event_triggered_suite_test.go b/examples/generic/event_triggered/event_triggered_suite_test.go new file mode 100644 index 00000000..f75089a9 --- /dev/null +++ b/examples/generic/event_triggered/event_triggered_suite_test.go @@ -0,0 +1,27 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestLogKill(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "ERC20 Event Triggered test Suite") +} diff --git a/examples/generic/event_triggered/integration_test.go b/examples/generic/event_triggered/integration_test.go new file mode 100644 index 00000000..5948c3b3 --- /dev/null +++ b/examples/generic/event_triggered/integration_test.go @@ -0,0 +1,133 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/examples/constants" + "github.com/vulcanize/vulcanizedb/examples/generic" + "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" + "github.com/vulcanize/vulcanizedb/examples/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +var burnLog = core.Log{ + BlockNumber: 5488076, + Address: constants.TusdContractAddress, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Index: 110, + Topics: [4]string{ + constants.BurnEvent.Signature(), + "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", + "", + "", + }, + Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", +} + +var mintLog = core.Log{ + BlockNumber: 5488076, + Address: constants.TusdContractAddress, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Index: 110, + Topics: [4]string{ + constants.MintEvent.Signature(), + "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", + "", + "", + }, + Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", +} + +//converted transfer to assert against +var logs = []core.Log{ + burnLog, + mintLog, + { + BlockNumber: 0, + TxHash: "", + Address: "", + Topics: core.Topics{}, + Index: 0, + Data: "", + }, +} + +var _ = Describe("Integration test with vulcanizedb", func() { + var db *postgres.DB + + BeforeEach(func() { + db = test_helpers.SetupIntegrationDB(db, logs) + }) + + AfterEach(func() { + db = test_helpers.TearDownIntegrationDB(db) + }) + + It("creates token_burns entry for each Burn event received", func() { + transformer, err := event_triggered.NewTransformer(db, generic.TusdConfig) + Expect(err).ToNot(HaveOccurred()) + + transformer.Execute() + + var count int + err = db.QueryRow(`SELECT COUNT(*) FROM token_burns`).Scan(&count) + Expect(err).ToNot(HaveOccurred()) + Expect(count).To(Equal(1)) + + burn := event_triggered.BurnModel{} + + err = db.Get(&burn, `SELECT + token_name, + token_address, + burner, + tokens, + block, + tx + FROM token_burns WHERE block=$1`, logs[0].BlockNumber) + Expect(err).ToNot(HaveOccurred()) + Expect(burn).To(Equal(expectedBurnModel)) + }) + + It("creates token_mints entry for each Mint event received", func() { + transformer, err := event_triggered.NewTransformer(db, generic.TusdConfig) + Expect(err).ToNot(HaveOccurred()) + + transformer.Execute() + + var count int + err = db.QueryRow(`SELECT COUNT(*) FROM token_mints`).Scan(&count) + Expect(err).ToNot(HaveOccurred()) + Expect(count).To(Equal(1)) + + mint := event_triggered.MintModel{} + + err = db.Get(&mint, `SELECT + token_name, + token_address, + minter, + mintee, + tokens, + block, + tx + FROM token_mints WHERE block=$1`, logs[0].BlockNumber) + Expect(err).ToNot(HaveOccurred()) + Expect(mint).To(Equal(expectedMintModel)) + }) + +}) diff --git a/examples/generic/event_triggered/model.go b/examples/generic/event_triggered/model.go new file mode 100644 index 00000000..680ac2ab --- /dev/null +++ b/examples/generic/event_triggered/model.go @@ -0,0 +1,34 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered + +type BurnModel struct { + TokenName string `db:"token_name"` + TokenAddress string `db:"token_address"` + Burner string `db:"burner"` + Tokens string `db:"tokens"` + Block int64 `db:"block"` + TxHash string `db:"tx"` +} + +type MintModel struct { + TokenName string `db:"token_name"` + TokenAddress string `db:"token_address"` + Mintee string `db:"mintee"` + Minter string `db:"minter"` + Tokens string `db:"tokens"` + Block int64 `db:"block"` + TxHash string `db:"tx"` +} diff --git a/examples/generic/event_triggered/repository.go b/examples/generic/event_triggered/repository.go new file mode 100644 index 00000000..922589a6 --- /dev/null +++ b/examples/generic/event_triggered/repository.go @@ -0,0 +1,50 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered + +import ( + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type GenericEventDatastore interface { + CreateBurn(model *BurnModel, vulcanizeLogId int64) error + CreateMint(model *MintModel, vulcanizeLogId int64) error +} + +type GenericEventRepository struct { + *postgres.DB +} + +func (repository GenericEventRepository) CreateBurn(burnModel *BurnModel, vulcanizeLogId int64) error { + _, err := repository.DB.Exec( + + `INSERT INTO token_burns (vulcanize_log_id, token_name, token_address, burner, tokens, block, tx) + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT (vulcanize_log_id) DO NOTHING`, + vulcanizeLogId, burnModel.TokenName, burnModel.TokenAddress, burnModel.Burner, burnModel.Tokens, burnModel.Block, burnModel.TxHash) + + return err +} + +func (repository GenericEventRepository) CreateMint(mintModel *MintModel, vulcanizeLogId int64) error { + _, err := repository.DB.Exec( + + `INSERT INTO token_mints (vulcanize_log_id, token_name, token_address, minter, mintee, tokens, block, tx) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + ON CONFLICT (vulcanize_log_id) DO NOTHING`, + vulcanizeLogId, mintModel.TokenName, mintModel.TokenAddress, mintModel.Minter, mintModel.Mintee, mintModel.Tokens, mintModel.Block, mintModel.TxHash) + + return err +} diff --git a/examples/generic/event_triggered/repository_test.go b/examples/generic/event_triggered/repository_test.go new file mode 100644 index 00000000..6b358e2e --- /dev/null +++ b/examples/generic/event_triggered/repository_test.go @@ -0,0 +1,229 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered_test + +import ( + "math/rand" + "time" + + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" + "github.com/vulcanize/vulcanizedb/examples/generic/helpers" + "github.com/vulcanize/vulcanizedb/examples/test_helpers" + "github.com/vulcanize/vulcanizedb/pkg/config" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" +) + +var burnEntity = &event_triggered.BurnEntity{ + TokenName: "Tusd", + TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), + Burner: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), + Value: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), + Block: 5488076, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", +} + +var mintEntity = &event_triggered.MintEntity{ + TokenName: "Tusd", + TokenAddress: common.HexToAddress("0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359"), + To: common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"), + Amount: helpers.BigFromString("1097077688018008265106216665536940668749033598146"), + Block: 5488076, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", +} + +var _ = Describe("Approval and Transfer Repository Tests", func() { + var db *postgres.DB + var converter event_triggered.GenericConverter + var repository event_triggered.GenericEventRepository + var logRepository repositories.LogRepository + var blockRepository repositories.BlockRepository + var receiptRepository repositories.ReceiptRepository + var blockNumber int64 + var blockId int64 + var vulcanizeLogId int64 + rand.Seed(time.Now().UnixNano()) + + BeforeEach(func() { + var err error + db, err = postgres.NewDB(config.Database{ + Hostname: "localhost", + Name: "vulcanize_private", + Port: 5432, + }, core.Node{}) + Expect(err).NotTo(HaveOccurred()) + + receiptRepository = repositories.ReceiptRepository{DB: db} + logRepository = repositories.LogRepository{DB: db} + blockRepository = *repositories.NewBlockRepository(db) + + blockNumber = rand.Int63() + blockId = test_helpers.CreateBlock(blockNumber, blockRepository) + + log := core.Log{} + logs := []core.Log{log} + receipt := core.Receipt{ + Logs: logs, + } + receipts := []core.Receipt{receipt} + + err = receiptRepository.CreateReceiptsAndLogs(blockId, receipts) + Expect(err).ToNot(HaveOccurred()) + + err = logRepository.Get(&vulcanizeLogId, `SELECT id FROM logs`) + Expect(err).ToNot(HaveOccurred()) + + repository = event_triggered.GenericEventRepository{DB: db} + converter = event_triggered.GenericConverter{} + }) + + AfterEach(func() { + db.Query(`DELETE FROM logs`) + db.Query(`DELETE FROM log_filters`) + db.Query(`DELETE FROM token_burns`) + db.Query(`DELETE FROM token_mints`) + + }) + + It("Creates a new Burn record", func() { + model := converter.ToBurnModel(burnEntity) + err := repository.CreateBurn(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + type DBRow struct { + DBID uint64 `db:"id"` + VulcanizeLogID int64 `db:"vulcanize_log_id"` + event_triggered.BurnModel + } + dbResult := DBRow{} + + err = repository.QueryRowx(`SELECT * FROM token_burns`).StructScan(&dbResult) + Expect(err).ToNot(HaveOccurred()) + + Expect(dbResult.VulcanizeLogID).To(Equal(vulcanizeLogId)) + Expect(dbResult.TokenName).To(Equal(model.TokenName)) + Expect(dbResult.TokenAddress).To(Equal(model.TokenAddress)) + Expect(dbResult.Burner).To(Equal(model.Burner)) + Expect(dbResult.Tokens).To(Equal(model.Tokens)) + Expect(dbResult.Block).To(Equal(model.Block)) + Expect(dbResult.TxHash).To(Equal(model.TxHash)) + }) + + It("does not duplicate token_transfers that have already been seen", func() { + model := converter.ToBurnModel(burnEntity) + + err := repository.CreateBurn(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + err = repository.CreateBurn(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + + var count int + err = repository.DB.QueryRowx(`SELECT count(*) FROM token_burns`).Scan(&count) + Expect(err).ToNot(HaveOccurred()) + Expect(count).To(Equal(1)) + }) + + It("Removes a Burn record when the corresponding log is removed", func() { + var exists bool + + model := converter.ToBurnModel(burnEntity) + err := repository.CreateBurn(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + + err = repository.DB.QueryRow(`SELECT exists (SELECT * FROM token_burns WHERE vulcanize_log_id = $1)`, vulcanizeLogId).Scan(&exists) + Expect(err).ToNot(HaveOccurred()) + Expect(exists).To(BeTrue()) + + var logCount int + _, err = logRepository.DB.Exec(`DELETE FROM logs WHERE id = $1`, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + err = logRepository.Get(&logCount, `SELECT count(*) FROM logs WHERE id = $1`, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + Expect(logCount).To(BeZero()) + + var LogKillCount int + err = repository.DB.QueryRowx( + `SELECT count(*) FROM token_burns WHERE vulcanize_log_id = $1`, vulcanizeLogId).Scan(&LogKillCount) + Expect(err).ToNot(HaveOccurred()) + Expect(LogKillCount).To(BeZero()) + }) + + It("Creates a new Mint record", func() { + model := converter.ToMintModel(mintEntity) + err := repository.CreateMint(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + type DBRow struct { + DBID uint64 `db:"id"` + VulcanizeLogID int64 `db:"vulcanize_log_id"` + event_triggered.MintModel + } + dbResult := DBRow{} + + err = repository.QueryRowx(`SELECT * FROM token_mints`).StructScan(&dbResult) + Expect(err).ToNot(HaveOccurred()) + + Expect(dbResult.VulcanizeLogID).To(Equal(vulcanizeLogId)) + Expect(dbResult.TokenName).To(Equal(model.TokenName)) + Expect(dbResult.TokenAddress).To(Equal(model.TokenAddress)) + Expect(dbResult.Mintee).To(Equal(model.Mintee)) + Expect(dbResult.Minter).To(Equal(model.Minter)) + Expect(dbResult.Tokens).To(Equal(model.Tokens)) + Expect(dbResult.Block).To(Equal(model.Block)) + Expect(dbResult.TxHash).To(Equal(model.TxHash)) + }) + + It("does not duplicate token_mints that have already been seen", func() { + model := converter.ToMintModel(mintEntity) + + err := repository.CreateMint(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + err = repository.CreateMint(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + + var count int + err = repository.DB.QueryRowx(`SELECT count(*) FROM token_mints`).Scan(&count) + Expect(err).ToNot(HaveOccurred()) + Expect(count).To(Equal(1)) + }) + + It("Removes a Mint record when the corresponding log is removed", func() { + var exists bool + + model := converter.ToMintModel(mintEntity) + err := repository.CreateMint(model, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + + err = repository.DB.QueryRow(`SELECT exists (SELECT * FROM token_mints WHERE vulcanize_log_id = $1)`, vulcanizeLogId).Scan(&exists) + Expect(err).ToNot(HaveOccurred()) + Expect(exists).To(BeTrue()) + + var logCount int + _, err = logRepository.DB.Exec(`DELETE FROM logs WHERE id = $1`, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + err = logRepository.Get(&logCount, `SELECT count(*) FROM logs WHERE id = $1`, vulcanizeLogId) + Expect(err).ToNot(HaveOccurred()) + Expect(logCount).To(BeZero()) + + var LogKillCount int + err = repository.DB.QueryRowx( + `SELECT count(*) FROM token_mints WHERE vulcanize_log_id = $1`, vulcanizeLogId).Scan(&LogKillCount) + Expect(err).ToNot(HaveOccurred()) + Expect(LogKillCount).To(BeZero()) + }) +}) diff --git a/examples/generic/event_triggered/transformer.go b/examples/generic/event_triggered/transformer.go new file mode 100644 index 00000000..f6b74bf7 --- /dev/null +++ b/examples/generic/event_triggered/transformer.go @@ -0,0 +1,87 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered + +import ( + "fmt" + "log" + + "github.com/vulcanize/vulcanizedb/examples/constants" + "github.com/vulcanize/vulcanizedb/examples/generic" + "github.com/vulcanize/vulcanizedb/libraries/shared" + "github.com/vulcanize/vulcanizedb/pkg/datastore" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" +) + +type GenericTransformer struct { + Converter GenericConverterInterface + WatchedEventRepository datastore.WatchedEventRepository + FilterRepository datastore.FilterRepository + Repository GenericEventDatastore +} + +func NewTransformer(db *postgres.DB, config generic.ContractConfig) (shared.Transformer, error) { + var transformer shared.Transformer + + cnvtr, err := NewGenericConverter(config) + if err != nil { + return transformer, err + } + + wer := repositories.WatchedEventRepository{DB: db} + fr := repositories.FilterRepository{DB: db} + lkr := GenericEventRepository{DB: db} + transformer = GenericTransformer{ + Converter: cnvtr, + WatchedEventRepository: wer, + FilterRepository: fr, + Repository: lkr, + } + + for _, filter := range constants.TusdGenericFilters { + fr.CreateFilter(filter) + } + return transformer, nil +} + +func (tr GenericTransformer) Execute() error { + for _, filter := range constants.TusdGenericFilters { + watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name) + if err != nil { + log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err) + return err + } + for _, we := range watchedEvents { + if filter.Name == constants.BurnEvent.String() { + entity, err := tr.Converter.ToBurnEntity(*we) + model := tr.Converter.ToBurnModel(entity) + if err != nil { + log.Printf("Error persisting data for Dai Burns (watchedEvent.LogID %d):\n %s", we.LogID, err) + } + tr.Repository.CreateBurn(model, we.LogID) + } + if filter.Name == constants.MintEvent.String() { + entity, err := tr.Converter.ToMintEntity(*we) + model := tr.Converter.ToMintModel(entity) + if err != nil { + log.Printf("Error persisting data for Dai Mints (watchedEvent.LogID %d):\n %s", we.LogID, err) + } + tr.Repository.CreateMint(model, we.LogID) + } + } + } + return nil +} diff --git a/examples/generic/event_triggered/transformer_test.go b/examples/generic/event_triggered/transformer_test.go new file mode 100644 index 00000000..cbe2288c --- /dev/null +++ b/examples/generic/event_triggered/transformer_test.go @@ -0,0 +1,111 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package event_triggered_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/examples/constants" + "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" + "github.com/vulcanize/vulcanizedb/examples/mocks" + "github.com/vulcanize/vulcanizedb/pkg/core" +) + +var blockID1 = int64(5428074) +var logID1 = int64(113) +var blockID2 = int64(5428405) +var logID2 = int64(100) + +var fakeWatchedEvents = []*core.WatchedEvent{ + { + LogID: logID1, + Name: constants.BurnEvent.String(), + BlockNumber: blockID1, + Address: constants.TusdContractAddress, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Index: 110, + Topic0: constants.BurnEvent.Signature(), + Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", + Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", + Topic3: "", + Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", + }, + { + LogID: logID2, + Name: constants.MintEvent.String(), + BlockNumber: blockID2, + Address: constants.TusdContractAddress, + TxHash: "0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad6546ae", + Index: 110, + Topic0: constants.MintEvent.Signature(), + Topic1: "0x000000000000000000000000000000000000000000000000000000000000af21", + Topic2: "0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391", + Topic3: "", + Data: "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000000000000000000000000000392d2e2bda9c00000000000000000000000000000000000000000000000000927f41fa0a4a418000000000000000000000000000000000000000000000000000000000005adcfebe", + }, +} + +var _ = Describe("Mock ERC20 transformer", func() { + var mockERC20Converter mocks.MockERC20Converter + var watchedEventsRepo mocks.MockWatchedEventsRepository + var mockEventRepo mocks.MockEventRepo + var filterRepo mocks.MockFilterRepository + var transformer event_triggered.GenericTransformer + + BeforeEach(func() { + mockERC20Converter = mocks.MockERC20Converter{} + watchedEventsRepo = mocks.MockWatchedEventsRepository{} + watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents) + mockEventRepo = mocks.MockEventRepo{} + filterRepo = mocks.MockFilterRepository{} + + transformer = event_triggered.GenericTransformer{ + Converter: &mockERC20Converter, + WatchedEventRepository: &watchedEventsRepo, + FilterRepository: filterRepo, + Repository: &mockEventRepo, + } + }) + + It("calls the watched events repo with correct filter", func() { + transformer.Execute() + Expect(len(watchedEventsRepo.Names)).To(Equal(2)) + Expect(watchedEventsRepo.Names).To(ConsistOf([]string{constants.BurnEvent.String(), constants.MintEvent.String()})) + }) + + It("calls the mock ERC20 converter with the watched events", func() { + transformer.Execute() + Expect(len(mockERC20Converter.WatchedEvents)).To(Equal(2)) + Expect(mockERC20Converter.WatchedEvents).To(ConsistOf(fakeWatchedEvents)) + }) + + It("converts a Burn and Mint entity to their models", func() { + transformer.Execute() + Expect(len(mockERC20Converter.BurnsToConvert)).To(Equal(1)) + Expect(mockERC20Converter.BurnsToConvert[0].Block).To(Equal(blockID1)) + + Expect(len(mockERC20Converter.MintsToConvert)).To(Equal(1)) + Expect(mockERC20Converter.MintsToConvert[0].Block).To(Equal(blockID2)) + }) + + It("persists Burn and Mint data for each watched Burn or Mint event", func() { + transformer.Execute() + Expect(len(mockEventRepo.BurnLogs)).To(Equal(1)) + Expect(len(mockEventRepo.MintLogs)).To(Equal(1)) + Expect(mockEventRepo.VulcanizeLogIDs).To(ConsistOf(logID1, logID2)) + }) + +}) diff --git a/examples/generic/every_block/every_block_suite_test.go b/examples/generic/every_block/every_block_suite_test.go index daf68e25..e43b72f9 100644 --- a/examples/generic/every_block/every_block_suite_test.go +++ b/examples/generic/every_block/every_block_suite_test.go @@ -15,12 +15,12 @@ package every_block_test import ( + "io/ioutil" + "log" "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "io/ioutil" - "log" ) func TestEveryBlock(t *testing.T) { diff --git a/examples/generic/every_block/getter.go b/examples/generic/every_block/getter.go index ec06de9a..2a283024 100644 --- a/examples/generic/every_block/getter.go +++ b/examples/generic/every_block/getter.go @@ -15,10 +15,12 @@ package every_block import ( + "math/big" + "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/examples/generic" "github.com/vulcanize/vulcanizedb/pkg/core" - "math/big" ) // Getter serves as a higher level data fetcher that invokes its underlying Fetcher methods for a given contract method @@ -36,13 +38,13 @@ type GenericGetterInterface interface { } // Getter struct -type Getter struct { +type GenericGetter struct { fetcher generic.Fetcher // Underlying Fetcher } // Initializes and returns a Getter with the given blockchain -func NewGetter(blockChain core.BlockChain) Getter { - return Getter{ +func NewGetter(blockChain core.BlockChain) GenericGetter { + return GenericGetter{ fetcher: generic.Fetcher{ BlockChain: blockChain, }, @@ -50,35 +52,35 @@ func NewGetter(blockChain core.BlockChain) Getter { } // Public getter methods for calling contract methods -func (g Getter) GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error) { +func (g GenericGetter) GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error) { return g.fetcher.FetchAddress("owner", contractAbi, contractAddress, blockNumber, nil) } -func (g Getter) GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error) { +func (g GenericGetter) GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error) { return g.fetcher.FetchBool("stopped", contractAbi, contractAddress, blockNumber, nil) } -func (g Getter) GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error) { +func (g GenericGetter) GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error) { return g.fetcher.FetchString("name", contractAbi, contractAddress, blockNumber, nil) } -func (g Getter) GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { +func (g GenericGetter) GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { return g.fetcher.FetchHash("name", contractAbi, contractAddress, blockNumber, nil) } -func (g Getter) GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error) { +func (g GenericGetter) GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error) { return g.fetcher.FetchString("symbol", contractAbi, contractAddress, blockNumber, nil) } -func (g Getter) GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { +func (g GenericGetter) GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) { return g.fetcher.FetchHash("symbol", contractAbi, contractAddress, blockNumber, nil) } -func (g Getter) GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { +func (g GenericGetter) GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) { return g.fetcher.FetchBigInt("decimals", contractAbi, contractAddress, blockNumber, nil) } // Method to retrieve the Getter's blockchain -func (g Getter) GetBlockChain() core.BlockChain { +func (g GenericGetter) GetBlockChain() core.BlockChain { return g.fetcher.BlockChain } diff --git a/examples/generic/every_block/getter_test.go b/examples/generic/every_block/getter_test.go index 3251c053..d2bc9774 100644 --- a/examples/generic/every_block/getter_test.go +++ b/examples/generic/every_block/getter_test.go @@ -15,12 +15,14 @@ package every_block_test import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/ethereum/go-ethereum/common" "github.com/vulcanize/vulcanizedb/examples/constants" "github.com/vulcanize/vulcanizedb/examples/generic/every_block" "github.com/vulcanize/vulcanizedb/pkg/fakes" @@ -28,7 +30,6 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/geth/client" rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" "github.com/vulcanize/vulcanizedb/pkg/geth/node" - "math/big" ) var _ = Describe("every_block Getter", func() { diff --git a/examples/generic/fetcher.go b/examples/generic/fetcher.go index 3417323d..2f083c72 100644 --- a/examples/generic/fetcher.go +++ b/examples/generic/fetcher.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/pkg/core" ) diff --git a/examples/generic/helpers/helpers.go b/examples/generic/helpers/helpers.go index 706277ef..116930af 100644 --- a/examples/generic/helpers/helpers.go +++ b/examples/generic/helpers/helpers.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/vulcanize/vulcanizedb/pkg/core" ) diff --git a/examples/generic/retriever.go b/examples/generic/retriever.go index 6cc14f43..4ff5a1e6 100644 --- a/examples/generic/retriever.go +++ b/examples/generic/retriever.go @@ -16,21 +16,25 @@ package generic import ( "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "log" + + "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" ) // Retriever is used to iterate over addresses going into or out of a contract // address in an attempt to generate a list of token holder addresses -type RetrieverInterface interface { - retrieveTransferEventAddresses() ([][2]string, error) - retrieveApprovalEventAddresses() ([][2]string, error) - RetrieveContractAssociatedAddresses() (map[common.Address]bool, error) +type TokenHolderRetrieverInterface interface { + RetrieveTokenHolderAddresses() (map[common.Address]bool, error) + retrieveTokenSenders() ([]string, error) + retrieveTokenReceivers() ([]string, error) + retrieveTokenOwners() ([]string, error) + retrieveTokenSpenders() ([]string, error) } -type Retriever struct { +type TokenHolderRetriever struct { Database *postgres.DB ContractAddress string } @@ -59,16 +63,18 @@ const ( GetReceiversError = "Error fetching token receivers from contract %s: %s" GetOwnersError = "Error fetching token owners from contract %s: %s" GetSpendersError = "Error fetching token spenders from contract %s: %s" + GetMinteesError = "Error fetching token mintees from contract %s: %s" + GetBurnersError = "Error fetching token burners from contract %s: %s" ) -func NewRetriever(db *postgres.DB, address string) Retriever { - return Retriever{ +func NewTokenHolderRetriever(db *postgres.DB, address string) TokenHolderRetriever { + return TokenHolderRetriever{ Database: db, ContractAddress: address, } } -func (rt Retriever) retrieveTokenSenders() ([]string, error) { +func (rt TokenHolderRetriever) retrieveTokenSenders() ([]string, error) { senders := make([]string, 0) @@ -81,10 +87,11 @@ func (rt Retriever) retrieveTokenSenders() ([]string, error) { if err != nil { return []string{}, newRetrieverError(err, GetSendersError, rt.ContractAddress) } - return senders, err + + return senders, nil } -func (rt Retriever) retrieveTokenReceivers() ([]string, error) { +func (rt TokenHolderRetriever) retrieveTokenReceivers() ([]string, error) { receivers := make([]string, 0) @@ -100,7 +107,41 @@ func (rt Retriever) retrieveTokenReceivers() ([]string, error) { return receivers, err } -func (rt Retriever) retrieveTokenOwners() ([]string, error) { +func (rt TokenHolderRetriever) retrieveTokenMintees() ([]string, error) { + + mintees := make([]string, 0) + + err := rt.Database.DB.Select( + &mintees, + `SELECT mintee FROM token_mints + WHERE token_address = $1`, + rt.ContractAddress, + ) + if err != nil { + return []string{}, newRetrieverError(err, GetMinteesError, rt.ContractAddress) + } + + return mintees, nil +} + +func (rt TokenHolderRetriever) retrieveTokenBurners() ([]string, error) { + + burners := make([]string, 0) + + err := rt.Database.DB.Select( + &burners, + `SELECT burner FROM token_burns + WHERE token_address = $1`, + rt.ContractAddress, + ) + if err != nil { + return []string{}, newRetrieverError(err, GetBurnersError, rt.ContractAddress) + } + + return burners, nil +} + +func (rt TokenHolderRetriever) retrieveTokenOwners() ([]string, error) { owners := make([]string, 0) @@ -113,10 +154,11 @@ func (rt Retriever) retrieveTokenOwners() ([]string, error) { if err != nil { return []string{}, newRetrieverError(err, GetOwnersError, rt.ContractAddress) } - return owners, err + + return owners, nil } -func (rt Retriever) retrieveTokenSpenders() ([]string, error) { +func (rt TokenHolderRetriever) retrieveTokenSpenders() ([]string, error) { spenders := make([]string, 0) @@ -129,10 +171,11 @@ func (rt Retriever) retrieveTokenSpenders() ([]string, error) { if err != nil { return []string{}, newRetrieverError(err, GetSpendersError, rt.ContractAddress) } - return spenders, err + + return spenders, nil } -func (rt Retriever) RetrieveTokenHolderAddresses() (map[common.Address]bool, error) { +func (rt TokenHolderRetriever) RetrieveTokenHolderAddresses() (map[common.Address]bool, error) { senders, err := rt.retrieveTokenSenders() if err != nil { @@ -144,6 +187,16 @@ func (rt Retriever) RetrieveTokenHolderAddresses() (map[common.Address]bool, err return nil, err } + mintees, err := rt.retrieveTokenMintees() + if err != nil { + return nil, err + } + + burners, err := rt.retrieveTokenBurners() + if err != nil { + return nil, err + } + owners, err := rt.retrieveTokenOwners() if err != nil { return nil, err @@ -164,6 +217,14 @@ func (rt Retriever) RetrieveTokenHolderAddresses() (map[common.Address]bool, err contractAddresses[common.HexToAddress(addr)] = true } + for _, addr := range mintees { + contractAddresses[common.HexToAddress(addr)] = true + } + + for _, addr := range burners { + contractAddresses[common.HexToAddress(addr)] = true + } + for _, addr := range owners { contractAddresses[common.HexToAddress(addr)] = true } diff --git a/examples/mocks/converter.go b/examples/mocks/converter.go new file mode 100644 index 00000000..63ff1a98 --- /dev/null +++ b/examples/mocks/converter.go @@ -0,0 +1,78 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mocks + +import ( + et1 "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" + et2 "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" + "github.com/vulcanize/vulcanizedb/pkg/core" +) + +type MockERC20Converter struct { + WatchedEvents []*core.WatchedEvent + TransfersToConvert []et1.TransferEntity + ApprovalsToConvert []et1.ApprovalEntity + BurnsToConvert []et2.BurnEntity + MintsToConvert []et2.MintEntity + block int64 +} + +func (mlkc *MockERC20Converter) ToTransferModel(entity *et1.TransferEntity) *et1.TransferModel { + mlkc.TransfersToConvert = append(mlkc.TransfersToConvert, *entity) + return &et1.TransferModel{} +} + +func (mlkc *MockERC20Converter) ToTransferEntity(watchedEvent core.WatchedEvent) (*et1.TransferEntity, error) { + mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) + e := &et1.TransferEntity{Block: watchedEvent.BlockNumber} + mlkc.block++ + return e, nil +} + +func (mlkc *MockERC20Converter) ToApprovalModel(entity *et1.ApprovalEntity) *et1.ApprovalModel { + mlkc.ApprovalsToConvert = append(mlkc.ApprovalsToConvert, *entity) + return &et1.ApprovalModel{} +} + +func (mlkc *MockERC20Converter) ToApprovalEntity(watchedEvent core.WatchedEvent) (*et1.ApprovalEntity, error) { + mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) + e := &et1.ApprovalEntity{Block: watchedEvent.BlockNumber} + mlkc.block++ + return e, nil +} + +func (mlkc *MockERC20Converter) ToBurnEntity(watchedEvent core.WatchedEvent) (*et2.BurnEntity, error) { + mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) + e := &et2.BurnEntity{Block: watchedEvent.BlockNumber} + mlkc.block++ + return e, nil +} + +func (mlkc *MockERC20Converter) ToBurnModel(entity *et2.BurnEntity) *et2.BurnModel { + mlkc.BurnsToConvert = append(mlkc.BurnsToConvert, *entity) + return &et2.BurnModel{} +} + +func (mlkc *MockERC20Converter) ToMintEntity(watchedEvent core.WatchedEvent) (*et2.MintEntity, error) { + mlkc.WatchedEvents = append(mlkc.WatchedEvents, &watchedEvent) + e := &et2.MintEntity{Block: watchedEvent.BlockNumber} + mlkc.block++ + return e, nil +} + +func (mlkc *MockERC20Converter) ToMintModel(entity *et2.MintEntity) *et2.MintModel { + mlkc.MintsToConvert = append(mlkc.MintsToConvert, *entity) + return &et2.MintModel{} +} diff --git a/examples/mocks/event_repo.go b/examples/mocks/event_repo.go index 121ddc50..23c722b5 100644 --- a/examples/mocks/event_repo.go +++ b/examples/mocks/event_repo.go @@ -15,7 +15,8 @@ package mocks import ( - "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" + et1 "github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered" + et2 "github.com/vulcanize/vulcanizedb/examples/generic/event_triggered" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/filters" ) @@ -23,6 +24,8 @@ import ( type MockWatchedEventsRepository struct { watchedTransferEvents []*core.WatchedEvent watchedApprovalEvents []*core.WatchedEvent + watchedBurnEvents []*core.WatchedEvent + watchedMintEvents []*core.WatchedEvent Names []string } @@ -34,6 +37,12 @@ func (mwer *MockWatchedEventsRepository) SetWatchedEvents(watchedEvents []*core. if event.Name == "Approval" { mwer.watchedApprovalEvents = append(mwer.watchedApprovalEvents, event) } + if event.Name == "Burn" { + mwer.watchedBurnEvents = append(mwer.watchedBurnEvents, event) + } + if event.Name == "Mint" { + mwer.watchedMintEvents = append(mwer.watchedMintEvents, event) + } } } @@ -50,23 +59,47 @@ func (mwer *MockWatchedEventsRepository) GetWatchedEvents(name string) ([]*core. // clear watched events once returned so same events are returned for every filter while testing mwer.watchedApprovalEvents = []*core.WatchedEvent{} } + if name == "Burn" { + result = mwer.watchedBurnEvents + // clear watched events once returned so same events are returned for every filter while testing + mwer.watchedBurnEvents = []*core.WatchedEvent{} + } + if name == "Mint" { + result = mwer.watchedMintEvents + // clear watched events once returned so same events are returned for every filter while testing + mwer.watchedMintEvents = []*core.WatchedEvent{} + } return result, nil } type MockEventRepo struct { - TransferLogs []event_triggered.TransferModel - ApprovalLogs []event_triggered.ApprovalModel + TransferLogs []et1.TransferModel + ApprovalLogs []et1.ApprovalModel + BurnLogs []et2.BurnModel + MintLogs []et2.MintModel VulcanizeLogIDs []int64 } -func (molr *MockEventRepo) CreateTransfer(transferModel event_triggered.TransferModel, vulcanizeLogId int64) error { - molr.TransferLogs = append(molr.TransferLogs, transferModel) +func (molr *MockEventRepo) CreateTransfer(transferModel *et1.TransferModel, vulcanizeLogId int64) error { + molr.TransferLogs = append(molr.TransferLogs, *transferModel) molr.VulcanizeLogIDs = append(molr.VulcanizeLogIDs, vulcanizeLogId) return nil } -func (molk *MockEventRepo) CreateApproval(approvalModel event_triggered.ApprovalModel, vulcanizeLogID int64) error { - molk.ApprovalLogs = append(molk.ApprovalLogs, approvalModel) +func (molk *MockEventRepo) CreateApproval(approvalModel *et1.ApprovalModel, vulcanizeLogID int64) error { + molk.ApprovalLogs = append(molk.ApprovalLogs, *approvalModel) + molk.VulcanizeLogIDs = append(molk.VulcanizeLogIDs, vulcanizeLogID) + return nil +} + +func (molr *MockEventRepo) CreateBurn(burnModel *et2.BurnModel, vulcanizeLogId int64) error { + molr.BurnLogs = append(molr.BurnLogs, *burnModel) + molr.VulcanizeLogIDs = append(molr.VulcanizeLogIDs, vulcanizeLogId) + return nil +} + +func (molk *MockEventRepo) CreateMint(mintModel *et2.MintModel, vulcanizeLogID int64) error { + molk.MintLogs = append(molk.MintLogs, *mintModel) molk.VulcanizeLogIDs = append(molk.VulcanizeLogIDs, vulcanizeLogID) return nil } diff --git a/examples/mocks/fetcher.go b/examples/mocks/fetcher.go index 4104577c..940039f4 100644 --- a/examples/mocks/fetcher.go +++ b/examples/mocks/fetcher.go @@ -17,10 +17,11 @@ package mocks import ( "errors" "math/big" + "reflect" "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/pkg/core" - "reflect" ) type Fetcher struct { diff --git a/examples/mocks/getter.go b/examples/mocks/getter.go index ff147b5b..d9106147 100644 --- a/examples/mocks/getter.go +++ b/examples/mocks/getter.go @@ -18,6 +18,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/vulcanize/vulcanizedb/pkg/core" ) diff --git a/examples/test_helpers/database.go b/examples/test_helpers/database.go index 3e7acf45..1b7855d7 100644 --- a/examples/test_helpers/database.go +++ b/examples/test_helpers/database.go @@ -15,8 +15,12 @@ package test_helpers import ( + "math/rand" + "time" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/config" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" @@ -74,3 +78,52 @@ func CreateBlock(blockNumber int64, repository repositories.BlockRepository) (bl return blockId } + +func SetupIntegrationDB(db *postgres.DB, logs []core.Log) *postgres.DB { + + rand.Seed(time.Now().UnixNano()) + + db, err := postgres.NewDB(config.Database{ + Hostname: "localhost", + Name: "vulcanize_private", + Port: 5432, + }, core.Node{}) + Expect(err).NotTo(HaveOccurred()) + + receiptRepository := repositories.ReceiptRepository{DB: db} + blockRepository := *repositories.NewBlockRepository(db) + + blockNumber := rand.Int63() + blockId := CreateBlock(blockNumber, blockRepository) + + receipt := core.Receipt{ + Logs: logs, + } + receipts := []core.Receipt{receipt} + + err = receiptRepository.CreateReceiptsAndLogs(blockId, receipts) + Expect(err).NotTo(HaveOccurred()) + + var vulcanizeLogIds []int64 + err = db.Select(&vulcanizeLogIds, `SELECT id FROM logs`) + Expect(err).NotTo(HaveOccurred()) + + return db +} + +func TearDownIntegrationDB(db *postgres.DB) *postgres.DB { + + _, err := db.Exec(`DELETE FROM token_transfers`) + Expect(err).NotTo(HaveOccurred()) + + _, err = db.Exec(`DELETE FROM token_approvals`) + Expect(err).NotTo(HaveOccurred()) + + _, err = db.Exec(`DELETE FROM log_filters`) + Expect(err).NotTo(HaveOccurred()) + + _, err = db.Exec(`DELETE FROM logs`) + Expect(err).NotTo(HaveOccurred()) + + return db +} diff --git a/integration_test/contract_test.go b/integration_test/contract_test.go index 275e4769..72c1473e 100644 --- a/integration_test/contract_test.go +++ b/integration_test/contract_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" diff --git a/integration_test/geth_blockchain_test.go b/integration_test/geth_blockchain_test.go index 9dc386eb..a64906c8 100644 --- a/integration_test/geth_blockchain_test.go +++ b/integration_test/geth_blockchain_test.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/fakes" "github.com/vulcanize/vulcanizedb/pkg/geth" diff --git a/integration_test/integration_test_suite_test.go b/integration_test/integration_test_suite_test.go index b9c75608..73ecd005 100644 --- a/integration_test/integration_test_suite_test.go +++ b/integration_test/integration_test_suite_test.go @@ -1,10 +1,10 @@ package integration_test import ( + "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - - "testing" ) func TestIntegrationTest(t *testing.T) { diff --git a/test_config/test_config.go b/test_config/test_config.go index b1a59d1b..643908b8 100644 --- a/test_config/test_config.go +++ b/test_config/test_config.go @@ -2,10 +2,10 @@ package test_config import ( "log" - "os" "github.com/spf13/viper" + "github.com/vulcanize/vulcanizedb/pkg/config" "github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" diff --git a/utils/utils.go b/utils/utils.go index 7652e2ee..d1e26060 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -2,12 +2,9 @@ package utils import ( "log" - - "path/filepath" - "math/big" - "os" + "path/filepath" "github.com/vulcanize/vulcanizedb/pkg/config" "github.com/vulcanize/vulcanizedb/pkg/core" diff --git a/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go b/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go index 6f140271..c275514d 100644 --- a/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go +++ b/vendor/github.com/btcsuite/btcd/btcec/btcec_test.go @@ -898,132 +898,132 @@ var testVectors = []struct { r, s string ok bool }{ -/* - * All of these tests are disabled since they are for P224, not sec256k1. - * they are left here as an example of test vectors for when some *real* - * vectors may be found. - * - oga@conformal.com - { - "09626b45493672e48f3d1226a3aff3201960e577d33a7f72c7eb055302db8fe8ed61685dd036b554942a5737cd1512cdf811ee0c00e6dd2f08c69f08643be396e85dafda664801e772cdb7396868ac47b172245b41986aa2648cb77fbbfa562581be06651355a0c4b090f9d17d8f0ab6cced4e0c9d386cf465a516630f0231bd", - "9504b5b82d97a264d8b3735e0568decabc4b6ca275bc53cbadfc1c40", - "03426f80e477603b10dee670939623e3da91a94267fc4e51726009ed", - "81d3ac609f9575d742028dd496450a58a60eea2dcf8b9842994916e1", - "96a8c5f382c992e8f30ccce9af120b067ec1d74678fa8445232f75a5", - false, - }, - { - "96b2b6536f6df29be8567a72528aceeaccbaa66c66c534f3868ca9778b02faadb182e4ed34662e73b9d52ecbe9dc8e875fc05033c493108b380689ebf47e5b062e6a0cdb3dd34ce5fe347d92768d72f7b9b377c20aea927043b509c078ed2467d7113405d2ddd458811e6faf41c403a2a239240180f1430a6f4330df5d77de37", - "851e3100368a22478a0029353045ae40d1d8202ef4d6533cfdddafd8", - "205302ac69457dd345e86465afa72ee8c74ca97e2b0b999aec1f10c2", - "4450c2d38b697e990721aa2dbb56578d32b4f5aeb3b9072baa955ee0", - "e26d4b589166f7b4ba4b1c8fce823fa47aad22f8c9c396b8c6526e12", - false, - }, - { - "86778dbb4a068a01047a8d245d632f636c11d2ad350740b36fad90428b454ad0f120cb558d12ea5c8a23db595d87543d06d1ef489263d01ee529871eb68737efdb8ff85bc7787b61514bed85b7e01d6be209e0a4eb0db5c8df58a5c5bf706d76cb2bdf7800208639e05b89517155d11688236e6a47ed37d8e5a2b1e0adea338e", - "ad5bda09d319a717c1721acd6688d17020b31b47eef1edea57ceeffc", - "c8ce98e181770a7c9418c73c63d01494b8b80a41098c5ea50692c984", - "de5558c257ab4134e52c19d8db3b224a1899cbd08cc508ce8721d5e9", - "745db7af5a477e5046705c0a5eff1f52cb94a79d481f0c5a5e108ecd", - true, - }, - { - "4bc6ef1958556686dab1e39c3700054a304cbd8f5928603dcd97fafd1f29e69394679b638f71c9344ce6a535d104803d22119f57b5f9477e253817a52afa9bfbc9811d6cc8c8be6b6566c6ef48b439bbb532abe30627548c598867f3861ba0b154dc1c3deca06eb28df8efd28258554b5179883a36fbb1eecf4f93ee19d41e3d", - "cc5eea2edf964018bdc0504a3793e4d2145142caa09a72ac5fb8d3e8", - "a48d78ae5d08aa725342773975a00d4219cf7a8029bb8cf3c17c374a", - "67b861344b4e416d4094472faf4272f6d54a497177fbc5f9ef292836", - "1d54f3fcdad795bf3b23408ecbac3e1321d1d66f2e4e3d05f41f7020", - false, - }, - { - "bb658732acbf3147729959eb7318a2058308b2739ec58907dd5b11cfa3ecf69a1752b7b7d806fe00ec402d18f96039f0b78dbb90a59c4414fb33f1f4e02e4089de4122cd93df5263a95be4d7084e2126493892816e6a5b4ed123cb705bf930c8f67af0fb4514d5769232a9b008a803af225160ce63f675bd4872c4c97b146e5e", - "6234c936e27bf141fc7534bfc0a7eedc657f91308203f1dcbd642855", - "27983d87ca785ef4892c3591ef4a944b1deb125dd58bd351034a6f84", - "e94e05b42d01d0b965ffdd6c3a97a36a771e8ea71003de76c4ecb13f", - "1dc6464ffeefbd7872a081a5926e9fc3e66d123f1784340ba17737e9", - false, - }, - { - "7c00be9123bfa2c4290be1d8bc2942c7f897d9a5b7917e3aabd97ef1aab890f148400a89abd554d19bec9d8ed911ce57b22fbcf6d30ca2115f13ce0a3f569a23bad39ee645f624c49c60dcfc11e7d2be24de9c905596d8f23624d63dc46591d1f740e46f982bfae453f107e80db23545782be23ce43708245896fc54e1ee5c43", - "9f3f037282aaf14d4772edffff331bbdda845c3f65780498cde334f1", - "8308ee5a16e3bcb721b6bc30000a0419bc1aaedd761be7f658334066", - "6381d7804a8808e3c17901e4d283b89449096a8fba993388fa11dc54", - "8e858f6b5b253686a86b757bad23658cda53115ac565abca4e3d9f57", - false, - }, - { - "cffc122a44840dc705bb37130069921be313d8bde0b66201aebc48add028ca131914ef2e705d6bedd19dc6cf9459bbb0f27cdfe3c50483808ffcdaffbeaa5f062e097180f07a40ef4ab6ed03fe07ed6bcfb8afeb42c97eafa2e8a8df469de07317c5e1494c41547478eff4d8c7d9f0f484ad90fedf6e1c35ee68fa73f1691601", - "a03b88a10d930002c7b17ca6af2fd3e88fa000edf787dc594f8d4fd4", - "e0cf7acd6ddc758e64847fe4df9915ebda2f67cdd5ec979aa57421f5", - "387b84dcf37dc343c7d2c5beb82f0bf8bd894b395a7b894565d296c1", - "4adc12ce7d20a89ce3925e10491c731b15ddb3f339610857a21b53b4", - false, - }, - { - "26e0e0cafd85b43d16255908ccfd1f061c680df75aba3081246b337495783052ba06c60f4a486c1591a4048bae11b4d7fec4f161d80bdc9a7b79d23e44433ed625eab280521a37f23dd3e1bdc5c6a6cfaa026f3c45cf703e76dab57add93fe844dd4cda67dc3bddd01f9152579e49df60969b10f09ce9372fdd806b0c7301866", - "9a8983c42f2b5a87c37a00458b5970320d247f0c8a88536440173f7d", - "15e489ec6355351361900299088cfe8359f04fe0cab78dde952be80c", - "929a21baa173d438ec9f28d6a585a2f9abcfc0a4300898668e476dc0", - "59a853f046da8318de77ff43f26fe95a92ee296fa3f7e56ce086c872", - true, - }, - { - "1078eac124f48ae4f807e946971d0de3db3748dd349b14cca5c942560fb25401b2252744f18ad5e455d2d97ed5ae745f55ff509c6c8e64606afe17809affa855c4c4cdcaf6b69ab4846aa5624ed0687541aee6f2224d929685736c6a23906d974d3c257abce1a3fb8db5951b89ecb0cda92b5207d93f6618fd0f893c32cf6a6e", - "d6e55820bb62c2be97650302d59d667a411956138306bd566e5c3c2b", - "631ab0d64eaf28a71b9cbd27a7a88682a2167cee6251c44e3810894f", - "65af72bc7721eb71c2298a0eb4eed3cec96a737cc49125706308b129", - "bd5a987c78e2d51598dbd9c34a9035b0069c580edefdacee17ad892a", - false, - }, - { - "919deb1fdd831c23481dfdb2475dcbe325b04c34f82561ced3d2df0b3d749b36e255c4928973769d46de8b95f162b53cd666cad9ae145e7fcfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82130761231f536e6a3d59792f784902c469aa897aabf9a0678f93446610d56d5e0981e4c8a563556b", - "269b455b1024eb92d860a420f143ac1286b8cce43031562ae7664574", - "baeb6ca274a77c44a0247e5eb12ca72bdd9a698b3f3ae69c9f1aaa57", - "cb4ec2160f04613eb0dfe4608486091a25eb12aa4dec1afe91cfb008", - "40b01d8cd06589481574f958b98ca08ade9d2a8fe31024375c01bb40", - false, - }, - { - "6e012361250dacf6166d2dd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33f", - "6d2d695efc6b43b13c14111f2109608f1020e3e03b5e21cfdbc82fcd", - "26a4859296b7e360b69cf40be7bd97ceaffa3d07743c8489fc47ca1b", - "9a8cb5f2fdc288b7183c5b32d8e546fc2ed1ca4285eeae00c8b572ad", - "8c623f357b5d0057b10cdb1a1593dab57cda7bdec9cf868157a79b97", - true, - }, - { - "bf6bd7356a52b234fe24d25557200971fc803836f6fec3cade9642b13a8e7af10ab48b749de76aada9d8927f9b12f75a2c383ca7358e2566c4bb4f156fce1fd4e87ef8c8d2b6b1bdd351460feb22cdca0437ac10ca5e0abbbce9834483af20e4835386f8b1c96daaa41554ceee56730aac04f23a5c765812efa746051f396566", - "14250131b2599939cf2d6bc491be80ddfe7ad9de644387ee67de2d40", - "b5dc473b5d014cd504022043c475d3f93c319a8bdcb7262d9e741803", - "4f21642f2201278a95339a80f75cc91f8321fcb3c9462562f6cbf145", - "452a5f816ea1f75dee4fd514fa91a0d6a43622981966c59a1b371ff8", - false, - }, - { - "0eb7f4032f90f0bd3cf9473d6d9525d264d14c031a10acd31a053443ed5fe919d5ac35e0be77813071b4062f0b5fdf58ad5f637b76b0b305aec18f82441b6e607b44cdf6e0e3c7c57f24e6fd565e39430af4a6b1d979821ed0175fa03e3125506847654d7e1ae904ce1190ae38dc5919e257bdac2db142a6e7cd4da6c2e83770", - "d1f342b7790a1667370a1840255ac5bbbdc66f0bc00ae977d99260ac", - "76416cabae2de9a1000b4646338b774baabfa3db4673790771220cdb", - "bc85e3fc143d19a7271b2f9e1c04b86146073f3fab4dda1c3b1f35ca", - "9a5c70ede3c48d5f43307a0c2a4871934424a3303b815df4bb0f128e", - false, - }, - { - "5cc25348a05d85e56d4b03cec450128727bc537c66ec3a9fb613c151033b5e86878632249cba83adcefc6c1e35dcd31702929c3b57871cda5c18d1cf8f9650a25b917efaed56032e43b6fc398509f0d2997306d8f26675f3a8683b79ce17128e006aa0903b39eeb2f1001be65de0520115e6f919de902b32c38d691a69c58c92", - "7e49a7abf16a792e4c7bbc4d251820a2abd22d9f2fc252a7bf59c9a6", - "44236a8fb4791c228c26637c28ae59503a2f450d4cfb0dc42aa843b9", - "084461b4050285a1a85b2113be76a17878d849e6bc489f4d84f15cd8", - "079b5bddcc4d45de8dbdfd39f69817c7e5afa454a894d03ee1eaaac3", - false, - }, - { - "1951533ce33afb58935e39e363d8497a8dd0442018fd96dff167b3b23d7206a3ee182a3194765df4768a3284e23b8696c199b4686e670d60c9d782f08794a4bccc05cffffbd1a12acd9eb1cfa01f7ebe124da66ecff4599ea7720c3be4bb7285daa1a86ebf53b042bd23208d468c1b3aa87381f8e1ad63e2b4c2ba5efcf05845", - "31945d12ebaf4d81f02be2b1768ed80784bf35cf5e2ff53438c11493", - "a62bebffac987e3b9d3ec451eb64c462cdf7b4aa0b1bbb131ceaa0a4", - "bc3c32b19e42b710bca5c6aaa128564da3ddb2726b25f33603d2af3c", - "ed1a719cc0c507edc5239d76fe50e2306c145ad252bd481da04180c0", - false, - }, -*/ + /* + * All of these tests are disabled since they are for P224, not sec256k1. + * they are left here as an example of test vectors for when some *real* + * vectors may be found. + * - oga@conformal.com + { + "09626b45493672e48f3d1226a3aff3201960e577d33a7f72c7eb055302db8fe8ed61685dd036b554942a5737cd1512cdf811ee0c00e6dd2f08c69f08643be396e85dafda664801e772cdb7396868ac47b172245b41986aa2648cb77fbbfa562581be06651355a0c4b090f9d17d8f0ab6cced4e0c9d386cf465a516630f0231bd", + "9504b5b82d97a264d8b3735e0568decabc4b6ca275bc53cbadfc1c40", + "03426f80e477603b10dee670939623e3da91a94267fc4e51726009ed", + "81d3ac609f9575d742028dd496450a58a60eea2dcf8b9842994916e1", + "96a8c5f382c992e8f30ccce9af120b067ec1d74678fa8445232f75a5", + false, + }, + { + "96b2b6536f6df29be8567a72528aceeaccbaa66c66c534f3868ca9778b02faadb182e4ed34662e73b9d52ecbe9dc8e875fc05033c493108b380689ebf47e5b062e6a0cdb3dd34ce5fe347d92768d72f7b9b377c20aea927043b509c078ed2467d7113405d2ddd458811e6faf41c403a2a239240180f1430a6f4330df5d77de37", + "851e3100368a22478a0029353045ae40d1d8202ef4d6533cfdddafd8", + "205302ac69457dd345e86465afa72ee8c74ca97e2b0b999aec1f10c2", + "4450c2d38b697e990721aa2dbb56578d32b4f5aeb3b9072baa955ee0", + "e26d4b589166f7b4ba4b1c8fce823fa47aad22f8c9c396b8c6526e12", + false, + }, + { + "86778dbb4a068a01047a8d245d632f636c11d2ad350740b36fad90428b454ad0f120cb558d12ea5c8a23db595d87543d06d1ef489263d01ee529871eb68737efdb8ff85bc7787b61514bed85b7e01d6be209e0a4eb0db5c8df58a5c5bf706d76cb2bdf7800208639e05b89517155d11688236e6a47ed37d8e5a2b1e0adea338e", + "ad5bda09d319a717c1721acd6688d17020b31b47eef1edea57ceeffc", + "c8ce98e181770a7c9418c73c63d01494b8b80a41098c5ea50692c984", + "de5558c257ab4134e52c19d8db3b224a1899cbd08cc508ce8721d5e9", + "745db7af5a477e5046705c0a5eff1f52cb94a79d481f0c5a5e108ecd", + true, + }, + { + "4bc6ef1958556686dab1e39c3700054a304cbd8f5928603dcd97fafd1f29e69394679b638f71c9344ce6a535d104803d22119f57b5f9477e253817a52afa9bfbc9811d6cc8c8be6b6566c6ef48b439bbb532abe30627548c598867f3861ba0b154dc1c3deca06eb28df8efd28258554b5179883a36fbb1eecf4f93ee19d41e3d", + "cc5eea2edf964018bdc0504a3793e4d2145142caa09a72ac5fb8d3e8", + "a48d78ae5d08aa725342773975a00d4219cf7a8029bb8cf3c17c374a", + "67b861344b4e416d4094472faf4272f6d54a497177fbc5f9ef292836", + "1d54f3fcdad795bf3b23408ecbac3e1321d1d66f2e4e3d05f41f7020", + false, + }, + { + "bb658732acbf3147729959eb7318a2058308b2739ec58907dd5b11cfa3ecf69a1752b7b7d806fe00ec402d18f96039f0b78dbb90a59c4414fb33f1f4e02e4089de4122cd93df5263a95be4d7084e2126493892816e6a5b4ed123cb705bf930c8f67af0fb4514d5769232a9b008a803af225160ce63f675bd4872c4c97b146e5e", + "6234c936e27bf141fc7534bfc0a7eedc657f91308203f1dcbd642855", + "27983d87ca785ef4892c3591ef4a944b1deb125dd58bd351034a6f84", + "e94e05b42d01d0b965ffdd6c3a97a36a771e8ea71003de76c4ecb13f", + "1dc6464ffeefbd7872a081a5926e9fc3e66d123f1784340ba17737e9", + false, + }, + { + "7c00be9123bfa2c4290be1d8bc2942c7f897d9a5b7917e3aabd97ef1aab890f148400a89abd554d19bec9d8ed911ce57b22fbcf6d30ca2115f13ce0a3f569a23bad39ee645f624c49c60dcfc11e7d2be24de9c905596d8f23624d63dc46591d1f740e46f982bfae453f107e80db23545782be23ce43708245896fc54e1ee5c43", + "9f3f037282aaf14d4772edffff331bbdda845c3f65780498cde334f1", + "8308ee5a16e3bcb721b6bc30000a0419bc1aaedd761be7f658334066", + "6381d7804a8808e3c17901e4d283b89449096a8fba993388fa11dc54", + "8e858f6b5b253686a86b757bad23658cda53115ac565abca4e3d9f57", + false, + }, + { + "cffc122a44840dc705bb37130069921be313d8bde0b66201aebc48add028ca131914ef2e705d6bedd19dc6cf9459bbb0f27cdfe3c50483808ffcdaffbeaa5f062e097180f07a40ef4ab6ed03fe07ed6bcfb8afeb42c97eafa2e8a8df469de07317c5e1494c41547478eff4d8c7d9f0f484ad90fedf6e1c35ee68fa73f1691601", + "a03b88a10d930002c7b17ca6af2fd3e88fa000edf787dc594f8d4fd4", + "e0cf7acd6ddc758e64847fe4df9915ebda2f67cdd5ec979aa57421f5", + "387b84dcf37dc343c7d2c5beb82f0bf8bd894b395a7b894565d296c1", + "4adc12ce7d20a89ce3925e10491c731b15ddb3f339610857a21b53b4", + false, + }, + { + "26e0e0cafd85b43d16255908ccfd1f061c680df75aba3081246b337495783052ba06c60f4a486c1591a4048bae11b4d7fec4f161d80bdc9a7b79d23e44433ed625eab280521a37f23dd3e1bdc5c6a6cfaa026f3c45cf703e76dab57add93fe844dd4cda67dc3bddd01f9152579e49df60969b10f09ce9372fdd806b0c7301866", + "9a8983c42f2b5a87c37a00458b5970320d247f0c8a88536440173f7d", + "15e489ec6355351361900299088cfe8359f04fe0cab78dde952be80c", + "929a21baa173d438ec9f28d6a585a2f9abcfc0a4300898668e476dc0", + "59a853f046da8318de77ff43f26fe95a92ee296fa3f7e56ce086c872", + true, + }, + { + "1078eac124f48ae4f807e946971d0de3db3748dd349b14cca5c942560fb25401b2252744f18ad5e455d2d97ed5ae745f55ff509c6c8e64606afe17809affa855c4c4cdcaf6b69ab4846aa5624ed0687541aee6f2224d929685736c6a23906d974d3c257abce1a3fb8db5951b89ecb0cda92b5207d93f6618fd0f893c32cf6a6e", + "d6e55820bb62c2be97650302d59d667a411956138306bd566e5c3c2b", + "631ab0d64eaf28a71b9cbd27a7a88682a2167cee6251c44e3810894f", + "65af72bc7721eb71c2298a0eb4eed3cec96a737cc49125706308b129", + "bd5a987c78e2d51598dbd9c34a9035b0069c580edefdacee17ad892a", + false, + }, + { + "919deb1fdd831c23481dfdb2475dcbe325b04c34f82561ced3d2df0b3d749b36e255c4928973769d46de8b95f162b53cd666cad9ae145e7fcfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82130761231f536e6a3d59792f784902c469aa897aabf9a0678f93446610d56d5e0981e4c8a563556b", + "269b455b1024eb92d860a420f143ac1286b8cce43031562ae7664574", + "baeb6ca274a77c44a0247e5eb12ca72bdd9a698b3f3ae69c9f1aaa57", + "cb4ec2160f04613eb0dfe4608486091a25eb12aa4dec1afe91cfb008", + "40b01d8cd06589481574f958b98ca08ade9d2a8fe31024375c01bb40", + false, + }, + { + "6e012361250dacf6166d2dd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33f", + "6d2d695efc6b43b13c14111f2109608f1020e3e03b5e21cfdbc82fcd", + "26a4859296b7e360b69cf40be7bd97ceaffa3d07743c8489fc47ca1b", + "9a8cb5f2fdc288b7183c5b32d8e546fc2ed1ca4285eeae00c8b572ad", + "8c623f357b5d0057b10cdb1a1593dab57cda7bdec9cf868157a79b97", + true, + }, + { + "bf6bd7356a52b234fe24d25557200971fc803836f6fec3cade9642b13a8e7af10ab48b749de76aada9d8927f9b12f75a2c383ca7358e2566c4bb4f156fce1fd4e87ef8c8d2b6b1bdd351460feb22cdca0437ac10ca5e0abbbce9834483af20e4835386f8b1c96daaa41554ceee56730aac04f23a5c765812efa746051f396566", + "14250131b2599939cf2d6bc491be80ddfe7ad9de644387ee67de2d40", + "b5dc473b5d014cd504022043c475d3f93c319a8bdcb7262d9e741803", + "4f21642f2201278a95339a80f75cc91f8321fcb3c9462562f6cbf145", + "452a5f816ea1f75dee4fd514fa91a0d6a43622981966c59a1b371ff8", + false, + }, + { + "0eb7f4032f90f0bd3cf9473d6d9525d264d14c031a10acd31a053443ed5fe919d5ac35e0be77813071b4062f0b5fdf58ad5f637b76b0b305aec18f82441b6e607b44cdf6e0e3c7c57f24e6fd565e39430af4a6b1d979821ed0175fa03e3125506847654d7e1ae904ce1190ae38dc5919e257bdac2db142a6e7cd4da6c2e83770", + "d1f342b7790a1667370a1840255ac5bbbdc66f0bc00ae977d99260ac", + "76416cabae2de9a1000b4646338b774baabfa3db4673790771220cdb", + "bc85e3fc143d19a7271b2f9e1c04b86146073f3fab4dda1c3b1f35ca", + "9a5c70ede3c48d5f43307a0c2a4871934424a3303b815df4bb0f128e", + false, + }, + { + "5cc25348a05d85e56d4b03cec450128727bc537c66ec3a9fb613c151033b5e86878632249cba83adcefc6c1e35dcd31702929c3b57871cda5c18d1cf8f9650a25b917efaed56032e43b6fc398509f0d2997306d8f26675f3a8683b79ce17128e006aa0903b39eeb2f1001be65de0520115e6f919de902b32c38d691a69c58c92", + "7e49a7abf16a792e4c7bbc4d251820a2abd22d9f2fc252a7bf59c9a6", + "44236a8fb4791c228c26637c28ae59503a2f450d4cfb0dc42aa843b9", + "084461b4050285a1a85b2113be76a17878d849e6bc489f4d84f15cd8", + "079b5bddcc4d45de8dbdfd39f69817c7e5afa454a894d03ee1eaaac3", + false, + }, + { + "1951533ce33afb58935e39e363d8497a8dd0442018fd96dff167b3b23d7206a3ee182a3194765df4768a3284e23b8696c199b4686e670d60c9d782f08794a4bccc05cffffbd1a12acd9eb1cfa01f7ebe124da66ecff4599ea7720c3be4bb7285daa1a86ebf53b042bd23208d468c1b3aa87381f8e1ad63e2b4c2ba5efcf05845", + "31945d12ebaf4d81f02be2b1768ed80784bf35cf5e2ff53438c11493", + "a62bebffac987e3b9d3ec451eb64c462cdf7b4aa0b1bbb131ceaa0a4", + "bc3c32b19e42b710bca5c6aaa128564da3ddb2726b25f33603d2af3c", + "ed1a719cc0c507edc5239d76fe50e2306c145ad252bd481da04180c0", + false, + }, + */ } func TestVectors(t *testing.T) {