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\Model\ChainId;
12:
13: use Waves\Transactions\TransferTransaction as CurrentTransaction;
14:
15: class TransferTransaction extends Transaction
16: {
17: const TYPE = 4;
18: const LATEST_VERSION = 3;
19: const MIN_FEE = 100_000;
20:
21: private Recipient $recipient;
22: private Amount $amount;
23: private Base58String $attachment;
24:
25: static function build( PublicKey $sender, Recipient $recipient, Amount $amount, Base58String $attachment = null ): CurrentTransaction
26: {
27: $tx = new CurrentTransaction;
28: $tx->setBase( $sender, CurrentTransaction::TYPE, CurrentTransaction::LATEST_VERSION, CurrentTransaction::MIN_FEE );
29:
30: // TRANSFER TRANSACTION
31: {
32: $tx->setRecipient( $recipient );
33: $tx->setAmount( $amount );
34: $tx->setAttachment( $attachment );
35: }
36:
37: return $tx;
38: }
39:
40: function getUnsigned(): CurrentTransaction
41: {
42: // VERSION
43: if( $this->version() !== CurrentTransaction::LATEST_VERSION )
44: throw new Exception( __FUNCTION__ . ' unexpected version = ' . $this->version(), ExceptionCode::UNEXPECTED );
45:
46: // BASE
47: $pb_Transaction = $this->getProtobufTransactionBase();
48:
49: // TRANSFER TRANSACTION
50: {
51: $pb_TransactionData = new \Waves\Protobuf\TransferTransactionData;
52: // RECIPIENT
53: {
54: $pb_TransactionData->setRecipient( $this->recipient()->toProtobuf() );
55: }
56: // AMOUNT
57: {
58: $pb_TransactionData->setAmount( $this->amount()->toProtobuf() );
59: }
60: // ATTACHMENT
61: {
62: $pb_TransactionData->setAttachment( $this->attachment()->bytes() );
63: }
64: }
65:
66: // TRANSFER TRANSACTION
67: $this->setBodyBytes( $pb_Transaction->setTransfer( $pb_TransactionData )->serializeToString() );
68: return $this;
69: }
70:
71: function recipient(): Recipient
72: {
73: if( !isset( $this->recipient ) )
74: $this->recipient = $this->json->get( 'recipient' )->asRecipient();
75: return $this->recipient;
76: }
77:
78: function setRecipient( Recipient $recipient ): CurrentTransaction
79: {
80: $this->recipient = $recipient;
81: $this->json->put( 'recipient', $recipient->toString() );
82: return $this;
83: }
84:
85: function amount(): Amount
86: {
87: if( !isset( $this->amount ) )
88: $this->amount = Amount::fromJson( $this->json );
89: return $this->amount;
90: }
91:
92: function setAmount( Amount $amount ): CurrentTransaction
93: {
94: $this->amount = $amount;
95: $this->json->put( 'amount', $amount->value() );
96: $this->json->put( 'assetId', $amount->assetId()->toJsonValue() );
97: return $this;
98: }
99:
100: function attachment(): Base58String
101: {
102: if( !isset( $this->attachment ) )
103: $this->attachment = $this->json->get( 'attachment' )->asBase58String();
104: return $this->attachment;
105: }
106:
107: function setAttachment( Base58String $attachment = null ): CurrentTransaction
108: {
109: $attachment = $attachment ?? Base58String::emptyString();
110: $this->attachment = $attachment;
111: $this->json->put( 'attachment', $attachment->toString() );
112: return $this;
113: }
114:
115: // COMMON
116:
117: function __construct( Json $json = null )
118: {
119: parent::__construct( $json );
120: }
121:
122: function addProof( PrivateKey $privateKey, int $index = null ): CurrentTransaction
123: {
124: $proof = (new \deemru\WavesKit)->sign( $this->bodyBytes(), $privateKey->bytes() );
125: if( $proof === false )
126: throw new Exception( __FUNCTION__ . ' unexpected sign() error', ExceptionCode::UNEXPECTED );
127: $proof = Base58String::fromBytes( $proof )->encoded();
128:
129: $proofs = $this->proofs();
130: if( !isset( $index ) )
131: $proofs[] = $proof;
132: else
133: $proofs[$index] = $proof;
134: return $this->setProofs( $proofs );
135: }
136:
137: /**
138: * @return CurrentTransaction
139: */
140: function setType( int $type )
141: {
142: parent::setType( $type );
143: return $this;
144: }
145:
146: /**
147: * @return CurrentTransaction
148: */
149: function setSender( PublicKey $sender )
150: {
151: parent::setSender( $sender );
152: return $this;
153: }
154:
155: /**
156: * @return CurrentTransaction
157: */
158: function setVersion( int $version )
159: {
160: parent::setVersion( $version );
161: return $this;
162: }
163:
164: /**
165: * @return CurrentTransaction
166: */
167: function setFee( Amount $fee )
168: {
169: parent::setFee( $fee );
170: return $this;
171: }
172:
173: /**
174: * @return CurrentTransaction
175: */
176: function setChainId( ChainId $chainId = null )
177: {
178: parent::setChainId( $chainId );
179: return $this;
180: }
181:
182: /**
183: * @return CurrentTransaction
184: */
185: function setTimestamp( int $timestamp = null )
186: {
187: parent::setTimestamp( $timestamp );
188: return $this;
189: }
190:
191: /**
192: * @param array<int, string> $proofs
193: * @return CurrentTransaction
194: */
195: function setProofs( array $proofs = null )
196: {
197: parent::setProofs( $proofs );
198: return $this;
199: }
200:
201: function bodyBytes(): string
202: {
203: if( !isset( $this->bodyBytes ) )
204: $this->getUnsigned();
205: return parent::bodyBytes();
206: }
207: }
208: