-
Notifications
You must be signed in to change notification settings - Fork 119
/
executors.go
106 lines (98 loc) · 5.2 KB
/
executors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package keeper
import (
"fmt"
"github.com/Sifchain/sifnode/x/dispensation/types"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/pkg/errors"
)
//CreateAndDistributeDrops creates new drop Records . These records are then used to facilitate distribution
// Each Recipient and DropName generate a unique Record
func (k Keeper) CreateDrops(ctx sdk.Context, output []banktypes.Output, name string, distributionType types.DistributionType, authorizedRunner string) error {
for _, receiver := range output {
distributionRecord := types.NewDistributionRecord(types.DistributionStatus_DISTRIBUTION_STATUS_PENDING, distributionType, name, receiver.Address, receiver.Coins, ctx.BlockHeight(), -1, authorizedRunner)
if k.ExistsDistributionRecord(ctx, name, receiver.Address, types.DistributionStatus_DISTRIBUTION_STATUS_PENDING, distributionRecord.DistributionType) {
oldRecord, err := k.GetDistributionRecord(ctx, name, receiver.Address, types.DistributionStatus_DISTRIBUTION_STATUS_PENDING, distributionRecord.DistributionType)
if err != nil {
return errors.Wrapf(types.ErrDistribution, "failed appending record for : %s", distributionRecord.RecipientAddress)
}
distributionRecord = distributionRecord.Add(*oldRecord)
}
err := k.SetDistributionRecord(ctx, distributionRecord)
if err != nil {
return errors.Wrapf(types.ErrFailedOutputs, "error setting distibution record : %s", distributionRecord.String())
}
}
return nil
}
// DistributeDrops is called at the beginning of every block .
// It checks if any pending records are present , if there are it completes the top 'distributionCount' items
func (k Keeper) DistributeDrops(ctx sdk.Context,
height int64,
distributionName string,
authorizedRunner string,
distributionType types.DistributionType,
distributionCount int64) (*types.DistributionRecords, error) {
pendingRecords := k.GetLimitedRecordsForRunner(ctx, distributionName, authorizedRunner, distributionType, types.DistributionStatus_DISTRIBUTION_STATUS_PENDING, distributionCount)
for _, record := range pendingRecords.DistributionRecords {
recipientAddress, err := sdk.AccAddressFromBech32(record.RecipientAddress)
if err != nil {
err := errors.Wrapf(err, "Invalid address for distribute : %s", record.RecipientAddress)
ctx.Logger().Error(err.Error())
continue
}
err = k.GetBankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipientAddress, record.Coins)
if err != nil {
err := errors.Wrapf(types.ErrFailedOutputs, "for address : %s", record.RecipientAddress)
ctx.Logger().Error(err.Error())
err = k.ChangeRecordStatus(ctx, *record, height, types.DistributionStatus_DISTRIBUTION_STATUS_FAILED)
if err != nil {
panic(fmt.Sprintf("Unable to set Distribution Records to Failed : %s", record.String()))
}
continue
}
err = k.ChangeRecordStatus(ctx, *record, height, types.DistributionStatus_DISTRIBUTION_STATUS_COMPLETED)
if err != nil {
err := errors.Wrapf(types.ErrFailedOutputs, "error setting distibution record : %s", record.String())
ctx.Logger().Error(err.Error())
// If the SetDistributionRecord returns error , that would mean the required amount was transferred to the user , but the record was not set to completed .
// In this case we try to take the funds back from the user , and attempt the withdrawal later .
err = k.GetBankKeeper().SendCoinsFromAccountToModule(ctx, recipientAddress, types.ModuleName, record.Coins)
if err != nil {
panic(fmt.Sprintf("Unable to set Distribution Records to completed : %s", record.String()))
}
continue
}
// Use record details to delete associated claim
if record.DoesTypeSupportClaim() {
k.DeleteClaim(ctx, record.RecipientAddress, record.DistributionType)
}
ctx.Logger().Info(fmt.Sprintf("Distributed to : %s | At height : %d | Amount :%s \n", record.RecipientAddress, height, record.Coins.String()))
}
return pendingRecords, nil
}
// AccumulateDrops collects funds from a senders account and transfers it to the Dispensation module account
func (k Keeper) AccumulateDrops(ctx sdk.Context, addr string, amount sdk.Coins) error {
address, err := sdk.AccAddressFromBech32(addr)
if err != nil {
return errors.Wrapf(err, "Invalid address for distribute : %s", addr)
}
err = k.GetBankKeeper().SendCoinsFromAccountToModule(ctx, address, types.ModuleName, amount)
if err != nil {
return errors.Wrapf(types.ErrFailedInputs, "for address : %s", addr)
}
return nil
}
// Verify if the distribution is correct
// The verification is the for distributionName + distributionType
func (k Keeper) VerifyAndSetDistribution(ctx sdk.Context, distributionName string, distributionType types.DistributionType, authorizedRunner string) error {
if k.ExistsDistribution(ctx, distributionName, distributionType, authorizedRunner) {
return errors.Wrapf(types.ErrDistribution, "airdrop with same name already exists : %s ", distributionName)
}
// Create distribution only if a distribution with the same name does not exist
err := k.SetDistribution(ctx, types.NewDistribution(distributionType, distributionName, authorizedRunner))
if err != nil {
return errors.Wrapf(types.ErrDistribution, "unable to set airdrop : %s ", distributionName)
}
return nil
}