Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

impl.gno

7.67 Kb · 217 lines
  1package ucs03_zkgm
  2
  3import (
  4	"chain/runtime/unsafe"
  5
  6	types "gno.land/p/onbloc/ibc/union/types"
  7
  8	z "gno.land/p/onbloc/ibc/union/zkgm"
  9	u256 "gno.land/p/onbloc/math/uint256"
 10	zkgm "gno.land/r/onbloc/ibc/union/apps/ucs03_zkgm"
 11	"gno.land/r/onbloc/ibc/union/core"
 12)
 13
 14// ucs03ZkgmV1 is the v1 implementation of the zkgm app. It holds the injected
 15// proxy state (zkgm.IStore) and contains all the protocol logic; the proxy keeps
 16// only the stable identity, the escrow funds, and the swap point. State writes go
 17// through the store's borrow-rule setters: v.store.SetXXX(0, rlm, ...).
 18type ucs03ZkgmV1 struct {
 19	store zkgm.IStore
 20}
 21
 22var _ zkgm.IApp = &ucs03ZkgmV1{}
 23
 24// NewUCS03ZkgmV1 constructs a fresh v1 impl bound to the injected store.
 25func NewUCS03ZkgmV1(store zkgm.IStore) zkgm.IApp {
 26	return &ucs03ZkgmV1{store: store}
 27}
 28
 29// OnChannelOpenInit accepts a channel only if it speaks the zkgm protocol version.
 30func (v *ucs03ZkgmV1) OnChannelOpenInit(_ int, rlm realm, connectionId types.ConnectionId, channelId types.ChannelId, version string, relayer address) {
 31	assertIsRlmCurrent(0, rlm)
 32
 33	enforceVersion(version)
 34}
 35
 36// OnChannelOpenTry enforces the protocol version on both sides of the handshake.
 37func (v *ucs03ZkgmV1) OnChannelOpenTry(_ int, rlm realm, connectionId types.ConnectionId, channelId types.ChannelId, version string, counterpartyVersion string, relayer address) {
 38	assertIsRlmCurrent(0, rlm)
 39
 40	enforceVersion(version)
 41	enforceVersion(counterpartyVersion)
 42}
 43
 44// OnChannelOpenAck enforces the counterparty's negotiated protocol version.
 45func (v *ucs03ZkgmV1) OnChannelOpenAck(_ int, rlm realm, channelId types.ChannelId, counterpartyChannelId types.ChannelId, counterpartyVersion string, relayer address) {
 46	assertIsRlmCurrent(0, rlm)
 47
 48	enforceVersion(counterpartyVersion)
 49}
 50
 51// OnChannelOpenConfirm completes the handshake; zkgm keeps no per-channel state.
 52func (v *ucs03ZkgmV1) OnChannelOpenConfirm(_ int, rlm realm, channelId types.ChannelId, relayer address) {
 53	assertIsRlmCurrent(0, rlm)
 54}
 55
 56// Channel closing is not supported by zkgm (reference returns an error).
 57func (v *ucs03ZkgmV1) OnChannelCloseInit(_ int, rlm realm, channelId types.ChannelId, relayer address) {
 58	assertIsRlmCurrent(0, rlm)
 59
 60	panic("channel closing is not allowed")
 61}
 62
 63func (v *ucs03ZkgmV1) OnChannelCloseConfirm(_ int, rlm realm, channelId types.ChannelId, relayer address) {
 64	assertIsRlmCurrent(0, rlm)
 65
 66	panic("channel closing is not allowed")
 67}
 68
 69// OnRecvPacket decodes the packet and dispatches it; decode/exec failures return a failure ack rather than aborting.
 70func (v *ucs03ZkgmV1) OnRecvPacket(_ int, rlm realm, packet types.Packet, relayer address, relayerMsg []byte) types.RecvPacketResult {
 71	assertIsRlmCurrent(0, rlm)
 72
 73	zp, err := z.DecodeZkgmPacket(types.CloneBytes(packet.Data))
 74	if err != nil {
 75		zkgm.EmitRecvError(0, rlm, packet.SourceChannelId, packet.DestinationChannelId, err.Error())
 76		return failureResult(universalErrorAck())
 77	}
 78
 79	res, err := v.dispatchExecutePacket(0, rlm, packet, relayer, relayerMsg, zp.Salt, zp.Path, zp.Instruction, false)
 80	if err != nil {
 81		zkgm.EmitRecvError(0, rlm, packet.SourceChannelId, packet.DestinationChannelId, err.Error())
 82		return failureResult(universalErrorAck())
 83	}
 84
 85	// An only-maker outcome (a maker-only fill that could not be satisfied, or
 86	// an only-maker child anywhere in a batch) must revert the whole recv tx —
 87	// no ack is written and any already-applied batch-child mutations are rolled
 88	// back. This mirrors union's reply handler returning Err(OnlyMaker) for both
 89	// the single-instruction and batch cases (contract.rs L2530, L2545), and the
 90	// symmetric guard already in OnIntentRecvPacket. Core does not recover recv
 91	// panics, so this reverts atomically.
 92	if isOnlyMakerAck(res.Acknowledgement) {
 93		panic(errIsOnlyMakerAck)
 94	}
 95
 96	return res
 97}
 98
 99// OnIntentRecvPacket executes the market-maker fast path. Only-maker outcomes
