-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7a014d7
commit 07b7aa3
Showing
776 changed files
with
91,333 additions
and
120,153 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
|
||
# Change Log | ||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog](http://keepachangelog.com/) | ||
and this project adheres to [Semantic Versioning](http://semver.org/). | ||
|
||
## v2.0.0-alpha | ||
|
||
### changed | ||
- Rebranded payman into tzpay | ||
- project structure | ||
- added tests | ||
- uses go-tezos v2.5.2-alpha | ||
- forges operations locally | ||
- uses enviroment variables for configuration | ||
- docker image | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
FROM golang:latest | ||
|
||
# Set the Current Working Directory inside the container | ||
WORKDIR $GOPATH/src/github.com/goat-systems/tzpay | ||
|
||
# Copy everything from the current directory to the PWD (Present Working Directory) inside the container | ||
COPY . . | ||
|
||
# Download all the dependencies | ||
RUN go get -d -v ./... | ||
|
||
# Install the package | ||
RUN go install -v ./... |
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
This file was deleted.
Oops, something went wrong.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
package baker | ||
|
||
import ( | ||
"context" | ||
"math/big" | ||
"unicode" | ||
|
||
gotezos "github.com/goat-systems/go-tezos/v2" | ||
"github.com/goat-systems/tzpay/v2/cli/internal/enviroment" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// DelegationEarning - | ||
type DelegationEarning struct { | ||
Delegation string | ||
Fee *big.Int | ||
GrossRewards *big.Int | ||
NetRewards *big.Int | ||
Share float64 | ||
} | ||
|
||
// Baker is a tezos baker that can get payouts and execute them. | ||
type Baker struct { | ||
gt gotezos.IFace | ||
} | ||
|
||
type processDelegationsInput struct { | ||
delegations *[]string | ||
stakingBalance *big.Int | ||
frozenBalanceRewards *gotezos.FrozenBalance | ||
blockHash string | ||
} | ||
|
||
type processDelegationsOutput struct { | ||
delegationEarning DelegationEarning | ||
err error | ||
} | ||
|
||
type processDelegationInput struct { | ||
delegation string | ||
stakingBalance *big.Int | ||
frozenBalanceRewards *gotezos.FrozenBalance | ||
blockHash string | ||
} | ||
|
||
// Payout contains all needed information for a payout | ||
type Payout struct { | ||
DelegationEarnings DelegationEarnings `json:"delegaions"` | ||
Cycle int `json:"cycle"` | ||
FrozenBalance *big.Int `json:"rewards"` | ||
StakingBalance *big.Int `json:"staking_balance"` | ||
Delegate string `json:"delegate"` | ||
} | ||
|
||
// DelegationEarnings contains list of DelegationEarning and implements sort. | ||
type DelegationEarnings []DelegationEarning | ||
|
||
func (d DelegationEarnings) Len() int { return len(d) } | ||
func (d DelegationEarnings) Swap(i, j int) { | ||
d[i], d[j] = d[j], d[i] | ||
} | ||
|
||
func (d DelegationEarnings) Less(i, j int) bool { | ||
iRunes := []rune(d[i].Delegation) | ||
jRunes := []rune(d[j].Delegation) | ||
|
||
max := len(iRunes) | ||
if max > len(jRunes) { | ||
max = len(jRunes) | ||
} | ||
|
||
for idx := 0; idx < max; idx++ { | ||
ir := iRunes[idx] | ||
jr := jRunes[idx] | ||
|
||
lir := unicode.ToLower(ir) | ||
ljr := unicode.ToLower(jr) | ||
|
||
if lir != ljr { | ||
return lir < ljr | ||
} | ||
|
||
if ir != jr { | ||
return ir < jr | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
// NewBaker returns a pointer to a new Baker | ||
func NewBaker(gt gotezos.IFace) *Baker { | ||
return &Baker{gt: gt} | ||
} | ||
|
||
// Payouts returns all payouts for a cycle | ||
func (b *Baker) Payouts(ctx context.Context, cycle int) (*Payout, error) { | ||
params := enviroment.GetEnviromentFromContext(ctx) | ||
frozenBalanceRewards, err := b.gt.FrozenBalance(cycle, params.Delegate) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle) | ||
} | ||
|
||
delegations, err := b.gt.DelegatedContractsAtCycle(cycle, params.Delegate) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle) | ||
} | ||
|
||
networkCycle, err := b.gt.Cycle(cycle) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle) | ||
} | ||
|
||
stakingBalance, err := b.gt.StakingBalance(networkCycle.BlockHash, params.Delegate) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to get delegation earnings for cycle %d", cycle) | ||
} | ||
|
||
out := b.proccessDelegations(ctx, &processDelegationsInput{ | ||
delegations: delegations, | ||
stakingBalance: stakingBalance, | ||
frozenBalanceRewards: frozenBalanceRewards, | ||
blockHash: networkCycle.BlockHash, | ||
}) | ||
|
||
payouts := Payout{ | ||
Delegate: params.Delegate, | ||
StakingBalance: stakingBalance, | ||
Cycle: cycle, | ||
FrozenBalance: frozenBalanceRewards.Rewards.Big, | ||
} | ||
for _, delegation := range out { | ||
if delegation.err != nil { | ||
err = errors.Wrapf(delegation.err, "failed to get payout for delegation %s", delegation.delegationEarning.Delegation) | ||
} else { | ||
payouts.DelegationEarnings = append(payouts.DelegationEarnings, delegation.delegationEarning) | ||
} | ||
} | ||
|
||
return &payouts, err | ||
} | ||
|
||
func (b *Baker) proccessDelegations(ctx context.Context, input *processDelegationsInput) []processDelegationsOutput { | ||
numJobs := len(*input.delegations) | ||
jobs := make(chan processDelegationInput, numJobs) | ||
results := make(chan processDelegationsOutput, numJobs) | ||
|
||
for i := 0; i < 50; i++ { | ||
go b.proccessDelegationWorker(ctx, jobs, results) | ||
} | ||
|
||
for _, pd := range *input.delegations { | ||
jobs <- processDelegationInput{ | ||
delegation: pd, | ||
stakingBalance: input.stakingBalance, | ||
frozenBalanceRewards: input.frozenBalanceRewards, | ||
blockHash: input.blockHash, | ||
} | ||
} | ||
close(jobs) | ||
|
||
var out []processDelegationsOutput | ||
for i := 1; i <= numJobs; i++ { | ||
out = append(out, <-results) | ||
} | ||
close(results) | ||
|
||
return out | ||
} | ||
|
||
func (b *Baker) proccessDelegationWorker(ctx context.Context, jobs <-chan processDelegationInput, results chan<- processDelegationsOutput) { | ||
for j := range jobs { | ||
d, err := b.processDelegation(ctx, &j) | ||
if err != nil { | ||
results <- processDelegationsOutput{ | ||
err: err, | ||
} | ||
} else { | ||
results <- processDelegationsOutput{ | ||
delegationEarning: *d, | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (b *Baker) processDelegation(ctx context.Context, input *processDelegationInput) (*DelegationEarning, error) { | ||
params := enviroment.GetEnviromentFromContext(ctx) | ||
delegationEarning := &DelegationEarning{Delegation: input.delegation} | ||
balance, err := b.gt.Balance(input.blockHash, input.delegation) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to process delegation earnings for delegation %s", input.delegation) | ||
} | ||
|
||
delegationEarning.Share = float64(balance.Int64()) / float64(input.stakingBalance.Int64()) | ||
grossRewardsFloat := delegationEarning.Share * float64(input.frozenBalanceRewards.Rewards.Big.Int64()) | ||
feeFloat := grossRewardsFloat * params.BakersFee | ||
|
||
delegationEarning.GrossRewards = big.NewInt(int64(grossRewardsFloat)) | ||
delegationEarning.Fee = big.NewInt(int64(feeFloat)) | ||
delegationEarning.NetRewards = big.NewInt(0).Sub(delegationEarning.GrossRewards, delegationEarning.Fee) | ||
|
||
return delegationEarning, nil | ||
} | ||
|
||
// ForgePayout converts Payout into operation contents and forges them locally | ||
func (b *Baker) ForgePayout(ctx context.Context, payout Payout) (string, error) { | ||
base := enviroment.GetEnviromentFromContext(ctx) | ||
head, err := b.gt.Head() | ||
if err != nil { | ||
return "", errors.Wrap(err, "failed to forge payout") | ||
} | ||
|
||
counter, err := b.gt.Counter(head.Hash, base.Wallet.Address) | ||
if err != nil { | ||
return "", errors.Wrap(err, "failed to forge payout") | ||
} | ||
|
||
transactions := b.constructPayoutContents(ctx, *counter, payout) | ||
|
||
forge, err := gotezos.ForgeTransactionOperation(head.Hash, transactions...) | ||
if err != nil { | ||
return "", errors.Wrap(err, "failed to forge payout") | ||
} | ||
|
||
return *forge, nil | ||
} | ||
|
||
func (b *Baker) constructPayoutContents(ctx context.Context, counter int, payout Payout) []gotezos.ForgeTransactionOperationInput { | ||
base := enviroment.GetEnviromentFromContext(ctx) | ||
var contents []gotezos.ForgeTransactionOperationInput | ||
for _, delegation := range payout.DelegationEarnings { | ||
counter++ | ||
if delegation.NetRewards.Int64() >= int64(base.MinimumPayment) { | ||
contents = append(contents, gotezos.ForgeTransactionOperationInput{ | ||
Source: base.Wallet.Address, | ||
Destination: delegation.Delegation, | ||
Amount: gotezos.Int{Big: delegation.NetRewards}, | ||
Fee: gotezos.Int{Big: big.NewInt(int64(base.NetworkFee))}, //TODO: expose NewInt function in GoTezos | ||
GasLimit: gotezos.Int{Big: big.NewInt(int64(base.GasLimit))}, | ||
Counter: counter, | ||
StorageLimit: gotezos.Int{Big: big.NewInt(int64(0))}, | ||
}) | ||
} | ||
} | ||
|
||
return contents | ||
} |
Oops, something went wrong.