Created
August 24, 2016 09:55
-
-
Save miladmostavi/508f1628e543d10b314d901b8fd9097d to your computer and use it in GitHub Desktop.
SingularDTV crowdsale javascript code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var SingularDTVCrowdfunding_abi = [{"inputs": [], "constant": true, "type": "function", "name": "startDate", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "CROWDFUNDING_PERIOD", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "emergencyCall", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [{"type": "address", "name": "singularDTVFundAddress"}, {"type": "address", "name": "singularDTVTokenAddress"}], "constant": false, "type": "function", "name": "setup", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "withdrawFunding", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "fundBalance", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "singularDTVFund", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "baseValue", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "TOKEN_TARGET", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "singularDTVToken", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "owner", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [{"type": "uint256", "name": "valueInWei"}], "constant": false, "type": "function", "name": "changeBaseValue", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [{"type": "address", "name": ""}], "constant": true, "type": "function", "name": "investments", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "fund", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "stage", "outputs": [{"type": "uint8", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "updateStage", "outputs": [{"type": "uint8", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "valuePerShare", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "TOKEN_LOCKING_PERIOD", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "campaignEndedSuccessfully", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "workshopWaited2Years", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "CAP", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "withdrawForWorkshop", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "type": "constructor"}]; | |
var SingularDTVFund_abi = [{"inputs": [{"type": "address", "name": "singularDTVCrowdfundingAddress"}, {"type": "address", "name": "singularDTVTokenAddress"}], "constant": false, "type": "function", "name": "setup", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "depositRevenue", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": false, "type": "function", "name": "withdrawRevenue", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [{"type": "address", "name": "forAddress"}], "constant": false, "type": "function", "name": "softWithdrawRevenueFor", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "workshop", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [{"type": "address", "name": ""}], "constant": true, "type": "function", "name": "revenueAtTimeOfWithdraw", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "singularDTVToken", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "owner", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "singularDTVCrowdfunding", "outputs": [{"type": "address", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "totalRevenue", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [{"type": "address", "name": ""}], "constant": true, "type": "function", "name": "owed", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [], "type": "constructor"}]; | |
var SingularDTVToken_abi = [{"inputs": [], "constant": true, "type": "function", "name": "name", "outputs": [{"type": "string", "name": ""}]}, {"inputs": [{"type": "address", "name": "_spender"}, {"type": "uint256", "name": "_value"}], "constant": false, "type": "function", "name": "approve", "outputs": [{"type": "bool", "name": "success"}]}, {"inputs": [], "constant": true, "type": "function", "name": "totalSupply", "outputs": [{"type": "uint256", "name": ""}]}, {"inputs": [{"type": "address", "name": "from"}, {"type": "address", "name": "to"}, {"type": "uint256", "name": "value"}], "constant": false, "type": "function", "name": "transferFrom", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [], "constant": true, "type": "function", "name": "decimals", "outputs": [{"type": "uint8", "name": ""}]}, {"inputs": [{"type": "address", "name": "_for"}, {"type": "uint256", "name": "tokenCount"}], "constant": false, "type": "function", "name": "issueTokens", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [{"type": "address", "name": "_owner"}], "constant": true, "type": "function", "name": "balanceOf", "outputs": [{"type": "uint256", "name": "balance"}]}, {"inputs": [], "constant": true, "type": "function", "name": "symbol", "outputs": [{"type": "string", "name": ""}]}, {"inputs": [{"type": "address", "name": "to"}, {"type": "uint256", "name": "value"}], "constant": false, "type": "function", "name": "transfer", "outputs": [{"type": "bool", "name": ""}]}, {"inputs": [{"type": "address", "name": "_owner"}, {"type": "address", "name": "_spender"}], "constant": true, "type": "function", "name": "allowance", "outputs": [{"type": "uint256", "name": "remaining"}]}, {"inputs": [], "type": "constructor"}, {"inputs": [{"indexed": true, "type": "address", "name": "from"}, {"indexed": true, "type": "address", "name": "to"}, {"indexed": false, "type": "uint256", "name": "value"}], "type": "event", "name": "Transfer", "anonymous": false}, {"inputs": [{"indexed": true, "type": "address", "name": "owner"}, {"indexed": true, "type": "address", "name": "spender"}, {"indexed": false, "type": "uint256", "name": "value"}], "type": "event", "name": "Approval", "anonymous": false}]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/* Filters */ | |
angular.module('singularFilters', []) | |
.filter('bigNumber', function() { | |
return function(big_number) { | |
if(big_number) { | |
var string_split = String(big_number.toString(10)).split('.'); | |
var new_string = ""; | |
var places = string_split[0].length - 1; | |
for (var i=places; i>=0; i--) { | |
new_string = string_split[0][i] + new_string; | |
if (i > 0 && (places - i + 1) % 3 == 0) { | |
new_string = ',' + new_string; | |
} | |
} | |
if (string_split.length == 2) { | |
new_string += '.' + string_split[1].substring(0, 2); | |
} | |
return new_string; | |
} | |
return null; | |
}; | |
}) | |
.filter('dateFormat', function() { | |
return function(date_input) { | |
if(date_input != 0) { | |
return moment(date_input).format('YYYY-MM-DD HH:mm:ss'); | |
} | |
return '-'; | |
}; | |
}) | |
.filter('dateFormatFromNow', function() { | |
function filter(date_input) { | |
if(date_input != 0) { | |
return moment(new Date(date_input)).fromNow(); | |
} | |
return '-'; | |
}; | |
filter.$stateful = true; | |
return filter; | |
}) | |
.filter('feeToPercentage', function() { | |
return function(fee) { | |
if (fee) { | |
return fee.dividedBy(1000).toString(10); | |
} | |
return ""; | |
}; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var app = angular.module('crowdfunding', [ | |
'LocalStorageModule', | |
'singularServices', | |
'singularFilters', | |
'ui-notification', | |
'angular-clipboard', | |
'singularTestTools' | |
]); | |
app.controller('StatusCtrl', function($scope, walletService, EthereumService, stateService, Notification, clipboard, $timeout) { | |
$scope.crowdsale_enabled = window.crowdsale_config.enabled; | |
$scope.$watch(function() { | |
return walletService.exists() && ! stateService.isWalletCreating; | |
}, function(newVal) { | |
if (!newVal) { | |
$scope.is_shown = 0; | |
} else { | |
$scope.address = walletService.getAddress(); | |
$scope.is_shown = 1; | |
} | |
}); | |
$scope.$watch(function() { | |
return stateService.blocknumber + stateService.updates; | |
}, function(newVal) { | |
$scope.tokens = walletService.balances.sngls ? walletService.balances.sngls.toFixed(0) : '...'; | |
$scope.eth_balance = walletService.balances.wei ? web3.fromWei(walletService.balances.wei, 'ether').toFixed(4) : '...'; | |
$scope.transactions = getTransactions(); | |
$scope.sngls_price = stateService.snglsPrice; | |
$scope.stage = stateService.stage; | |
if($scope.stage == stateService.stages.CrowdfundingEndedAndGoalReached) { | |
EthereumService.getRevenueShare().then(function(revenue_share_wei) { | |
$scope.revenue_share = web3.fromWei(revenue_share_wei).toNumber(); | |
}); | |
} | |
if($scope.stage == stateService.stages.CrowdfundingEndedAndGoalNotReached || crowdsale_config.show_withdraw_investment) { | |
EthereumService.getInvestmentShare().then(function(investment_wei) { | |
$scope.investment_share = web3.fromWei(investment_wei).toNumber(); | |
}); | |
} | |
}); | |
$scope.isBuyShown = function() { | |
return $scope.is_shown && ($scope.stage == stateService.stages.CrowdfundingGoingAndGoalNotReached || $scope.stage == stateService.stages.CrowdfundingGoingAndGoalReached); | |
}; | |
$scope.isWithdrawRevenueShown = function() { | |
return $scope.is_shown && $scope.stage == stateService.stages.CrowdfundingEndedAndGoalReached; | |
}; | |
function getTransactions() { | |
return _.sortBy(EthereumService.transactions , function(o) { | |
return new Date(o.date).getTime(); | |
}).reverse(); | |
} | |
$scope.show_deposit = 0; | |
$scope.show_withdraw = 0; | |
$scope.show_tx_history = 0; | |
$scope.cancelWalletAction = function() { | |
$scope.show_deposit = 0; | |
$scope.show_withdraw = 0; | |
$scope.show_tx_history = 0; | |
$timeout(function() { | |
$('html, body').animate({ | |
scrollTop: $("#wallet").offset().top | |
}, 400); | |
}); | |
}; | |
$scope.showDeposit = function() { | |
$scope.show_deposit = 1; | |
$scope.show_withdraw = 0; | |
$scope.show_tx_history = 0; | |
$timeout(function() { | |
$('html, body').animate({ | |
scrollTop: $("#wallet-deposit").offset().top | |
}, 400); | |
}); | |
} | |
$scope.showWithdraw = function() { | |
$scope.show_deposit = 0; | |
$scope.show_withdraw = 1; | |
$scope.show_tx_history = 0; | |
$scope.withdraw_amount = null; | |
$timeout(function() { | |
$('html, body').animate({ | |
scrollTop: $("#wallet-withdraw").offset().top | |
}, 400); | |
}); | |
} | |
$scope.showTxHistory = function() { | |
$scope.show_deposit = 0; | |
$scope.show_withdraw = 0; | |
$scope.show_tx_history = 1; | |
$scope.withdraw_amount = null; | |
$scope.transactions = getTransactions(); | |
$timeout(function() { | |
$('html, body').animate({ | |
scrollTop: $("#wallet-txhistory").offset().top | |
}, 400); | |
}); | |
} | |
$scope.copyAddressToClipboard = function() { | |
if (!clipboard.supported) { | |
Notification.error('Sorry, copy to clipboard is not supported on your device'); | |
return false; | |
} | |
clipboard.copyText(walletService.getAddress()); | |
Notification.info('Address copied to clipboard'); | |
}; | |
$scope.openShapeshiftPopup = function($event) { | |
$event.preventDefault(); | |
var link = $event.target.href; | |
window.open(link,'1418115287605','width=700,height=500,toolbar=0,menubar=0,location=0,status=1,scrollbars=1,resizable=0,left=0,top=0'); | |
}; | |
$scope.logout = function() { | |
walletService.destroy(); | |
EthereumService.logout(); | |
loadCrowdFundingPhase1(1); | |
window.location.reload(); | |
}; | |
$scope.withdraw = function() { | |
$scope.withdraw_error = {}; | |
if($scope.withdraw_token == 'ETH') { | |
if(walletService.balances.wei.equals(0)) { | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = "You don't have any ETH in your wallet"; | |
return false; | |
} | |
try { | |
var value = web3.toWei($scope.withdraw_amount); | |
var gas_cost = new BigNumber(web3.eth.gasPrice * 21000); | |
var gas_cost_eth = web3.fromWei(gas_cost); | |
var max_value = web3.fromWei(new BigNumber(walletService.balances.wei).minus(gas_cost)); | |
var total_cost = new BigNumber(value).plus(gas_cost); | |
if(total_cost.greaterThan(walletService.balances.wei)) { | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = 'Not enough funds. Gas cost is: ' + gas_cost_eth + ' ETH; The maximum amount you can withdraw is: ' + max_value + ' ETH'; | |
return false; | |
} | |
} catch(e) { | |
console.log(e); | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = 'Amount must be a valid number'; | |
return false; | |
} | |
if(! web3.isAddress($scope.withdraw_to)) { | |
$scope.withdraw_error.to = true; | |
$scope.withdraw_error.message = 'Invalid Ethereum address'; | |
return false; | |
} | |
$scope.withdrawing = true; | |
stateService.EthereumService.withdraw($scope.withdraw_to, value).then(function(tx_hash) { | |
Notification.info('Your withdrawal transaction was sent, it may take up to 20 seconds. Awaiting confirmation...'); | |
stateService.EthereumService.waitForTransactionReceipt(tx_hash).then(function() { | |
Notification.success('Withdrawal transaction confirmed.'); | |
}); | |
$scope.closeWithdraw(); | |
}).catch(function(err) { | |
Notification.error('Transaction error: ' + err); | |
}).finally(function() { | |
$scope.withdrawing = false; | |
}); | |
} | |
if($scope.withdraw_token == 'SNGLS') { | |
if(walletService.balances.sngls.equals(0)) { | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = "You don't have any SGNLS in your wallet"; | |
return false; | |
} | |
var gas_cost = new BigNumber(web3.eth.gasPrice * stateService.EthereumService.DEFAULT_GAS); | |
var gas_cost_eth = web3.fromWei(gas_cost); | |
if(gas_cost.greaterThan(walletService.balances.wei)) { | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = 'Not enough ETH funds for gas cost. Please deposit at least ' + gas_cost_eth + ' ETH in your account first'; | |
return false; | |
} | |
try { | |
var tokens = $scope.withdraw_amount; | |
var tokens_bn = new BigNumber(tokens); | |
if(tokens_bn.greaterThan(walletService.balances.sngls)) { | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = 'You can transfer a maximum of ' + walletService.balances.sngls + ' SNGLS.'; | |
return false; | |
} | |
} catch(e) { | |
console.log(e); | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = 'Amount must be a valid number'; | |
return false; | |
} | |
if(! tokens_bn.isInteger()) { | |
$scope.withdraw_error.amount = true; | |
$scope.withdraw_error.message = 'Amount must be an integer. SNGLS do not have sub units.'; | |
return false; | |
} | |
if(! web3.isAddress($scope.withdraw_to)) { | |
$scope.withdraw_error.to = true; | |
$scope.withdraw_error.message = 'Invalid Ethereum address'; | |
return false; | |
} | |
$scope.withdrawing = true; | |
stateService.EthereumService.transferSngls($scope.withdraw_to, tokens).then(function(tx_hash) { | |
Notification.info('Your withdrawal transaction was sent, it may take up to 20 seconds. Awaiting confirmation...'); | |
stateService.EthereumService.waitForTransactionReceipt(tx_hash).then(function() { | |
Notification.success('Withdrawal transaction confirmed.'); | |
}); | |
$scope.closeWithdraw(); | |
}).catch(function(err) { | |
Notification.error('Transaction error: ' + err); | |
}).finally(function() { | |
$scope.withdrawing = false; | |
}); | |
} | |
}; | |
var skip_buy_form_recalc = false; | |
$scope.$watch(function() { | |
return $scope.buy_sngls_amount; | |
}, function(newVal, oldValue) { | |
if(skip_buy_form_recalc) { | |
skip_buy_form_recalc = false; | |
return; | |
} | |
if(! newVal) { | |
$scope.buy_sngls_amount = null; | |
$scope.buy_eth_amount = null; | |
$scope.buy_eth_amount_bn = null; | |
return; | |
} | |
try { | |
skip_buy_form_recalc = true; | |
var sngls = new BigNumber($scope.buy_sngls_amount).floor(); | |
$scope.buy_sngls_amount = sngls.toFixed(0); | |
$scope.buy_eth_amount_bn = new BigNumber(web3.fromWei(sngls.times($scope.sngls_price), 'ether')); | |
$scope.buy_eth_amount = $scope.buy_eth_amount_bn.toNumber(); | |
} catch(e) { | |
console.error(e); | |
$scope.buy_sngls_amount = oldValue; | |
} | |
}); | |
$scope.$watch(function() { | |
return $scope.buy_eth_amount; | |
}, function(newVal, oldValue) { | |
if(skip_buy_form_recalc) { | |
skip_buy_form_recalc = false; | |
return; | |
} | |
if(! newVal) { | |
$scope.buy_sngls_amount = null; | |
$scope.buy_eth_amount = null; | |
$scope.buy_eth_amount_bn = null; | |
return; | |
} | |
try { | |
skip_buy_form_recalc = true; | |
$scope.buy_eth_amount_bn = new BigNumber(newVal); | |
$scope.buy_sngls_amount = $scope.buy_eth_amount_bn.div(web3.fromWei($scope.sngls_price)).floor(); | |
} catch(e) { | |
console.error(e); | |
$scope.buy_eth_amount = oldValue; | |
} | |
}); | |
$scope.buySngls = function() { | |
$scope.buy_error = {}; | |
if(walletService.balances.wei.equals(0)) { | |
$scope.buy_error.amount = true; | |
$scope.buy_error.message = "You don't have any ETH in your wallet"; | |
return false; | |
} | |
try { | |
var value = web3.toWei($scope.buy_eth_amount_bn); | |
var gas_cost = new BigNumber(web3.eth.gasPrice * stateService.EthereumService.DEFAULT_GAS); | |
var gas_cost_eth = web3.fromWei(gas_cost); | |
if(gas_cost.greaterThan(walletService.balances.wei)) { | |
$scope.buy_error.amount = true; | |
$scope.buy_error.message = 'Not enough ETH funds for gas cost. Please deposit at least ' + gas_cost_eth + ' ETH in your account first'; | |
return false; | |
} | |
var gas_cost = new BigNumber(web3.eth.gasPrice * stateService.EthereumService.DEFAULT_GAS); | |
var gas_cost_eth = web3.fromWei(gas_cost); | |
var max_value = web3.fromWei(new BigNumber(walletService.balances.wei).minus(gas_cost)); | |
var total_cost = new BigNumber(value).plus(gas_cost); | |
if(total_cost.greaterThan(walletService.balances.wei)) { | |
$scope.buy_error.amount = true; | |
$scope.buy_error.message = 'Not enough funds. Gas cost is: ' + gas_cost_eth + ' ETH; The maximum amount you can buy with is: ' + max_value + ' ETH'; | |
return false; | |
} | |
} catch(e) { | |
console.log(e); | |
$scope.buy_error.amount = true; | |
$scope.buy_error.message = 'Amount must be a valid number'; | |
return false; | |
} | |
if(value <= 0) { | |
$scope.buy_error.amount = true; | |
$scope.buy_error.message = 'SNGLS amount is requiured'; | |
return false; | |
} | |
$scope.buying = true; | |
stateService.EthereumService.buySngls(value).then(function(tx_hash) { | |
Notification.info('Your buy transaction was sent, it may take up to 20 seconds. Awaiting confirmation...'); | |
sendGaEvent('crowdsale', 'buy', 'sngls', $scope.buy_sngls_amount); | |
stateService.EthereumService.waitForTransactionReceipt(tx_hash).then(function() { | |
Notification.success('Buy transaction confirmed.'); | |
$scope.buying = false; | |
$scope.buy_sngls_amount = null; | |
EthereumService.updateStatsWidgets(); | |
}); | |
}).catch(function(err) { | |
Notification.error('Transaction error: ' + err); | |
$scope.buying = false; | |
}).finally(function() { | |
// | |
}); | |
}; | |
$scope.closeWithdraw = function() { | |
$scope.withdraw_amount = null; | |
$scope.withdraw_to = null; | |
$scope.withdraw_error = {}; | |
$scope.cancelWalletAction(); | |
}; | |
$scope.withdrawRevenueShare = function() { | |
$scope.withdraw_revenue = {}; | |
var gas_cost = new BigNumber(web3.eth.gasPrice * stateService.EthereumService.DEFAULT_GAS); | |
var gas_cost_eth = web3.fromWei(gas_cost); | |
if(gas_cost.greaterThan(walletService.balances.wei)) { | |
$scope.withdraw_revenue.message = 'Not enough ETH funds for gas cost. Please deposit at least ' + gas_cost_eth + ' ETH in your account first'; | |
return false; | |
} | |
$scope.withdrawing_revenue_share = true; | |
stateService.EthereumService.withdrawRevenueShare().then(function(tx_hash) { | |
Notification.info('Your withdrawRevenueShare transaction was sent, it may take up to 20 seconds. Awaiting confirmation...'); | |
stateService.EthereumService.waitForTransactionReceipt(tx_hash).then(function() { | |
Notification.success('withdrawRevenueShare transaction confirmed.'); | |
$scope.withdrawing_revenue_share = false; | |
}); | |
}).catch(function(err) { | |
Notification.error('Transaction error: ' + err); | |
$scope.withdrawing_revenue_share = false; | |
}).finally(function() { | |
// | |
}); | |
}; | |
$scope.isWithdrawInvestmentShown = function() { | |
return stateService.stage == stateService.stages.CrowdfundingEndedAndGoalNotReached; | |
}; | |
$scope.withdrawInvestmentShare = function() { | |
$scope.withdraw_investment = {}; | |
var gas_cost = new BigNumber(web3.eth.gasPrice * stateService.EthereumService.DEFAULT_GAS); | |
var gas_cost_eth = web3.fromWei(gas_cost); | |
if(gas_cost.greaterThan(walletService.balances.wei)) { | |
$scope.withdraw_investment.message = 'Not enough ETH funds for gas cost. Please deposit at least ' + gas_cost_eth + ' ETH in your account first'; | |
return false; | |
} | |
$scope.withdrawing_investment_share = true; | |
stateService.EthereumService.withdrawInvestmentShare().then(function(tx_hash) { | |
Notification.info('Your withdrawinvestmentShare transaction was sent, it may take up to 20 seconds. Awaiting confirmation...'); | |
stateService.EthereumService.waitForTransactionReceipt(tx_hash).then(function() { | |
Notification.success('withdrawinvestmentShare transaction confirmed.'); | |
$scope.withdrawing_investment_share = false; | |
}); | |
}).catch(function(err) { | |
Notification.error('Transaction error: ' + err); | |
$scope.withdrawing_investment_share = false; | |
}).finally(function() { | |
// | |
}); | |
}; | |
}); | |
app.controller('LightWalletCtrl', function($scope, walletService, $http, stateService) { | |
$scope.$watch(function() { | |
return walletService.exists() | |
}, function(newVal) { | |
if (newVal) { | |
if (!$scope.is_creating) { | |
loadCrowdFundingPhase2(5); | |
} | |
} else { | |
loadCrowdFundingPhase1(1); | |
} | |
}); | |
$scope.recovery_seed = null; | |
$scope.recovery_seed_form_error = 0; | |
$scope.setRecoveringWallet = function(val) { | |
$scope.recovering_wallet = val; | |
}; | |
$scope.endRecovery = function() { | |
$scope.recovering_wallet = 0; | |
$scope.recovering_wallet_seed = 0; | |
$scope.recovery_seed = null; | |
$scope.recovery_seed_form_error = 0; | |
}; | |
$scope.uploadWallet = function(element) { | |
walletService.upload(element, $scope.endRecovery); | |
angular.element(element).val(null); | |
return walletService; | |
}; | |
$scope.recoverBySeed = function() { | |
$scope.recovery_seed_form_error = 0; | |
if (!lightwallet.keystore.isSeedValid($scope.recovery_seed)) { | |
$scope.recovery_seed_form_error = 1; | |
return false; | |
} | |
loadCrowdFundingStep3($scope.recovery_seed, true); | |
$scope.endRecovery(); | |
$scope.is_creating = 1; | |
stateService.set({ | |
isWalletCreating: true | |
}); | |
}; | |
$scope.setCreatingWallet = function(val) { | |
$scope.creating_wallet = val; | |
$scope.$digest(); | |
}; | |
$scope.sendWalletToEmail = function() { | |
$scope.sending_wallet_to_email = 1; | |
$http.post('/crowdsale/send', { | |
address: walletService.getAddress(), | |
keystore: walletService.keystore.serialize(), | |
}) | |
.success(function(response, status, headers, config) { | |
if (response.success) { | |
$('#cfn-step4-continue').data('allowed', 1).slideDown(); | |
} else { | |
alert('Our mail server seems to be down. Please try to download the wallet instead.'); | |
} | |
}) | |
.error(function(data, status, headers, config) { | |
alert('Our mail server seems to be down. Please try to download the wallet instead.'); | |
}).finally(function() { | |
$scope.sending_wallet_to_email = 0; | |
}); | |
}; | |
window.crowdfunding_LightWalletCtrlScope = $scope; | |
}); | |
app.controller('PasswordPromptCtrl', function($scope, stateService) { | |
$scope.$watch(function() { | |
return stateService.show_password_prompt; | |
}, function(newVal) { | |
if (!newVal) { | |
$scope.is_shown = 0; | |
} else { | |
$scope.is_shown = 1; | |
} | |
}); | |
$scope.unlockWallet = function() { | |
$scope.deriving_key = true; | |
$scope.wallet_password_error = false; | |
if(! $scope.wallet_password) { | |
$scope.deriving_key = false; | |
$scope.wallet_password_error = true; | |
return false; | |
} | |
var keystore = stateService.walletService.keystore; | |
lightwallet.keystore.deriveKeyFromPassword($scope.wallet_password, function(err, pwDerivedKey) { | |
$scope.deriving_key = false; | |
if(! err && keystore.isDerivedKeyCorrect(pwDerivedKey)) { | |
stateService.password_prompt_cb(null, $scope.wallet_password); | |
stateService.password_prompt_cb = null; | |
$scope.wallet_password = null; | |
$scope.wallet_password_error = false; | |
stateService.hidePasswordPrompt(); | |
} else { | |
$scope.wallet_password_error = true; | |
$scope.$digest(); | |
} | |
}); | |
}; | |
$scope.close = function() { | |
stateService.hidePasswordPrompt(); | |
}; | |
}); | |
app.config(function($httpProvider) { | |
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; | |
$httpProvider.defaults.transformRequest = function(data) { | |
if (data === undefined) { | |
return data; | |
} | |
return $.param(data); | |
} | |
}); | |
app.filter('nl2br', function() { | |
return function(msg) { | |
var breakTag = '<br>'; | |
var msg = (msg + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2'); | |
return msg; | |
} | |
}); | |
app.directive('laddaLoading', function($filter, $timeout) { | |
return { | |
scope: true, | |
link: function(scope, element, attrs) { | |
var $element = $(element); | |
scope.$watch(attrs.laddaLoading, function(newVal) { | |
if (newVal) { | |
if (!$element.hasClass('ladda-button')) { | |
$element.addClass('ladda-button'); | |
$element.attr('data-style', 'zoom-in'); | |
} | |
scope.ladda_object = Ladda.create($element.get(0)); | |
scope.ladda_object.start(); | |
} else if (scope.ladda_object) { | |
scope.ladda_object.stop() | |
} | |
}); | |
} | |
}; | |
}); | |
app.directive('focusMe', function($timeout) { | |
return { | |
link: function(scope, element, attrs) { | |
scope.$watch(attrs.focusMe, function(value) { | |
if (value === 1) { | |
$timeout(function() { | |
element[0].focus(); | |
}); | |
} | |
}); | |
} | |
}; | |
}); | |
function loadCrowdFundingStep(step, data) { | |
// Make other steps inactive | |
$('.cfn-step').removeClass('cfn-active-step'); | |
switch (step) { | |
case 1: | |
loadCrowdFundingStep1(); | |
break; | |
case 2: | |
loadCrowdFundingStep2(); | |
break; | |
case 3: | |
loadCrowdFundingStep3(data); | |
break; | |
case 4: | |
loadCrowdFundingStep4(); | |
break; | |
case 5: | |
loadCrowdFundingStep5(); | |
break; | |
case 6: | |
loadCrowdFundingStep6(data); | |
break; | |
default: | |
loadCrowdFundingStep1(); | |
} | |
} | |
function loadCrowdFundingPhase1(step) { | |
var $phase = $('#cfn-phase1'); | |
$('.cfn-phase').removeClass('cfn-active-phase'); | |
$('#cfn-password-form').find('[type=password]').val(''); | |
// Make the phase active | |
$phase.addClass('cfn-active-phase'); | |
// Initiate the step with the first one | |
step = step || 1; | |
// Load the step | |
loadCrowdFundingStep(step); | |
//loadCrowdFundingStep(3, "taste rule grid clog surprise finger world thank someone learn pause dentist"); | |
} | |
function loadCrowdFundingStep1() { | |
crowdfunding_LightWalletCtrlScope.is_creating = 0; | |
var $step1 = $('#cfn-step1'); | |
// Make active | |
$step1.addClass('cfn-active-step'); | |
// We've got two actions: Generate & Open Wallet. Generate should get you to next step | |
$('#cfn-generate-btn').unbind('click').click(function(e) { | |
e.preventDefault(); | |
loadCrowdFundingStep(2); | |
}); | |
} | |
function loadCrowdFundingStep2() { | |
var $step2 = $('#cfn-step2'); | |
var $progressBody = $step2.find('.cfn-progress-body'); | |
var $progressBar = $step2.find('.cfn-progress-fill'); | |
var $progressIndicator = $step2.find('.cfn-progress-indicator'); | |
var entropy_limit = 5000; | |
var seed = null; | |
var percentage = 0; | |
var progress = 0; | |
crowdfunding_LightWalletCtrlScope.is_creating = 1; | |
window.state_service.set({ | |
isWalletCreating: true | |
}, true); | |
// Make active | |
$step2.addClass('cfn-active-step'); | |
// Set the default for the progress bar | |
$progressBar.css('width', percentage + '%'); | |
$progressIndicator.text(percentage); | |
// Generate the seed | |
EntropyCollector.start(); | |
var interval_timer = window.setInterval(function() { | |
if (EntropyCollector.estimatedEntropy > entropy_limit) { | |
$progressBody.addClass('cfn-progress-end'); | |
$progressIndicator.text(100); | |
seed = lightwallet.keystore.generateRandomSeed(String.fromCharCode.apply(null, new Uint16Array(EntropyCollector.buffer))); | |
EntropyCollector.stop(); | |
$(document).unbind('mousemove touchmove'); | |
loadCrowdFundingStep(3, seed); | |
clearInterval(interval_timer); | |
} else { | |
percentage = parseInt(EntropyCollector.estimatedEntropy / entropy_limit * 100); | |
if (percentage > progress) { | |
$progressBar.css('width', percentage + '%'); | |
$progressIndicator.text(percentage); | |
progress = percentage; | |
} | |
} | |
}, 1000 / 30); | |
} | |
function loadCrowdFundingStep3(seed, isRecovery) { | |
var $step1 = $('#cfn-step1'); | |
var $step3 = $('#cfn-step3'); | |
var keystore = null; | |
var address = null; | |
// Make active | |
$step1.removeClass('cfn-active-step'); | |
$step3.addClass('cfn-active-step'); | |
if (isRecovery) { | |
$('#cfn-step3-warning').hide(); | |
} else { | |
$('#cfn-step3-warning').show(); | |
} | |
// Update seed value | |
$('#cfn-seed').text(seed); | |
$('#cfn-password-form').unbind('submit').submit(function(e) { | |
e.preventDefault(); | |
var $form = $(this); | |
var $responseContainer = $('#cfn-password-form-response'); | |
var $passField = $form.find('input[name=password]'); | |
var $passVerifyField = $form.find('input[name=verify-password]'); | |
var password = $passField.val(); | |
var verify_password = $passVerifyField.val(); | |
$responseContainer.hide(); | |
$responseContainer.empty(); | |
$form.find('input').removeClass('input-error'); | |
crowdfunding_LightWalletCtrlScope.setCreatingWallet(1); | |
$.post($form.attr('action'), $form.serialize(), function(response) { | |
if (response.success == 1) { | |
registerWallet(); | |
} else { | |
$(response.errors).each(function(index, item) { | |
$form.find('input[name=' + item.name + ']').addClass('input-error'); | |
$responseContainer.append('<div class="alert-fail">' + item.message[0] + '</div>'); | |
}); | |
$responseContainer.slideDown(); | |
crowdfunding_LightWalletCtrlScope.setCreatingWallet(0); | |
} | |
}, 'json'); | |
function registerWallet() { | |
lightwallet.keystore.deriveKeyFromPassword(password, function(err, pwDerivedKey) { | |
var ks = new lightwallet.keystore(seed, pwDerivedKey); | |
ks.generateNewAddress(pwDerivedKey, 1); | |
var address = "0x" + ks.getAddresses()[0]; | |
$form.find('input').val(''); | |
Wallet.keystore = ks; | |
Wallet.save(); | |
loadCrowdFundingStep(4); | |
crowdfunding_LightWalletCtrlScope.setCreatingWallet(0); | |
sendGaEvent('lightwallet', 'generated'); | |
}); | |
} | |
}); | |
} | |
function loadCrowdFundingStep4() { | |
var $step4 = $('#cfn-step4'); | |
var $sendForm = $('#cfn-send-wallet-form'); | |
// Make active | |
$step4.addClass('cfn-active-step'); | |
$('#cfn-download-wallet-btn').unbind('click').click(function(e) { | |
e.preventDefault(); | |
Wallet.download(); | |
$step4.find('.cfn-continue').data('allowed', 1); | |
$step4.find('.cfn-continue').slideDown(); | |
$sendForm.hide(); | |
// Remove focus from button | |
$(this).blur(); | |
}); | |
$('#cfn-open-send-form-btn').unbind('click').click(function(e) { | |
e.preventDefault(); | |
$sendForm.fadeIn(); | |
// Remove focus from button | |
$(this).blur(); | |
}); | |
$sendForm.unbind('submit').submit(function() { | |
var $button = $sendForm.find('button[type=submit]'); | |
var $email = $sendForm.find('input[name=email]'); | |
var $keystore = $sendForm.find('input[name=keystore]'); | |
var $containerResponse = $('#cfn-send-wallet-form-response'); | |
clearTimeout($sendForm.data('resetTimeout')); | |
if (!$button.hasClass('ladda-button')) { | |
$button.addClass('ladda-button'); | |
$button.attr('data-style', 'zoom-in'); | |
} | |
$button.each(function() { | |
var ladda = Ladda.create(this); | |
ladda.start(); | |
$(this).data('ladda-object', ladda); | |
}); | |
// Adds the keystore to the form | |
$keystore.val(Wallet.keystore.serialize()); | |
var input = $("<input>").attr("type", "hidden").attr('id', 'dynamic-address-input').attr('name', 'address').val(Wallet.getAddress()); | |
$sendForm.find('#dynamic-address-input').remove(); | |
$sendForm.append($(input)); | |
// Resets errors | |
$containerResponse.hide(); | |
$containerResponse.empty(); | |
$email.removeClass('input-error'); | |
$.ajax({ | |
type: "POST", | |
url: $sendForm.attr('action'), | |
jsonp: "c", | |
dataType: "json", | |
data: $sendForm.serialize(), | |
complete: function(answer) { | |
var response = JSON.parse(answer.responseText); | |
var output = ""; | |
$button.each(function() { | |
try { | |
$(this).data('ladda-object').stop(); | |
} catch (e) { | |
} | |
}); | |
var resetTimeout = setTimeout(function() { | |
$button.removeClass('ladda-button'); | |
}, 1000); | |
$sendForm.data('resetTimeout', resetTimeout); | |
if (response.success == 1) { | |
output += '<div>Your message has been successfully sent. Thank you!</div>'; | |
$email.val(''); | |
$keystore.val(''); | |
$sendForm.hide(); | |
$step4.find('.cfn-continue').data('allowed', 1); | |
$step4.find('.cfn-continue').slideDown(); | |
} else { | |
$.each(response.messages, function(i, e) { | |
if (i === 'email') { | |
$email.addClass('input-error'); | |
} | |
output += '<div class="alert-fail">' + e + '</div>'; | |
}); | |
} | |
$containerResponse.append(output); | |
$containerResponse.slideDown(); | |
} | |
}); | |
return false; | |
}); | |
$step4.find('.cfn-continue').unbind('click').click(function(e) { | |
e.preventDefault(); | |
if ($(this).data('allowed') == 1) { | |
window.state_service.set({ | |
isWalletCreating: false | |
}, true); | |
loadCrowdFundingPhase2(5); | |
} | |
}); | |
} | |
function loadCrowdFundingPhase2() | |
{ | |
var $phase = $('#cfn-phase2'); | |
$('.cfn-phase').removeClass('cfn-active-phase'); | |
// Make the phase active | |
$phase.addClass('cfn-active-phase'); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/* Services */ | |
var singularServices = angular.module('singularServices', []); | |
singularServices.factory('stateService', function($rootScope, EthereumService, $timeout, $q) { | |
var state = { | |
isWalletCreating: false, | |
EthereumService: EthereumService, | |
walletService: EthereumService.walletService, | |
updates: 0, | |
blocknumber: 0, | |
sharesIssued: true, | |
snglsPrice: null, | |
stage: null, | |
}; | |
state.stages = { | |
CrowdfundingGoingAndGoalNotReached: 0, | |
CrowdfundingEndedAndGoalNotReached: 1, | |
CrowdfundingGoingAndGoalReached: 2, | |
CrowdfundingEndedAndGoalReached: 3, | |
}; | |
state.set = function(newState, isExternalCall) { | |
state = Object.assign(state, newState); | |
if(isExternalCall) { | |
$rootScope.$digest(); | |
} | |
}; | |
state.showPasswordPrompt = function(cb) { | |
state.show_password_prompt = 1; | |
state.password_prompt_cb = cb; | |
state.last_main_zindex = $('#main').css('z-index'); | |
$('#main').css('z-index', 5000); | |
try { | |
$rootScope.$digest(); | |
} catch(e) {} | |
}; | |
state.hidePasswordPrompt = function() { | |
state.show_password_prompt = 0; | |
if(state.password_prompt_cb && state.EthereumService.transaction_awaiting_pw_deferred) { | |
state.EthereumService.transaction_awaiting_pw_deferred.reject('Wallet password was not provided'); | |
state.EthereumService.transaction_awaiting_pw_deferred = null; | |
} | |
state.password_prompt_cb = null; | |
$timeout(function() { | |
$('#main').css('z-index', state.last_main_zindex); | |
}); | |
}; | |
state.update = function(skip_increment) { | |
$q.all([ | |
EthereumService.updateBalance(), | |
EthereumService.getSnglsPrice(), | |
getCurrentStage(), | |
]).then(function(results) { | |
EthereumService.walletService.balances = EthereumService.balances; | |
EthereumService.walletService.eth_balance = web3.fromWei(EthereumService.balances.wei); | |
state.snglsPrice = results[1]; | |
state.updates++; | |
try { | |
$rootScope.$digest(); | |
} catch(e) {} | |
}); | |
}; | |
function getCurrentStage() { | |
var deferred = $q.defer(); | |
crowdfunding_contract.updateStage.call(function(err, stage) { | |
if (!err) { | |
state.stage = stage.toNumber(); | |
deferred.resolve(stage.toNumber()); | |
} else { | |
console.error(err); | |
} | |
}); | |
return deferred.promise; | |
} | |
state.updateBlocknumber = function() { | |
EthereumService.getBlocknumber().then(function(blocknumber) { | |
if(state.blocknumber != blocknumber) { | |
state.blocknumber = blocknumber; | |
state.update(); | |
EthereumService.checkPendingTransactions(); | |
EthereumService.updateTransactions(); | |
} | |
}).finally(function() { | |
$timeout(function() { | |
state.updateBlocknumber(); | |
}, 5000); | |
}); | |
}; | |
state.updateBlocknumber(); | |
//circular reference | |
EthereumService.stateService = state; | |
window.state_service = state; | |
return state; | |
}); | |
singularServices.service('walletService', function($rootScope, localStorageService, $http) { | |
var wallet = this; | |
wallet.keystore = null; | |
wallet.EthereumService = null; | |
wallet.balances = { | |
sngls: null, | |
wei: null, | |
}; | |
wallet.exists = function() { | |
return localStorageService.get('keystore') ? true : false; | |
}; | |
wallet.save = function() { | |
localStorageService.set('keystore', this.keystore.serialize()); | |
this.connect(wallet.EthereumService); | |
setTimeout(function() { | |
$rootScope.$digest(); | |
}, 1); | |
return this; | |
}; | |
wallet.upload = function(element, cb) { | |
var reader = new FileReader(); | |
reader.onload = function() { | |
var text = reader.result; | |
try { | |
localStorageService.set('keystore', text); | |
if(wallet.restore(wallet.EthereumService)) { | |
if(cb) { cb(); } | |
} | |
$rootScope.$digest(); | |
} catch (err) {} | |
}; | |
reader.readAsText(element.files[0]); | |
}; | |
wallet.download = function() { | |
if (!wallet.exists()) { | |
alert("No wallet exists!"); | |
return; | |
} | |
var blob = new Blob([localStorageService.get('keystore')], { | |
type: "text/plain;charset=utf-8" | |
}); | |
saveAs(blob, "sngular_wallet.txt"); | |
}; | |
wallet.restore = function(EthereumService) { | |
try { | |
this.keystore = lightwallet.keystore.deserialize(localStorageService.get('keystore')); | |
wallet.connect(EthereumService); | |
return true; | |
} catch (e) { | |
console.error(e); | |
this.destroy(); | |
alert('We could not restore your wallet. Make sure you are using a compatible format.'); | |
return false; | |
} | |
}; | |
wallet.getAddress = function() { | |
return "0x" + this.keystore.getAddresses()[0]; | |
}; | |
wallet.destroy = function() { | |
localStorageService.remove('keystore'); | |
this.keystore = null; | |
wallet.balances = { | |
sngls: null, | |
wei: null, | |
}; | |
return this; | |
}; | |
wallet.connect = function(EthereumService) { | |
this.keystore.passwordProvider = function (callback) { | |
wallet.EthereumService.stateService.showPasswordPrompt(callback); | |
}; | |
EthereumService.connectProvider(); | |
if(EthereumService.stateService) { | |
EthereumService.stateService.update(); | |
} | |
}; | |
window.Wallet = this; | |
}); | |
singularServices.factory('EthereumService', ['$interval', '$timeout', '$http', '$rootScope', 'localStorageService', 'walletService', '$q', | |
function($interval, $timeout, $http, $rootScope, localStorageService, walletService, $q) { | |
window.web3 = new Web3(); | |
/* service config */ | |
var BLOCK_TIME = 15; // in seconds | |
var UPDATE_BLOCKCHAIN = BLOCK_TIME * 1000; // every 15 seconds | |
/* default setting values */ | |
var DEFAULT_GAS = 150000; | |
var DEFAULT_ETHEREUM_NODE = window.crowdsale_config.default_node; | |
var DEFAULT_CONTRACT_ADDRESS = window.crowdsale_config.fund_address; | |
var factory = {}; | |
factory.DEFAULT_GAS = DEFAULT_GAS; | |
factory.walletService = walletService; | |
factory.balances = { | |
wei: null, | |
sngls: null, | |
}; | |
factory.transactions = []; | |
/* add and persists transaction in local storage */ | |
function addTransaction(transaction) { | |
factory.transactions.push(transaction); | |
//trigger UI update | |
factory.stateService.updates++; | |
localStorageService.set('transactions', angular.toJson(factory.transactions)); | |
} | |
factory.addTransaction = addTransaction; | |
/* update information about pending transactions */ | |
function updateTransactions() { | |
var pending_transactions = factory.transactions.filter(function(tx) {if(!tx.receipt) return tx}); | |
for (var i=0; i<pending_transactions.length; i++) { | |
web3.eth.getTransactionReceipt(pending_transactions[i].hash, function(err, receipt) { | |
if(!err) { | |
for (var j=0; j<factory.transactions.length; j++) { | |
if(receipt && factory.transactions[j].hash == receipt.transactionHash) { | |
factory.transactions[j].receipt = receipt; | |
localStorageService.set('transactions', angular.toJson(factory.transactions)); | |
} | |
} | |
} | |
else { | |
logError(err); | |
} | |
}); | |
} | |
} | |
factory.updateTransactions = updateTransactions; | |
factory.getEthereumNode = function() { | |
return localStorageService.get('ethereum_node') || DEFAULT_ETHEREUM_NODE; | |
}; | |
factory.setContractAddress = function(contract_address) { | |
if (web3.isAddress(contract_address)) { | |
localStorageService.set('contract_address', angular.toJson(contract_address)); | |
} | |
}; | |
factory.setEthereumNode = function(ethereum_node) { | |
if (angular.isDefined(ethereum_node)) { | |
localStorageService.set('ethereum_node', ethereum_node); | |
} | |
}; | |
factory.resetSettings = function() { | |
localStorageService.set('contract_address', ""); | |
localStorageService.set('ethereum_node', ""); | |
}; | |
factory.getBlocknumber = function() { | |
var deferred = $q.defer(); | |
web3.eth.getBlockNumber(function(err, current_block) { | |
if(!err) { | |
deferred.resolve(current_block); | |
} | |
else { | |
deferred.reject(err); | |
} | |
}); | |
return deferred.promise; | |
} | |
factory.logout = function () { | |
factory.balances = { | |
wei: null, | |
sngls: null, | |
}; | |
factory.transactions = []; | |
factory.shares = {}; | |
localStorageService.set('transactions', ''); | |
}; | |
factory.withdraw = function(receiver_address, value) { | |
var deferred = $q.defer(); | |
web3.eth.sendTransaction({ | |
from: walletService.getAddress(), | |
to: receiver_address, | |
value: value, | |
gas: 21000, | |
gasPrice: web3.eth.gasPrice | |
}, | |
function(err, tx_hash) { | |
if (!err) { | |
addTransaction({ | |
'hash': tx_hash, | |
'subject': 'withdraw', | |
'token': 'ETH', | |
'value': web3.fromWei(value), | |
'receipt': null, | |
'from': walletService.getAddress(), | |
'to': receiver_address, | |
'date': new Date() | |
}); | |
deferred.resolve(tx_hash); | |
} else { | |
deferred.reject(err); | |
console.error(err); | |
} | |
} | |
); | |
factory.transaction_awaiting_pw_deferred = deferred; | |
return deferred.promise; | |
}; | |
/* initializes web3 library and interface contract*/ | |
var CrowdfundingContract = web3.eth.contract(SingularDTVCrowdfunding_abi); | |
window.crowdfunding_contract = CrowdfundingContract.at(crowdsale_config.crowdfunding_address); | |
var FundContract = web3.eth.contract(SingularDTVFund_abi); | |
window.fund_contract = FundContract.at(crowdsale_config.fund_address); | |
var TokenContract = web3.eth.contract(SingularDTVToken_abi); | |
window.token_contract = TokenContract.at(crowdsale_config.token_address); | |
/* connect provider with keystore */ | |
factory.connectProvider = function() { | |
window.provider = new HookedWeb3Provider({ | |
host: factory.getEthereumNode(), | |
transaction_signer: walletService.keystore | |
}); | |
web3.setProvider(provider); | |
is_connected = true; | |
try { | |
factory.transactions = angular.fromJson(localStorageService.get('transactions')) || []; | |
updateTransactions(); | |
} catch(e) { | |
} | |
}; | |
/* update balance info */ | |
factory.updateBalance = function() { | |
var deferred_eth = $q.defer(); | |
var deferred_sngls = $q.defer(); | |
web3.eth.getBalance(walletService.getAddress(), function(err, balance) { | |
if (!err) { | |
factory.balances.wei = balance; | |
deferred_eth.resolve(balance); | |
} else { | |
console.error(err); | |
} | |
}); | |
token_contract.balanceOf.call(walletService.getAddress(), function(err, balance) { | |
if (!err) { | |
factory.balances.sngls = balance; | |
deferred_sngls.resolve(balance) | |
} else { | |
console.error(err); | |
} | |
}); | |
return $q.all([ | |
deferred_eth.promise, | |
deferred_sngls.promise, | |
]); | |
}; | |
factory.transferSngls = function(receiver_address, value) { | |
var deferred = $q.defer(); | |
token_contract.transfer.sendTransaction( | |
receiver_address, | |
value, | |
{from: walletService.getAddress(), value: 0, gas: DEFAULT_GAS, gasPrice: web3.eth.gasPrice}, | |
function (err, tx_hash) { | |
if(!err) { | |
addTransaction({ | |
'hash': tx_hash, | |
'subject': 'withdraw', | |
'token': 'SNGLS', | |
'value': value, | |
'receipt': null, | |
'from': walletService.getAddress(), | |
'to': receiver_address, | |
'date': new Date() | |
}); | |
deferred.resolve(tx_hash); | |
} | |
else { | |
deferred.reject(err); | |
console.error(err); | |
} | |
} | |
); | |
factory.transaction_awaiting_pw_deferred = deferred; | |
return deferred.promise; | |
}; | |
factory.buySngls = function(value) { | |
var deferred = $q.defer(); | |
var value_bn = new BigNumber(value); | |
var sngls_price = factory.stateService.snglsPrice; | |
var sngls = value_bn.dividedBy(sngls_price).floor(); | |
crowdfunding_contract.fund.sendTransaction( | |
{from: walletService.getAddress(), value: value, gas: DEFAULT_GAS, gasPrice: web3.eth.gasPrice}, | |
function (err, tx_hash) { | |
if(!err) { | |
addTransaction({ | |
'hash': tx_hash, | |
'subject': 'buy', | |
'token': 'SNGLS', | |
'value': sngls.toFixed(0), | |
'receipt': null, | |
'from': walletService.getAddress(), | |
'to': crowdsale_config.crowdfunding_address, | |
'date': new Date() | |
}); | |
deferred.resolve(tx_hash); | |
} | |
else { | |
deferred.reject(err); | |
console.error(err); | |
} | |
} | |
); | |
factory.transaction_awaiting_pw_deferred = deferred; | |
return deferred.promise; | |
}; | |
factory.depositRevenue = function(value) { | |
var deferred = $q.defer(); | |
fund_contract.depositRevenue.sendTransaction( | |
{from: walletService.getAddress(), value: value, gas: DEFAULT_GAS, gasPrice: web3.eth.gasPrice}, | |
function (err, tx_hash) { | |
if(!err) { | |
addTransaction({ | |
'hash': tx_hash, | |
'subject': 'addRevenue', | |
'token': 'ETH', | |
'value': web3.fromWei(value), | |
'receipt': null, | |
'from': walletService.getAddress(), | |
'to': crowdsale_config.fund_address, | |
'date': new Date() | |
}); | |
deferred.resolve(tx_hash); | |
} | |
else { | |
deferred.reject(err); | |
console.error(err); | |
} | |
} | |
); | |
factory.transaction_awaiting_pw_deferred = deferred; | |
return deferred.promise; | |
}; | |
factory.withdrawForWorkshop = function() { | |
var deferred = $q.defer(); | |
crowdfunding_contract.withdrawForWorkshop.sendTransaction( | |
{from: walletService.getAddress(), value: 0, gas: DEFAULT_GAS, gasPrice: web3.eth.gasPrice}, | |
function (err, tx_hash) { | |
if(!err) { | |
addTransaction({ | |
'hash': tx_hash, | |
'subject': 'withdrawForWorkshop', | |
'token': 'ETH', | |
'value': 0, | |
'receipt': null, | |
'from': walletService.getAddress(), | |
'to': crowdsale_config.crowdfunding_address, | |
'date': new Date() | |
}); | |
deferred.resolve(tx_hash); | |
} | |
else { | |
deferred.reject(err); | |
console.error(err); | |
} | |
} | |
); | |
factory.transaction_awaiting_pw_deferred = deferred; | |
return deferred.promise; | |
}; | |
factory.pending_transactions = {}; | |
factory.waitForTransactionReceipt = function(tx_hash) { | |
var deferred = $q.defer(); | |
factory.pending_transactions[tx_hash] = { | |
callback: deferred.resolve, | |
}; | |
return deferred.promise; | |
}; | |
factory.checkPendingTransactions = function() { | |
for(var tx_hash in factory.pending_transactions) { | |
web3.eth.getTransactionReceipt(tx_hash, function(err, receipt) { | |
if(!err && receipt) { | |
for (var j=0; j<factory.transactions.length; j++) { | |
if(receipt && factory.transactions[j].hash == receipt.transactionHash) { | |
factory.transactions[j].receipt = receipt; | |
localStorageService.set('transactions', angular.toJson(factory.transactions)); | |
} | |
} | |
factory.pending_transactions[tx_hash].callback(); | |
delete factory.pending_transactions[tx_hash]; | |
} | |
}); | |
} | |
}; | |
factory.getSnglsPrice = function() { | |
var deferred = $q.defer(); | |
crowdfunding_contract.valuePerShare.call(function(err, wei_per_share) { | |
if (!err) { | |
deferred.resolve(wei_per_share) | |
} else { | |
console.error(err); | |
} | |
}); | |
return deferred.promise; | |
}; | |
factory.getCrowdfundBalance = function() { | |
var deferred = $q.defer(); | |
crowdfunding_contract.fundBalance.call(function(err, total_wei_balance) { | |
if (!err) { | |
deferred.resolve(total_wei_balance); | |
} else { | |
console.error(err); | |
} | |
}); | |
return deferred.promise; | |
}; | |
factory.getTotalSupply = function() { | |
var deferred = $q.defer(); | |
token_contract.totalSupply.call(function(err, totalSupply) { | |
if (!err) { | |
deferred.resolve(totalSupply); | |
} else { | |
console.error(err); | |
} | |
}); | |
return deferred.promise; | |
}; | |
factory.getRevenueShare = function() { | |
var deferred = $q.defer(); | |
fund_contract.withdrawRevenue.call( | |
{from: walletService.getAddress()}, | |
function(err, revenue_share) { | |
if (!err) { | |
deferred.resolve(revenue_share); | |
} else { | |
console.error(err); | |
} | |
} | |
); | |
return deferred.promise; | |
}; | |
factory.withdrawRevenueShare = function() { | |
var deferred = $q.defer(); | |
fund_contract.withdrawRevenue.sendTransaction( | |
walletService.getAddress(), | |
{from: walletService.getAddress(), value: 0, gas: DEFAULT_GAS, gasPrice: web3.eth.gasPrice}, | |
function (err, tx_hash) { | |
if(!err) { | |
addTransaction({ | |
'hash': tx_hash, | |
'subject': 'withdrawRevenueShare', | |
'token': 'ETH', | |
'value': 0, | |
'receipt': null, | |
'from': walletService.getAddress(), | |
'to': crowdsale_config.fund_address, | |
'date': new Date() | |
}); | |
deferred.resolve(tx_hash); | |
} | |
else { | |
deferred.reject(err); | |
console.error(err); | |
} | |
} | |
); | |
factory.transaction_awaiting_pw_deferred = deferred; | |
return deferred.promise; | |
}; | |
factory.getInvestmentShare = function() { | |
var deferred = $q.defer(); | |
crowdfunding_contract.investments.call(walletService.getAddress(), function(err, investment_share) { | |
if (!err) { | |
deferred.resolve(investment_share); | |
} else { | |
console.error(err); | |
} | |
}); | |
return deferred.promise; | |
}; | |
factory.withdrawInvestmentShare = function() { | |
var deferred = $q.defer(); | |
crowdfunding_contract.withdrawFunding.sendTransaction( | |
{from: walletService.getAddress(), value: 0, gas: DEFAULT_GAS, gasPrice: web3.eth.gasPrice}, | |
function (err, tx_hash) { | |
if(!err) { | |
addTransaction({ | |
'hash': tx_hash, | |
'subject': 'withdrawFunding', | |
'token': 'ETH', | |
'value': 0, | |
'receipt': null, | |
'from': walletService.getAddress(), | |
'to': crowdsale_config.crowdfunding_address, | |
'date': new Date() | |
}); | |
deferred.resolve(tx_hash); | |
} | |
else { | |
deferred.reject(err); | |
console.error(err); | |
} | |
} | |
); | |
factory.transaction_awaiting_pw_deferred = deferred; | |
return deferred.promise; | |
}; | |
factory.updateStatsWidgets = function() { | |
$q.all([ | |
factory.getTotalSupply(), | |
factory.getCrowdfundBalance(), | |
]).then(function(results) { | |
updateState(results[0].toFixed(0), web3.fromWei(results[1]).toFixed(1)); | |
}); | |
}; | |
if (walletService.exists()) { | |
walletService.restore(factory); | |
} | |
walletService.EthereumService = factory; | |
window.service = factory; | |
return factory; | |
} | |
]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment