Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 15 additions & 18 deletions examples/gno.land/p/demo/tokens/grc20/token.gno
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,17 @@ func (tok Token) RenderHome() string {

// SpendAllowance decreases the allowance of the specified owner and spender.
func (led *PrivateLedger) SpendAllowance(owner, spender address, amount int64) error {
if !owner.IsValid() {
return ErrInvalidAddress
}
if !spender.IsValid() {
if !owner.IsValid() || !spender.IsValid() {
return ErrInvalidAddress
}

if amount < 0 {
return ErrInvalidAmount
}
// do nothing
if amount == 0 {
return nil
}

currentAllowance := led.allowance(owner, spender)
if currentAllowance < amount {
Expand Down Expand Up @@ -162,30 +164,25 @@ func (led *PrivateLedger) TransferFrom(owner, spender, to address, amount int64)
if amount < 0 {
return ErrInvalidAmount
}

if !owner.IsValid() || !to.IsValid() {
return ErrInvalidAddress
}

if led.balanceOf(owner) < amount {
return ErrInsufficientBalance
}

// allowance must be sufficient
currentAllowance := led.allowance(owner, spender)
if currentAllowance < amount {
return ErrInsufficientAllowance
// The check above guarantees that Transfer will succeed, ensuring
// atomicity for the subsequent operations.
if err := led.SpendAllowance(owner, spender, amount); err != nil {
return err
}

if err := led.Transfer(owner, to, amount); err != nil {
return err
}

// decrease the allowance only when transfer is successful
key := allowanceKey(owner, spender)
newAllowance := overflow.Sub64p(currentAllowance, amount)

if newAllowance == 0 {
led.allowances.Remove(key)
} else {
led.allowances.Set(key, newAllowance)
}

return nil
}

Expand Down
10 changes: 10 additions & 0 deletions examples/gno.land/p/demo/tokens/grc20/token_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func TestTransferFromAtomicity(t *testing.T) {
spender = testutils.TestAddress("spender")

invalidRecipient = address("")
recipient = testutils.TestAddress("to")
)

token, admin := NewToken("Test", "TEST", 6)
Expand All @@ -121,6 +122,15 @@ func TestTransferFromAtomicity(t *testing.T) {
remainingAllowance := token.Allowance(owner, spender)
uassert.Equal(t, remainingAllowance, initialAllowance,
"allowance should not be reduced when transfer fails")

// transfer all tokens
admin.Transfer(owner, recipient, 100)
remainingBalance := token.BalanceOf(owner)
uassert.Equal(t, remainingBalance, int64(0),
"balance should be zero")

err = admin.TransferFrom(owner, spender, recipient, transferAmount)
uassert.Error(t, err, "transfer should fail due to insufficient balance")
}

func TestMintUntilOverflow(t *testing.T) {
Expand Down
Loading