Skip to content

Commit

Permalink
Support ERC-20 tokens (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
guidanoli committed Apr 25, 2024
1 parent af587ce commit 1c31e1f
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 36 deletions.
28 changes: 16 additions & 12 deletions contract/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (c *BugLessContract) Advance(
Description: inputPayload.Description,
Started: currTime,
Deadline: inputPayload.Deadline,
Token: inputPayload.Token,
InputIndex: metadata.InputIndex,
Sponsorships: nil,
Exploit: nil,
Expand Down Expand Up @@ -100,21 +101,24 @@ func (c *BugLessContract) Advance(
return fmt.Errorf("can't add sponsorship after deadline")
}

var etherDepositSender common.Address
var etherDepositValue *uint256.Int
var erc20DepositSender common.Address
var erc20DepositValue *uint256.Int

switch deposit := deposit.(type) {
case *rollmelette.EtherDeposit:
etherDepositSender = deposit.Sender
etherDepositValue, _ = uint256.FromBig(deposit.Value)
case *rollmelette.ERC20Deposit:
if deposit.Token != bounty.Token {
return fmt.Errorf("token mismatch: %v (obtained) != %v (expected)", deposit.Token, bounty.Token)
}
erc20DepositSender = deposit.Sender
erc20DepositValue, _ = uint256.FromBig(deposit.Amount)
default:
return fmt.Errorf("unsupported deposit: %T", deposit)
}

sponsorship := bounty.GetSponsorship(etherDepositSender)
sponsorship := bounty.GetSponsorship(erc20DepositSender)
if sponsorship != nil {
// Add to existing sponsorship
newValue := new(uint256.Int).Add(sponsorship.Value, etherDepositValue)
newValue := new(uint256.Int).Add(sponsorship.Value, erc20DepositValue)
sponsorship.Value = newValue
// Update profile
sponsorship.Sponsor.Name = inputPayload.Name
Expand All @@ -123,11 +127,11 @@ func (c *BugLessContract) Advance(
// Create new sponsorship
sponsorship := &shared.Sponsorship{
Sponsor: shared.Profile{
Address: etherDepositSender,
Address: erc20DepositSender,
Name: inputPayload.Name,
ImgLink: inputPayload.ImgLink,
},
Value: etherDepositValue,
Value: erc20DepositValue,
}
bounty.Sponsorships = append(bounty.Sponsorships, sponsorship)
}
Expand Down Expand Up @@ -163,7 +167,7 @@ func (c *BugLessContract) Advance(

// generate voucher for each sponsor
for _, sponsorship := range bounty.Sponsorships {
_, err := env.EtherWithdraw(sponsorship.Sponsor.Address, sponsorship.Value.ToBig())
_, err := env.ERC20Withdraw(bounty.Token, sponsorship.Sponsor.Address, sponsorship.Value.ToBig())
if err != nil {
return fmt.Errorf("failed to withdraw: %v", err)
}
Expand Down Expand Up @@ -216,15 +220,15 @@ func (c *BugLessContract) Advance(
if sponsor == hacker {
continue
}
err := env.EtherTransfer(sponsor, hacker, sponsorship.Value.ToBig())
err := env.ERC20Transfer(bounty.Token, sponsor, hacker, sponsorship.Value.ToBig())
if err != nil {
// this should be impossible
return fmt.Errorf("failed to transfer asset: %v", err)
}
}

// generate voucher
_, err := env.EtherWithdraw(hacker, accBounty.ToBig())
_, err := env.ERC20Withdraw(bounty.Token, hacker, accBounty.ToBig())
if err != nil {
return fmt.Errorf("failed to generate voucher: %v", err)
}
Expand Down
14 changes: 8 additions & 6 deletions shared/bugless.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type AppBounty struct {
Description string
Started int64 // (unix timestamp)
Deadline int64 // (unix timestamp)
Token common.Address // ERC-20
InputIndex int
Sponsorships []*Sponsorship
Exploit *Exploit
Expand Down Expand Up @@ -78,11 +79,12 @@ type Input struct {
}

type CreateAppBounty struct {
Name string `json:"name"`
ImgLink string `json:"imgLink"`
Description string `json:"description"`
Deadline int64 `json:"deadline"` // (unix timestamp)
CodeZipBinary string `json:"codeZipBinary"` // base64?
Name string `json:"name"`
ImgLink string `json:"imgLink"`
Description string `json:"description"`
Deadline int64 `json:"deadline"` // (unix timestamp)
CodeZipBinary string `json:"codeZipBinary"` // base64?
Token common.Address `json:"token"` // ERC-20
}

func (b *CreateAppBounty) Validate() error {
Expand All @@ -101,7 +103,7 @@ func (b *CreateAppBounty) Validate() error {
return nil
}

// From portal (Ether)
// From portal (ERC-20)
type AddSponsorship struct {
BountyIndex int `json:"bountyIndex"`
Name string `json:"name"`
Expand Down
74 changes: 56 additions & 18 deletions tests/tests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ local SPONSOR1_WALLET = "0x0000000000000000000000000000000000000101"
local HACKER1_WALLET = "0x0000000000000000000000000000000000000201"
local HACKER2_WALLET = "0x0000000000000000000000000000000000000202"

local CTSI_ADDRESS = "0x491604c0fdf08347dd1fa4ee062a822a5dd06b5d"
local USDC_ADDRESS = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
local WETH_ADDRESS = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"

local config = {
ETHER_PORTAL_ADDRESS = "0xffdbe43d4c855bf7e0f105c400a50857f53ab044",
ERC20_PORTAL_ADDRESS = "0x9c21aeb2093c32ddbc53eef24b873bdcd1ada1db",
DAPP_ADDRESS_RELAY_ADDRESS = "0xf5de34d6bbc0446e2a45719e718efebaae179dae",
DAPP_ADDRESS = "0x7122cd1221c20892234186facfe8615e6743ab02",
DAPP_ADDRESS = "0xab7528bb862fb57e8a2bcd567a2e929a0be56a5e",
}

local machine_config = ".sunodo/image"
Expand Down Expand Up @@ -58,10 +62,11 @@ local function inspect_input(machine, opts)
}, true))
end

local function advance_ether_deposit(machine, opts)
local function advance_erc20_deposit(machine, opts)
return decode_response_jsons(machine:advance_state({
metadata = { msg_sender = fromhex(config.ETHER_PORTAL_ADDRESS), timestamp = opts.timestamp },
payload = cartesix_encoder.encode_ether_deposit({
metadata = { msg_sender = fromhex(config.ERC20_PORTAL_ADDRESS), timestamp = opts.timestamp },
payload = cartesix_encoder.encode_erc20_deposit({
contract_address = fromhex(opts.token),
sender_address = fromhex(opts.sender),
amount = tobe256(opts.amount),
extra_data = tojson{ kind = opts.kind, payload = opts.data },
Expand Down Expand Up @@ -114,6 +119,7 @@ describe("tests on Lua bounty", function()
name = "Lua 5.4.3 Bounty",
description = "Try to crash a sandboxed Lua 5.4.3 script",
deadline = bounty_deadline,
token = CTSI_ADDRESS,
codeZipBinary = tobase64(readfile(bounty_code)),
},
})
Expand All @@ -132,14 +138,16 @@ describe("tests on Lua bounty", function()
InputIndex = 1,
Sponsorships = null,
Started = bounty_started,
Token = CTSI_ADDRESS,
Withdrawn = false,
},
},
})
end)

it("should add sponsorship from developer itself", function()
local res = advance_ether_deposit(machine, {
local res = advance_erc20_deposit(machine, {
token = CTSI_ADDRESS,
sender = DEVELOPER1_WALLET,
amount = 1000,
kind = "AddSponsorship",
Expand Down Expand Up @@ -173,14 +181,16 @@ describe("tests on Lua bounty", function()
},
},
Started = bounty_started,
Token = CTSI_ADDRESS,
Withdrawn = false,
},
},
})
end)

it("should add sponsorship from an external sponsor", function()
local res = advance_ether_deposit(machine, {
local res = advance_erc20_deposit(machine, {
token = CTSI_ADDRESS,
sender = SPONSOR1_WALLET,
amount = 2000,
kind = "AddSponsorship",
Expand Down Expand Up @@ -222,6 +232,7 @@ describe("tests on Lua bounty", function()
},
},
Started = bounty_started,
Token = CTSI_ADDRESS,
Withdrawn = false,
},
},
Expand All @@ -243,6 +254,21 @@ describe("tests on Lua bounty", function()
expect.equal(res.status, "rejected")
end)

it("should reject sponsorship with the wrong token", function()
local res = advance_erc20_deposit(machine, {
token = USDC_ADDRESS,
sender = DEVELOPER1_WALLET,
amount = 1000,
kind = "AddSponsorship",
timestamp = timestamp,
data = {
name = "Developer1",
bountyIndex = bounty_index,
},
})
expect.equal(res.status, "rejected")
end)

it("should reject sponsor withdraw before deadline", function()
local res = advance_input(machine, {
sender = DEVELOPER1_WALLET,
Expand Down Expand Up @@ -324,21 +350,22 @@ describe("tests on Lua bounty", function()
},
},
Started = bounty_started,
Token = CTSI_ADDRESS,
Withdrawn = true,
},
},
})
expect.equal(res.vouchers, {
{
address = fromhex(config.DAPP_ADDRESS),
payload = cartesix_encoder.encode_ether_transfer_voucher({
address = fromhex(CTSI_ADDRESS),
payload = cartesix_encoder.encode_erc20_transfer_voucher({
destination_address = DEVELOPER1_WALLET,
amount = tobe256(1000),
}),
},
{
address = fromhex(config.DAPP_ADDRESS),
payload = cartesix_encoder.encode_ether_transfer_voucher({
address = fromhex(CTSI_ADDRESS),
payload = cartesix_encoder.encode_erc20_transfer_voucher({
destination_address = SPONSOR1_WALLET,
amount = tobe256(2000),
}),
Expand Down Expand Up @@ -374,7 +401,8 @@ describe("tests on Lua bounty", function()
end)

it("should reject sponsorship after deadline", function()
local res = advance_ether_deposit(machine, {
local res = advance_erc20_deposit(machine, {
token = CTSI_ADDRESS,
sender = SPONSOR1_WALLET,
amount = 1000,
kind = "AddSponsorship",
Expand Down Expand Up @@ -464,6 +492,7 @@ describe("tests on SQLite bounty", function()
name = "SQLite3 3.32.2 Bounty",
description = "Try to crash SQLite 3.32.2 with a SQL query",
deadline = bounty_deadline,
token = WETH_ADDRESS,
codeZipBinary = tobase64(readfile(sqlite33202_bounty_code)),
},
})
Expand All @@ -483,14 +512,16 @@ describe("tests on SQLite bounty", function()
InputIndex = 5,
Sponsorships = null,
Started = bounty_started,
Token = WETH_ADDRESS,
Withdrawn = false,
},
},
})
end)

it("should add sponsorship from an external sponsor", function()
local res = advance_ether_deposit(machine, {
local res = advance_erc20_deposit(machine, {
token = WETH_ADDRESS,
sender = SPONSOR1_WALLET,
amount = 4000,
kind = "AddSponsorship",
Expand Down Expand Up @@ -525,14 +556,16 @@ describe("tests on SQLite bounty", function()
},
},
Started = bounty_started,
Token = WETH_ADDRESS,
Withdrawn = false,
},
},
})
end)

it("should raise an sponsorship", function()
local res = advance_ether_deposit(machine, {
local res = advance_erc20_deposit(machine, {
token = WETH_ADDRESS,
sender = SPONSOR1_WALLET,
amount = 5000,
kind = "AddSponsorship",
Expand Down Expand Up @@ -567,6 +600,7 @@ describe("tests on SQLite bounty", function()
},
},
Started = bounty_started,
Token = WETH_ADDRESS,
Withdrawn = false,
},
},
Expand Down Expand Up @@ -618,15 +652,16 @@ describe("tests on SQLite bounty", function()
},
},
Started = bounty_started,
Token = WETH_ADDRESS,
Withdrawn = true,
},
},
})
second_bounty_final_state = res.state.Bounties[bounty_index + 1]
expect.equal(res.vouchers, {
{
address = fromhex(config.DAPP_ADDRESS),
payload = cartesix_encoder.encode_ether_transfer_voucher({
address = fromhex(WETH_ADDRESS),
payload = cartesix_encoder.encode_erc20_transfer_voucher({
destination_address = HACKER1_WALLET,
amount = tobe256(9000),
}),
Expand Down Expand Up @@ -691,6 +726,7 @@ describe("tests on BusyBox bounty", function()
name = "BusyBox 1.36.1 Bounty",
description = "Try to crash BusyBox 1.36.1",
deadline = bounty_deadline,
token = USDC_ADDRESS,
codeZipBinary = tobase64(readfile(sqlite33202_bounty_code)),
},
})
Expand All @@ -711,6 +747,7 @@ describe("tests on BusyBox bounty", function()
InputIndex = 9,
Sponsorships = null,
Started = bounty_started,
Token = USDC_ADDRESS,
Withdrawn = false,
},
},
Expand Down Expand Up @@ -754,14 +791,15 @@ describe("tests on BusyBox bounty", function()
InputIndex = 9,
Sponsorships = null,
Started = bounty_started,
Token = USDC_ADDRESS,
Withdrawn = true,
},
},
})
expect.equal(res.vouchers, {
{
address = fromhex(config.DAPP_ADDRESS),
payload = cartesix_encoder.encode_ether_transfer_voucher({
address = fromhex(USDC_ADDRESS),
payload = cartesix_encoder.encode_erc20_transfer_voucher({
destination_address = HACKER1_WALLET,
amount = tobe256(0),
}),
Expand Down

0 comments on commit 1c31e1f

Please sign in to comment.