100// abort the intent tx so proven recv can proceed instead. This is also the
101// explicit stop point for market-maker fills that require unsupported native
102// maker funding.
103func (v *ucs03ZkgmV1) OnIntentRecvPacket(_ int, rlm realm, packet types.Packet, marketMaker address, marketMakerMsg []byte) types.RecvPacketResult {
104	assertIsRlmCurrent(0, rlm)
105
106	zp, err := z.DecodeZkgmPacket(types.CloneBytes(packet.Data))
107	if err != nil {
108		zkgm.EmitRecvError(0, rlm, packet.SourceChannelId, packet.DestinationChannelId, err.Error())
109		return failureResult(universalErrorAck())
110	}
111
112	res, err := v.dispatchExecutePacket(0, rlm, packet, marketMaker, marketMakerMsg, zp.Salt, zp.Path, zp.Instruction, true)
113	if err != nil {
114		zkgm.EmitRecvError(0, rlm, packet.SourceChannelId, packet.DestinationChannelId, err.Error())
115		return failureResult(universalErrorAck())
116	}
117
118	if isOnlyMakerAck(res.Acknowledgement) {
119		// Intent recv must not silently succeed without a maker fill. Panicking
120		// preserves the proven recv fallback path and makes unsupported native
121		// market-maker funding fail explicitly until funds plumbing is added.
122		panic("only maker")
123	}
124
125	return res
126}
127
128// OnAcknowledgementPacket routes the ack to its instruction, or to the forwarded parent packet.
129func (v *ucs03ZkgmV1) OnAcknowledgementPacket(_ int, rlm realm, packet types.Packet, acknowledgement []byte, relayer address) {
130	assertIsRlmCurrent(0, rlm)
131
132	zp, err := z.DecodeZkgmPacket(types.CloneBytes(packet.Data))
133	if err != nil {
134		panic(err.Error())
135	}
136
137	if v.handleForwardChild(0, rlm, packet, zp, acknowledgement) {
138		return
139	}
140
141	outerAck, err := z.DecodeAck(acknowledgement)
142	if err != nil {
143		panic(err.Error())
144	}
145
146	successful := outerAck.Tag != nil && outerAck.Tag.Eq(tagAckSuccess())
147	if err := v.acknowledgeInternal(0, rlm, packet, relayer, zp.Salt, zp.Path, zp.Instruction, successful, outerAck.InnerAck); err != nil {
148		panic(err.Error())
149	}
150}
151
152// OnTimeoutPacket refunds the timed-out instruction, or settles the forwarded parent packet.
153func (v *ucs03ZkgmV1) OnTimeoutPacket(_ int, rlm realm, packet types.Packet, relayer address) {
154	assertIsRlmCurrent(0, rlm)
155
156	zp, err := z.DecodeZkgmPacket(types.CloneBytes(packet.Data))
157	if err != nil {
158		panic(err.Error())
159	}
160
161	if v.handleForwardChild(0, rlm, packet, zp, universalErrorAck()) {
162		return
163	}
164
165	if err := v.timeoutInternal(0, rlm, packet, zp.Salt, zp.Path, zp.Instruction); err != nil {
166		panic(err.Error())
167	}
168}
169
170// Send verifies the instruction against the attached funds, namespaces the salt, and emits the packet through core.
171func (v *ucs03ZkgmV1) Send(_ int, rlm realm, channelId types.ChannelId, timeoutTimestamp types.Timestamp, salt [32]byte, instruction z.Instruction) types.Packet {
172	assertIsRlmCurrent(0, rlm)
173
174	sender := rlm.Previous().Address().String()
175
176	funds := newFunds(parseCoins(""))
177
178	// SAFE: native coins attached with -send live on the chain-root envelope,
179	// not on rlm.Previous(). Guard direct user calls before reading
180	// unsafe.OriginSend(), then seed the proxy escrow budget from it.
181	if rlm.Previous().IsUserCall() {
182		sentCoins := unsafe.OriginSend()
183		funds = newFunds(sentCoins)
184	}
185
186	err := v.verifyInternal(0, rlm, funds, channelId, u256.Zero(), instruction)
187	if err != nil {
188		panic(err)
189	}
190
191	err = funds.assertEmpty()
192	if err != nil {
193		panic(err)
194	}
195
196	// Only user-initiated sends apply DeriveSenderSalt. Forwarded packets are
197	// built in forward.gno and use DeriveForwardSalt instead.
198	hashedSalt := z.DeriveSenderSalt([]byte(sender), salt)
199
200	data, err := z.EncodeZkgmPacket(z.ZkgmPacket{
201		Salt:        hashedSalt,
202		Path:        u256.Zero(),
203		Instruction: instruction,
204	})
205	if err != nil {
206		panic(err)
207	}
208
209	return core.SendPacket(cross(rlm), channelId, timeoutTimestamp, data)
210}
211
212// enforceVersion rejects channels that do not speak the zkgm protocol version.
213func enforceVersion(version string) {
214	if version != zkgm.Version {
215		panic("unsupported channel version")
216	}
217}