Completed
Push — master ( c780c0...f2b04e )
by thomas
60:38 queued 58:10
created

AddressCreator::fromOutputScript()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6.027

Importance

Changes 0
Metric Value
cc 6
nc 5
nop 1
dl 0
loc 24
ccs 10
cts 11
cp 0.9091
crap 6.027
rs 8.9137
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Address;
6
7
use BitWasp\Bitcoin\Base58;
8
use BitWasp\Bitcoin\Bitcoin;
9
use BitWasp\Bitcoin\Exceptions\UnrecognizedAddressException;
10
use BitWasp\Bitcoin\Network\NetworkInterface;
11
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
12
use BitWasp\Bitcoin\Script\P2shScript;
13
use BitWasp\Bitcoin\Script\ScriptInterface;
14
use BitWasp\Bitcoin\Script\ScriptType;
15
use BitWasp\Bitcoin\Script\WitnessProgram;
16
use BitWasp\Bitcoin\Script\WitnessScript;
17
use BitWasp\Bitcoin\SegwitBech32;
18
use BitWasp\Buffertools\Buffer;
19
use BitWasp\Buffertools\BufferInterface;
20
21
class AddressCreator extends BaseAddressCreator
22
{
23
    /**
24
     * @param string $strAddress
25
     * @param NetworkInterface $network
26
     * @return Base58Address|null
27
     */
28 39
    protected function readBase58Address(string $strAddress, NetworkInterface $network)
29
    {
30
        try {
31 39
            $data = Base58::decodeCheck($strAddress);
32 33
            $prefixByte = $data->slice(0, $network->getP2shPrefixLength())->getHex();
33
34 33
            if ($prefixByte === $network->getP2shByte()) {
35 10
                return new ScriptHashAddress($data->slice(1));
36 23
            } else if ($prefixByte === $network->getAddressByte()) {
37 23
                return new PayToPubKeyHashAddress($data->slice($network->getAddressPrefixLength()));
38
            }
39 6
        } catch (\Exception $e) {
40
            // Just return null
41
        }
42
43 7
        return null;
44
    }
45
46
    /**
47
     * @param string $strAddress
48
     * @param NetworkInterface $network
49
     * @return SegwitAddress|null
50
     */
51 7
    protected function readSegwitAddress(string $strAddress, NetworkInterface $network)
52
    {
53
        try {
54 7
            list ($version, $program) = \BitWasp\Bech32\decodeSegwit($network->getSegwitBech32Prefix(), $strAddress);
55
56 6
            if (0 === $version) {
57 3
                $wp = WitnessProgram::v0(new Buffer($program));
58
            } else {
59 3
                $wp = new WitnessProgram($version, new Buffer($program));
60
            }
61
62 6
            return new SegwitAddress($wp);
63 1
        } catch (\Exception $e) {
64
            // Just return null
65
        }
66
67 1
        return null;
68
    }
69
70
    /**
71
     * @param ScriptInterface $outputScript
72
     * @return Address
73
     */
74 41
    public function fromOutputScript(ScriptInterface $outputScript): Address
75
    {
76 41
        if ($outputScript instanceof P2shScript || $outputScript instanceof WitnessScript) {
77
            throw new \RuntimeException("P2shScript & WitnessScript's are not accepted by fromOutputScript");
78
        }
79
80 41
        $wp = null;
81 41
        if ($outputScript->isWitness($wp)) {
82
            /** @var WitnessProgram $wp */
83 10
            return new SegwitAddress($wp);
84
        }
85
86 31
        $decode = (new OutputClassifier())->decode($outputScript);
87 31
        switch ($decode->getType()) {
88
            case ScriptType::P2PKH:
89
                /** @var BufferInterface $solution */
90 20
                return new PayToPubKeyHashAddress($decode->getSolution());
91
            case ScriptType::P2SH:
92
                /** @var BufferInterface $solution */
93 11
                return new ScriptHashAddress($decode->getSolution());
94
            default:
95 1
                throw new \RuntimeException('Script type is not associated with an address');
96
        }
97
    }
98
99
    /**
100
     * @param string $strAddress
101
     * @param NetworkInterface|null $network
102
     * @return Address
103
     * @throws UnrecognizedAddressException
104
     */
105 39
    public function fromString(string $strAddress, NetworkInterface $network = null): Address
106
    {
107 39
        $network = $network ?: Bitcoin::getNetwork();
108
109 39
        if (($base58Address = $this->readBase58Address($strAddress, $network))) {
110 32
            return $base58Address;
111
        }
112
113 7
        if (($bech32Address = $this->readSegwitAddress($strAddress, $network))) {
114 6
            return $bech32Address;
115
        }
116
117 1
        throw new UnrecognizedAddressException();
118
    }
119
}
120