1: <?php declare( strict_types = 1 );
2:
3: namespace Waves\Transactions;
4:
5: use Exception;
6: use Waves\Account\PrivateKey;
7: use Waves\Common\Base58String;
8: use Waves\Account\PublicKey;
9: use Waves\Common\ExceptionCode;
10: use Waves\Common\Json;
11: use Waves\Common\Value;
12: use Waves\Model\ChainId;
13: use Waves\Transactions\Invocation\FunctionCall;
14:
15: use Waves\Transactions\InvokeScriptTransaction as CurrentTransaction;
16:
17: class InvokeScriptTransaction extends Transaction
18: {
19: const TYPE = 16;
20: const LATEST_VERSION = 2;
21: const MIN_FEE = 500_000;
22:
23: private Recipient $dApp;
24: private FunctionCall $function;
25: /**
26: * @var array<int, Amount>
27: */
28: private array $payments;
29:
30: /**
31: * @param PublicKey $sender
32: * @param Recipient $dApp
33: * @param FunctionCall|null $function
34: * @param array<int, Amount>|null $payments
35: * @return CurrentTransaction
36: */
37: static function build( PublicKey $sender, Recipient $dApp, FunctionCall $function = null, array $payments = null ): CurrentTransaction
38: {
39: $tx = new CurrentTransaction;
40: $tx->setBase( $sender, CurrentTransaction::TYPE, CurrentTransaction::LATEST_VERSION, CurrentTransaction::MIN_FEE );
41:
42: // INVOKE TRANSACTION
43: {
44: $tx->setDApp( $dApp );
45: $tx->setFunction( $function );
46: $tx->setPayments( $payments );
47: }
48:
49: return $tx;
50: }
51:
52: function getUnsigned(): CurrentTransaction
53: {
54: // VERSION
55: if( $this->version() !== CurrentTransaction::LATEST_VERSION )
56: throw new Exception( __FUNCTION__ . ' unexpected version = ' . $this->version(), ExceptionCode::UNEXPECTED );
57:
58: // BASE
59: $pb_Transaction = $this->getProtobufTransactionBase();
60:
61: // INVOKE TRANSACTION
62: {
63:
64: $pb_TransactionData = new \Waves\Protobuf\InvokeScriptTransactionData;
65: // DAPP
66: {
67: $pb_TransactionData->setDApp( $this->dApp()->toProtobuf() );
68: }
69: // FUNCTION
70: {
71: $pb_TransactionData->setFunctionCall( $this->function()->toBodyBytes() );
72: }
73: // PAYMENTS
74: {
75: $pb_Payments = [];
76: foreach( $this->payments() as $payment )
77: $pb_Payments[] = $payment->toProtobuf();
78: $pb_TransactionData->setPayments( $pb_Payments );
79: }
80: }
81:
82: // INVOKE TRANSACTION
83: $this->setBodyBytes( $pb_Transaction->setInvokeScript( $pb_TransactionData )->serializeToString() );
84: return $this;
85: }
86:
87: function dApp(): Recipient
88: {
89: if( !isset( $this->dApp ) )
90: $this->dApp = $this->json->get( 'dApp' )->asRecipient();
91: return $this->dApp;
92: }
93:
94: function setDApp( Recipient $dApp ): CurrentTransaction
95: {
96: $this->dApp = $dApp;
97: $this->json->put( 'dApp', $dApp->toString() );
98: return $this;
99: }
100:
101: function function(): FunctionCall
102: {
103: if( !isset( $this->function ) )
104: $this->function = FunctionCall::fromJson( $this->json->get( 'call' )->asJson() );
105: return $this->function;
106: }
107:
108: function setFunction( FunctionCall $function = null ): CurrentTransaction
109: {
110: $function = $function ?? FunctionCall::as();
111: $this->function = $function;
112: $this->json->put( 'call', $function->toJsonValue() );
113: return $this;
114: }
115:
116: /**
117: * @return array<int, Amount>
118: */
119: function payments(): array
120: {
121: if( !isset( $this->payments ) )
122: {
123: $payments = [];
124: foreach( $this->json->get( 'payment' )->asArray() as $value )
125: $payments[] = Amount::fromJson( Value::as( $value )->asJson() );
126: $this->payments = $payments;
127: }
128: return $this->payments;
129: }
130:
131: /**
132: * @param array<int, Amount>|null $payments
133: * @return CurrentTransaction
134: */
135: function setPayments( array $payments = null ): CurrentTransaction
136: {
137: $this->payments = $payments ?? [];
138:
139: $payments = [];
140: foreach( $this->payments as $payment )
141: $payments[] = [ 'amount' => $payment->value(), 'assetId' => $payment->assetId()->toJsonValue() ];
142: $this->json->put( 'payment', $payments );
143: return $this;
144: }
145:
146: // COMMON
147:
148: function __construct( Json $json = null )
149: {
150: parent::__construct( $json );
151: }
152:
153: function addProof( PrivateKey $privateKey, int $index = null ): CurrentTransaction
154: {
155: $proof = (new \deemru\WavesKit)->sign( $this->bodyBytes(), $privateKey->bytes() );
156: if( $proof === false )
157: throw new Exception( __FUNCTION__ . ' unexpected sign() error', ExceptionCode::UNEXPECTED );
158: $proof = Base58String::fromBytes( $proof )->encoded();
159:
160: $proofs = $this->proofs();
161: if( !isset( $index ) )
162: $proofs[] = $proof;
163: else
164: $proofs[$index] = $proof;
165: return $this->setProofs( $proofs );
166: }
167:
168: /**
169: * @return CurrentTransaction
170: */
171: function setType( int $type )
172: {
173: parent::setType( $type );
174: return $this;
175: }
176:
177: /**
178: * @return CurrentTransaction
179: */
180: function setSender( PublicKey $sender )
181: {
182: parent::setSender( $sender );
183: return $this;
184: }
185:
186: /**
187: * @return CurrentTransaction
188: */
189: function setVersion( int $version )
190: {
191: parent::setVersion( $version );
192: return $this;
193: }
194:
195: /**
196: * @return CurrentTransaction
197: */
198: function setFee( Amount $fee )
199: {
200: parent::setFee( $fee );
201: return $this;
202: }
203:
204: /**
205: * @return CurrentTransaction
206: */
207: function setChainId( ChainId $chainId = null )
208: {
209: parent::setChainId( $chainId );
210: return $this;
211: }
212:
213: /**
214: * @return CurrentTransaction
215: */
216: function setTimestamp( int $timestamp = null )
217: {
218: parent::setTimestamp( $timestamp );
219: return $this;
220: }
221:
222: /**
223: * @param array<int, string> $proofs
224: * @return CurrentTransaction
225: */
226: function setProofs( array $proofs = null )
227: {
228: parent::setProofs( $proofs );
229: return $this;
230: }
231:
232: function bodyBytes(): string
233: {
234: if( !isset( $this->bodyBytes ) )
235: $this->getUnsigned();
236: return parent::bodyBytes();
237: }
238: }
239: