swap.gno
2.28 Kb ยท 98 lines
1package atomicswap
2
3import (
4 "crypto/sha256"
5 "encoding/hex"
6 "std"
7 "time"
8
9 "gno.land/p/demo/ufmt"
10)
11
12// Swap represents an atomic swap contract.
13type Swap struct {
14 sender std.Address
15 recipient std.Address
16 hashlock string
17 timelock time.Time
18 claimed bool
19 refunded bool
20 amountStr string
21 sendFn func(to std.Address)
22}
23
24func newSwap(
25 sender std.Address,
26 recipient std.Address,
27 hashlock string,
28 timelock time.Time,
29 amountStr string,
30 sendFn func(std.Address),
31) *Swap {
32 require(time.Now().Before(timelock), "timelock must be in the future")
33 require(hashlock != "", "hashlock must not be empty")
34 return &Swap{
35 recipient: recipient,
36 sender: sender,
37 hashlock: hashlock,
38 timelock: timelock,
39 claimed: false,
40 refunded: false,
41 sendFn: sendFn,
42 amountStr: amountStr,
43 }
44}
45
46// Claim allows the recipient to claim the funds if they provide the correct preimage.
47func (s *Swap) Claim(preimage string) {
48 require(!s.claimed, "already claimed")
49 require(!s.refunded, "already refunded")
50 require(std.PreviousRealm().Address() == s.recipient, "unauthorized")
51
52 hashlock := sha256.Sum256([]byte(preimage))
53 hashlockHex := hex.EncodeToString(hashlock[:])
54 require(hashlockHex == s.hashlock, "invalid preimage")
55
56 s.claimed = true
57 s.sendFn(s.recipient)
58}
59
60// Refund allows the sender to refund the funds after the timelock has expired.
61func (s *Swap) Refund() {
62 require(!s.claimed, "already claimed")
63 require(!s.refunded, "already refunded")
64 require(std.PreviousRealm().Address() == s.sender, "unauthorized")
65 require(time.Now().After(s.timelock), "timelock not expired")
66
67 s.refunded = true
68 s.sendFn(s.sender)
69}
70
71func (s Swap) Status() string {
72 switch {
73 case s.refunded:
74 return "refunded"
75 case s.claimed:
76 return "claimed"
77 case s.TimeRemaining() < 0:
78 return "expired"
79 default:
80 return "active"
81 }
82}
83
84func (s Swap) TimeRemaining() time.Duration {
85 remaining := time.Until(s.timelock)
86 if remaining < 0 {
87 return 0
88 }
89 return remaining
90}
91
92// String returns the current state of the swap.
93func (s Swap) String() string {
94 return ufmt.Sprintf(
95 "- status: %s\n- sender: %s\n- recipient: %s\n- amount: %s\n- hashlock: %s\n- timelock: %s\n- remaining: %s",
96 s.Status(), s.sender, s.recipient, s.amountStr, s.hashlock, s.timelock.Format(time.RFC3339), s.TimeRemaining().String(),
97 )
98}