-
Notifications
You must be signed in to change notification settings - Fork 27
/
builtinFunctionsMock.go
104 lines (89 loc) · 3.29 KB
/
builtinFunctionsMock.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
package worldmock
import (
"encoding/hex"
"errors"
"fmt"
"math/big"
"github.com/ElrondNetwork/elrond-go/core/vmcommon"
vmi "github.com/ElrondNetwork/elrond-go/core/vmcommon"
)
// BuiltInFunctionESDTTransfer is the key for the elrond standard digital token transfer built-in function
const BuiltInFunctionESDTTransfer = "ESDTTransfer"
func getBuiltinFunctionNames() vmcommon.FunctionNames {
builtinFunctionNames := make(vmcommon.FunctionNames)
var empty struct{}
builtinFunctionNames[BuiltInFunctionESDTTransfer] = empty
return builtinFunctionNames
}
func (b *MockWorld) processBuiltInFunction(input *vmcommon.ContractCallInput) (*vmi.VMOutput, error) {
if input.Function == BuiltInFunctionESDTTransfer {
output, err := b.runESDTTransferCall(input)
return output, err
}
return nil, fmt.Errorf("function %s is not provided by the mock as a builtin function", input.Function)
}
// StartTransferESDT updates ESDT balance deltas, without changing the actual balances.
// The deltas need to be committed afterwards.
func (b *MockWorld) StartTransferESDT(from, to []byte, tokenName string, amount *big.Int) (bool, error) {
sender := b.AcctMap.GetAccount(from)
senderESDT := sender.ESDTData[tokenName]
if senderESDT == nil {
return false, nil
}
balancePlusDelta := big.NewInt(0).Add(senderESDT.Balance, senderESDT.BalanceDelta)
if amount.Cmp(balancePlusDelta) > 0 {
return false, nil
}
senderESDT.BalanceDelta = senderESDT.BalanceDelta.Sub(senderESDT.BalanceDelta, amount)
recipient := b.AcctMap.GetAccount(to)
if recipient == nil {
return true, fmt.Errorf("Tx recipient (address: %s) does not exist", hex.EncodeToString(to))
}
recipientESDT := recipient.ESDTData[tokenName]
if recipientESDT == nil {
recipientESDT = &ESDTData{
Balance: big.NewInt(0),
BalanceDelta: big.NewInt(0),
Frozen: false,
}
recipient.ESDTData[tokenName] = recipientESDT
}
recipientESDT.BalanceDelta = recipientESDT.BalanceDelta.Add(recipientESDT.BalanceDelta, amount)
return true, nil
}
func (b *MockWorld) runESDTTransferCall(input *vmcommon.ContractCallInput) (*vmi.VMOutput, error) {
if len(input.Arguments) != 2 {
return nil, errors.New("ESDTTransfer expects 2 arguments")
}
tokenName := string(input.Arguments[0])
amount := big.NewInt(0).SetBytes(input.Arguments[1])
enoughFunds, err := b.StartTransferESDT(input.CallerAddr, input.RecipientAddr, tokenName, amount)
if err != nil {
return nil, err
}
if !enoughFunds {
// TODO: figure out what the actual error message is
return &vmcommon.VMOutput{
ReturnData: make([][]byte, 0),
ReturnCode: vmcommon.OutOfFunds,
ReturnMessage: fmt.Sprintf("Sender does not hold enough ESDT token %s", tokenName),
GasRemaining: 0,
GasRefund: big.NewInt(0),
OutputAccounts: make(map[string]*vmcommon.OutputAccount),
DeletedAccounts: make([][]byte, 0),
TouchedAccounts: make([][]byte, 0),
Logs: make([]*vmcommon.LogEntry, 0),
}, nil
}
return &vmcommon.VMOutput{
ReturnData: make([][]byte, 0),
ReturnCode: vmcommon.Ok,
ReturnMessage: "",
GasRemaining: 0,
GasRefund: big.NewInt(0),
OutputAccounts: make(map[string]*vmcommon.OutputAccount),
DeletedAccounts: make([][]byte, 0),
TouchedAccounts: make([][]byte, 0),
Logs: make([]*vmcommon.LogEntry, 0),
}, nil
}